]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
improve handling of 302 redirect and add option to handle them in the dialplan if...
authorBrian West <brian@freeswitch.org>
Tue, 9 Jun 2009 19:05:11 +0000 (19:05 +0000)
committerBrian West <brian@freeswitch.org>
Tue, 9 Jun 2009 19:05:11 +0000 (19:05 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@13734 d0543943-73ff-0310-b7d9-9358b9ac24b2

conf/sip_profiles/internal.xml
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_sofia/sofia_glue.c

index 05cd9c870b45d8165667d80c06d4b791a390bd21..f77b7c5e03bdd8c84e8a34729949a731497674eb 100644 (file)
     <!--Uncomment if you want to force the outbound leg of a bridge to only offer the codec 
        that the originator is using-->
     <!--<param name="disable-transcoding" value="true"/>-->
-    <!-- Disable Refer -->
+    <!-- Handle 302 Redirect in the dialplan -->
+    <!--<param name="manual-redirect" value="true"/> -->
+    <!-- Disable Register -->
     <!--<param name="disable-transfer" value="true"/> -->
     <!-- Disable Register -->
     <!--<param name="disable-register" value="true"/> -->
index a097b1f70904bd589062051d3e91f5743c47cc62..65a604913e1b5fa86e4c4dac889f8a7b82781cac 100644 (file)
@@ -191,7 +191,7 @@ typedef enum {
        PFLAG_AUTOFIX_TIMING,
        PFLAG_MESSAGE_QUERY_ON_REGISTER,
        PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE,
-       PFLAG_PROXY_FOLLOW_REDIRECT,
+       PFLAG_MANUAL_REDIRECT,
        PFLAG_AUTO_NAT,
        /* No new flags below this line */
        PFLAG_MAX
@@ -621,6 +621,7 @@ struct private_object {
        switch_codec_implementation_t read_impl;
        switch_codec_implementation_t write_impl;
        char *user_via;
+       char *redirected;
 };
 
 struct callback_t {
index 656f81ab2c2d932b2cdfc359684329b502aa392b..fb781c756c14ed6c020e15c83a9e6df4a9b48ad3 100644 (file)
@@ -1591,11 +1591,11 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
                                                } else {
                                                        sofia_clear_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
                                                }
-                                       } else if (!strcasecmp(var, "proxy-follow-redirect")) {
+                                       } else if (!strcasecmp(var, "manual-redirect")) {
                                                if (switch_true(val)) {
-                                                       sofia_set_pflag(profile, PFLAG_PROXY_FOLLOW_REDIRECT);
+                                                       sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT);
                                                } else {
-                                                       sofia_clear_pflag(profile, PFLAG_PROXY_FOLLOW_REDIRECT);
+                                                       sofia_clear_pflag(profile, PFLAG_MANUAL_REDIRECT);
                                                }
                                        } else if (!strcasecmp(var, "outbound-use-uuid-as-callid")) {
                                                if (switch_true(val)) {
@@ -2109,11 +2109,11 @@ switch_status_t config_sofia(int reload, char *profile_name)
                                                } else {
                                                        sofia_clear_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
                                                }
-                                       } else if (!strcasecmp(var, "proxy-follow-redirect")) {
+                                       } else if (!strcasecmp(var, "manual-redirect")) {
                                                if (switch_true(val)) {
-                                                       sofia_set_pflag(profile, PFLAG_PROXY_FOLLOW_REDIRECT);
+                                                       sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT);
                                                } else {
-                                                       sofia_clear_pflag(profile, PFLAG_PROXY_FOLLOW_REDIRECT);
+                                                       sofia_clear_pflag(profile, PFLAG_MANUAL_REDIRECT);
                                                }
                                        } else if (!strcasecmp(var, "inbound-proxy-media") && switch_true(val)) {
                                                sofia_set_flag(profile, TFLAG_PROXY_MEDIA);
@@ -2968,42 +2968,134 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
                        }
                }
 
-               if (channel && sip && status == 100 && switch_channel_test_flag(channel, CF_OUTBOUND)) {
+               if (channel && sip && (status == 302 || status == 305) && switch_channel_test_flag(channel, CF_OUTBOUND)) {
                        sip_contact_t * p_contact = sip->sip_contact;
                        int i = 0;
                        char var_name[80];      
+                       const char *diversion_header;
+                       char *full_contact = NULL;
+                       char *invite_contact;
+                       const char *br;
                        
-                       if (sofia_test_pflag(profile, PFLAG_PROXY_FOLLOW_REDIRECT) && tech_pvt->route_uri && p_contact && p_contact->m_url) {
-                               if (p_contact->m_url->url_port) {
-                                       tech_pvt->route_uri = switch_core_session_sprintf(tech_pvt->session, "sip:%s@%s:%s", 
-                                                                                                                                         p_contact->m_url->url_user, p_contact->m_url->url_host, p_contact->m_url->url_port);
-                               } else {
-                                       tech_pvt->route_uri = switch_core_session_sprintf(tech_pvt->session, "sip:%s@%s", 
-                                                                                                                                         p_contact->m_url->url_user, p_contact->m_url->url_host);
-                               }
+                       if ((br = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
+                               switch_xml_t root = NULL, domain = NULL;
+                               switch_core_session_t *a_session;
+                               switch_channel_t *a_channel;
 
-                               nua_set_hparams(tech_pvt->nh, NUTAG_PROXY(tech_pvt->route_uri), TAG_END());
-                       }
+                               const char *sip_redirect_profile, *sip_redirect_context, *sip_redirect_dialplan, *sip_redirect_fork;
+
+                               if ((a_session = switch_core_session_locate(br)) && (a_channel = switch_core_session_get_channel(a_session))) { 
+                                       switch_stream_handle_t stream = { 0 };
+                                       char separator[2] = "|";
+                                       char *redirect_dialstring;
+                                       su_home_t *home = su_home_new(sizeof(*home));
+                                       switch_assert(home != NULL);
+
+                                       SWITCH_STANDARD_STREAM(stream);
+
+                                       if (!(sip_redirect_profile = switch_channel_get_variable(channel, "sip_redirect_profile"))) {
+                                               sip_redirect_profile = profile->name;
+                                       }
+                                       if (!(sip_redirect_context = switch_channel_get_variable(channel, "sip_redirect_context"))) {
+                                               sip_redirect_context = "redirected";
+                                       }
+                                       if (!(sip_redirect_dialplan = switch_channel_get_variable(channel, "sip_redirect_dialplan"))) {
+                                               sip_redirect_dialplan = "XML";
+                                       }
 
-                       while (p_contact) {
-                               if (p_contact->m_url) {
-                                       if (p_contact->m_url->url_user) {
-                                               switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_user_%d", i);
-                                               switch_channel_set_variable_partner(channel, var_name, p_contact->m_url->url_user);
-                                               switch_channel_set_variable(channel, var_name, p_contact->m_url->url_user);
+                                       sip_redirect_fork = switch_channel_get_variable(channel, "sip_redirect_fork");
+                                       
+                                       if (switch_true(sip_redirect_fork)) {
+                                               *separator = ',';
                                        }
-                                       if (p_contact->m_url->url_host) {
-                                               switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_host_%d", i);
-                                               switch_channel_set_variable_partner(channel, var_name, p_contact->m_url->url_host);
-                                               switch_channel_set_variable(channel, var_name, p_contact->m_url->url_host);
+
+                                       for (p_contact = sip->sip_contact; p_contact; p_contact = p_contact->m_next) {
+                                               if (p_contact->m_url) {
+                                                       full_contact = sip_header_as_string(home, (void *) sip->sip_contact);
+                                                       invite_contact = sofia_glue_strip_uri(full_contact);
+                                                       
+                                                       switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_%d", i);
+                                                       switch_channel_set_variable(a_channel, var_name, full_contact);
+                                                       
+                                                       if (i == 0) {
+                                                               switch_channel_set_variable(channel, "sip_redirected_to", full_contact);
+                                                               switch_channel_set_variable(a_channel, "sip_redirected_to", full_contact);
+                                                       }
+                                                       
+                                                       if (p_contact->m_url->url_user) {
+                                                               switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_user_%d", i);
+                                                               switch_channel_set_variable(channel, var_name, p_contact->m_url->url_user);
+                                                               switch_channel_set_variable(a_channel, var_name, p_contact->m_url->url_user);
+                                                       }
+                                                       if (p_contact->m_url->url_host) {
+                                                               switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_host_%d", i);
+                                                               switch_channel_set_variable(channel, var_name, p_contact->m_url->url_host);
+                                                               switch_channel_set_variable(a_channel, var_name, p_contact->m_url->url_host);
+                                                       }
+                                                       if (p_contact->m_url->url_params) {
+                                                               switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_params_%d", i);
+                                                               switch_channel_set_variable(channel, var_name, p_contact->m_url->url_params);
+                                                               switch_channel_set_variable(a_channel, var_name, p_contact->m_url->url_params);
+                                                       }
+                                                       
+                                                       switch_snprintf(var_name, sizeof(var_name), "sip_redirect_dialstring_%d", i);
+                                                       switch_channel_set_variable_printf(channel, var_name, "sofia/%s/%s", sip_redirect_profile, invite_contact);
+                                                       switch_channel_set_variable_printf(a_channel, var_name, "sofia/%s/%s", sip_redirect_profile, invite_contact);
+                                                       stream.write_function(&stream, "%ssofia/%s/%s", i ? separator : "", sip_redirect_profile, invite_contact);
+                                                       free(invite_contact);
+                                                       i++;
+                                               }
                                        }
-                                       if (p_contact->m_url->url_params) {
-                                               switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_params_%d", i);
-                                               switch_channel_set_variable_partner(channel, var_name, p_contact->m_url->url_params);
-                                               switch_channel_set_variable(channel, var_name, p_contact->m_url->url_params);
+                                       
+                                       redirect_dialstring = stream.data;
+                                       
+                                       switch_channel_set_variable(channel, "sip_redirect_dialstring", redirect_dialstring);
+                                       switch_channel_set_variable(a_channel, "sip_redirect_dialstring", redirect_dialstring);
+                                       
+                                       p_contact = sip->sip_contact;
+                                       full_contact = sip_header_as_string(home, (void *) sip->sip_contact);
+                                       
+                                       if ((diversion_header = sofia_glue_get_unknown_header(sip, "diversion"))) {
+                                               switch_channel_set_variable(channel, "sip_redirected_by", diversion_header);
+                                               switch_channel_set_variable(a_channel, "sip_redirected_by", diversion_header);
                                        }
-                                       p_contact = p_contact->m_next;
-                                       i++;
+                                       
+                                       if (sofia_test_pflag(profile, PFLAG_MANUAL_REDIRECT)) {
+                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Redirect: Transfering to %s %s %s\n", 
+                                                                                 p_contact->m_url->url_user, sip_redirect_dialplan, sip_redirect_context);
+                                               switch_ivr_session_transfer(a_session, p_contact->m_url->url_user, sip_redirect_dialplan, sip_redirect_context);                                        
+                                       } else if ((!strcmp(profile->sipip, p_contact->m_url->url_host))
+                                                          || (!strcmp(profile->extsipip, p_contact->m_url->url_host))
+                                                          || (switch_xml_locate_domain(p_contact->m_url->url_host, NULL, &root, &domain) == SWITCH_STATUS_SUCCESS)) {
+                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Redirect: Transfering to %s\n", p_contact->m_url->url_user);
+                                               switch_ivr_session_transfer(a_session, p_contact->m_url->url_user, NULL, NULL);
+                                       } else {
+                                               invite_contact = sofia_glue_strip_uri(full_contact);
+                                               tech_pvt->redirected = switch_core_session_strdup(session, invite_contact);
+                                               free(invite_contact);
+                                       }
+                                       
+                                       if (home) {
+                                               su_home_unref(home);
+                                               home = NULL;
+                                       }
+
+                                       free(stream.data);
+                                       switch_core_session_rwunlock(a_session);
+                               }
+                       } else {
+                               su_home_t *home = su_home_new(sizeof(*home));
+                               switch_assert(home != NULL);
+                               full_contact = sip_header_as_string(home, (void *) sip->sip_contact);
+                               invite_contact = sofia_glue_strip_uri(full_contact);
+
+                               tech_pvt->redirected = switch_core_session_strdup(session, invite_contact);
+
+                               free(invite_contact);
+
+                               if (home) {
+                                       su_home_unref(home);
+                                       home = NULL;
                                }
                        }
                }
@@ -3084,6 +3176,22 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
                        SIPTAG_REPLACES_STR_REF(replaces_str), SOATAG_LOCAL_SDP_STR_REF(l_sdp), SOATAG_REMOTE_SDP_STR_REF(r_sdp), TAG_END());
        
        if (ss_state == nua_callstate_terminated) {
+
+               if ((status == 302 || status == 305) && session) {
+                       channel = switch_core_session_get_channel(session);
+                       tech_pvt = switch_core_session_get_private(session);
+                       
+                       if (!tech_pvt || !tech_pvt->nh) {
+                               goto done;
+                       }
+                       
+
+                       if (tech_pvt->redirected) {
+                               sofia_glue_do_invite(session);
+                               goto done;
+                       }
+               }
+
                if (sofia_private) {
                        sofia_private->destroy_me = 1;
                }
@@ -3493,7 +3601,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
                        sdp_session_t *sdp;
                        uint8_t match = 0;
                        int is_ok = 1;
-                       
+
                        sofia_clear_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE);
 
                        if (tech_pvt->num_codecs) {
index 772ad1fdc3f6f5e56dd562f495a2026fff98b960..3cdd9b3628931ec8c291381ebbd66c0e7080d1ab 100644 (file)
@@ -1705,6 +1705,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
        nua_invite(tech_pvt->nh,
                           NUTAG_AUTOANSWER(0),
                           NUTAG_SESSION_TIMER(session_timeout),
+                          TAG_IF(tech_pvt->redirected, NUTAG_URL(tech_pvt->redirected)),
                           TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
                           TAG_IF(!switch_strlen_zero(tech_pvt->rpid), SIPTAG_REMOTE_PARTY_ID_STR(tech_pvt->rpid)),
                           TAG_IF(!switch_strlen_zero(tech_pvt->preferred_id), SIPTAG_P_PREFERRED_IDENTITY_STR(tech_pvt->preferred_id)),
@@ -1724,6 +1725,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
                           SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), SOATAG_HOLD(holdstr), TAG_END());
 
        switch_safe_free(stream.data);
+       tech_pvt->redirected = NULL;
 
        return SWITCH_STATUS_SUCCESS;
 }