]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-5987 pushing the patch now since no matter what its better than before
authorAnthony Minessale <anthm@freeswitch.org>
Tue, 10 Dec 2013 19:04:26 +0000 (00:04 +0500)
committerAnthony Minessale <anthm@freeswitch.org>
Tue, 10 Dec 2013 19:04:26 +0000 (00:04 +0500)
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_sofia/sofia_presence.c
src/mod/endpoints/mod_sofia/sofia_reg.c

index 952fce2f9f1c518022712847c03cf1071a358058..f80539684ab9a4e95b7bff4b6ffc09e9e7594032 100644 (file)
@@ -164,7 +164,6 @@ typedef struct sofia_dispatch_event_s {
 
 struct sofia_private {
        char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1];
-       sofia_gateway_t *gateway;
        char gateway_name[256];
        char auth_gateway_name[256];
        char *call_id;
@@ -422,6 +421,7 @@ typedef enum {
 
 struct sofia_gateway_subscription {
        sofia_gateway_t *gateway;
+       sofia_private_t *sofia_private;
        nua_handle_t *nh;
        char *expires_str;
        char *event;                            /* eg, 'message-summary' to subscribe to MWI events */
index f9fc330c7173bdd6da50e5b126b78d60ca74a0e8..ad581d877e3202a6deef4d434fb92bf328f89a03 100644 (file)
@@ -337,6 +337,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
        switch_event_t *s_event = NULL;
        sofia_gateway_subscription_t *gw_sub_ptr;
        int sub_state;
+       sofia_gateway_t *gateway = NULL;
 
        tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END());
 
@@ -445,19 +446,25 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
                }
        }
 
-       if (!sofia_private || !sofia_private->gateway) {
+       if (!sofia_private || zstr(sofia_private->gateway_name)) {
                if (profile->debug) {
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Gateway information missing Subscription Event: %s\n",
                                                          sip->sip_event->o_type);
                }
                goto error;
        }
+       
+
+       if (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
+               goto error;
+       }
 
        /* find the corresponding gateway subscription (if any) */
-       if (!(gw_sub_ptr = sofia_find_gateway_subscription(sofia_private->gateway, sip->sip_event->o_type))) {
+       if (!(gw_sub_ptr = sofia_find_gateway_subscription(gateway, sip->sip_event->o_type))) {
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
                                                  "Could not find gateway subscription.  Gateway: %s.  Subscription Event: %s\n",
-                                                 sofia_private->gateway->name, sip->sip_event->o_type);
+                                                 gateway->name, sip->sip_event->o_type);
                goto error;
        }
 
@@ -466,17 +473,28 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
                goto error;
        }
 
+       if (sip->sip_subscription_state && sip->sip_subscription_state->ss_expires) {
+               int delta = atoi(sip->sip_subscription_state->ss_expires);
+
+               delta /= 2;
+
+               if (delta < 1) {
+                       delta = 1;
+               }
+               gw_sub_ptr->expires = switch_epoch_time_now(NULL) + delta;
+       }
+
        /* dispatch freeswitch event */
        if (switch_event_create(&s_event, SWITCH_EVENT_NOTIFY_IN) == SWITCH_STATUS_SUCCESS) {
                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event", sip->sip_event->o_type);
                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "pl_data", sip->sip_payload ? sip->sip_payload->pl_data : "");
                if ( sip->sip_content_type != NULL )
                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "sip_content_type", sip->sip_content_type->c_type);
-               switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", sofia_private->gateway->profile->sip_port);
+               switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", gateway->profile->sip_port);
                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "module_name", "mod_sofia");
-               switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", sofia_private->gateway->profile->name);
-               switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", sofia_private->gateway->profile->url);
-               switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "gateway_name", sofia_private->gateway->name);
+               switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", gateway->profile->name);
+               switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", gateway->profile->url);
+               switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "gateway_name", gateway->name);
                if ( sip->sip_call_info != NULL ) {
                        sip_call_info_t *call_info = sip->sip_call_info;
                        int cur_len = 0;
@@ -565,12 +583,16 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
 
   end:
 
-       if (sub_state == nua_substate_terminated && sofia_private && sofia_private != &mod_sofia_globals.destroy_private &&
+       if (!gateway && sub_state == nua_substate_terminated && sofia_private && sofia_private != &mod_sofia_globals.destroy_private &&
                sofia_private != &mod_sofia_globals.keep_private) {
                sofia_private->destroy_nh = 1;
                sofia_private->destroy_me = 1;
        }
 
+       if (gateway) {
+               sofia_reg_release_gateway(gateway);
+       }
+
 }
 
 void sofia_handle_sip_i_bye(switch_core_session_t *session, int status,
@@ -1049,9 +1071,9 @@ static void our_sofia_event_callback(nua_event_t event,
 
 
        if (sofia_private && sofia_private != &mod_sofia_globals.destroy_private && sofia_private != &mod_sofia_globals.keep_private) {
-               if ((gateway = sofia_private->gateway)) {
-                       /* Released in sofia_reg_release_gateway() */
-                       if (sofia_reg_gateway_rdlock(gateway) != SWITCH_STATUS_SUCCESS) {
+
+               if (!zstr(sofia_private->gateway_name)) {
+                       if (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
                                return;
                        }
                } else if (!zstr(sofia_private->uuid)) {
@@ -1499,9 +1521,16 @@ static void our_sofia_event_callback(nua_event_t event,
        case nua_r_authenticate:
 
                if (status >= 500) {
-                       if (sofia_private && sofia_private->gateway) {
-                               nua_handle_destroy(sofia_private->gateway->nh);
-                               sofia_private->gateway->nh = NULL;
+                       if (sofia_private && !zstr(sofia_private->gateway_name)) {
+                               sofia_gateway_t *gateway = NULL;
+
+                               if ((gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
+                                       nua_handle_bind(gateway->nh, NULL);
+                                       gateway->sofia_private = NULL;
+                                       nua_handle_destroy(gateway->nh);
+                                       gateway->nh = NULL;
+                                       sofia_reg_release_gateway(gateway);
+                               }
                        } else {
                                nua_handle_destroy(nh);
                        }
@@ -2325,10 +2354,9 @@ void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread
 
                        if (++gateway_loops >= GATEWAY_SECONDS) {
                                sofia_reg_check_gateway(profile, switch_epoch_time_now(NULL));
+                               sofia_sub_check_gateway(profile, switch_epoch_time_now(NULL));
                                gateway_loops = 0;
                        }
-
-                       sofia_sub_check_gateway(profile, time(NULL));
                }
 
                switch_yield(1000000);
index 747f4491e51083dd8faf2511f62e0b1170194dc3..dd0fe1ac95bd3fb8538f0cc57536c24651da4506 100644 (file)
@@ -4285,6 +4285,7 @@ void sofia_presence_handle_sip_r_subscribe(int status,
 {
        sip_event_t const *o = NULL;
        sofia_gateway_subscription_t *gw_sub_ptr;
+       sofia_gateway_t *gateway = NULL;
 
        if (!sip) {
                return;
@@ -4297,16 +4298,23 @@ void sofia_presence_handle_sip_r_subscribe(int status,
                return;
        }
 
-       if (!sofia_private || !sofia_private->gateway) {
+       if (!sofia_private || zstr(sofia_private->gateway_name)) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
                return;
        }
 
+
+       if (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
+               return;
+       }
+
+
        /* Find the subscription if one exists */
-       if (!(gw_sub_ptr = sofia_find_gateway_subscription(sofia_private->gateway, o->o_type))) {
+       if (!(gw_sub_ptr = sofia_find_gateway_subscription(gateway, o->o_type))) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Could not find gateway subscription.  Gateway: %s.  Subscription Event: %s\n",
-                                                 sofia_private->gateway->name, o->o_type);
-               return;
+                                                 gateway->name, o->o_type);
+               goto end;
        }
 
        /* Update the subscription status for the subscription */
@@ -4326,19 +4334,22 @@ void sofia_presence_handle_sip_r_subscribe(int status,
        default:
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "status (%d) != 200, updated state to SUB_STATE_FAILED.\n", status);
                gw_sub_ptr->state = SUB_STATE_FAILED;
+               gw_sub_ptr->expires = switch_epoch_time_now(NULL);
+               gw_sub_ptr->retry = switch_epoch_time_now(NULL);
 
-               if (sofia_private) {
-                       if (gw_sub_ptr->nh) {
-                               nua_handle_bind(gw_sub_ptr->nh, NULL);
-                               nua_handle_destroy(gw_sub_ptr->nh);
-                               gw_sub_ptr->nh = NULL;
-                       }
-               } else {
+               if (!sofia_private) {
                        nua_handle_destroy(nh);
                }
-
+               
                break;
        }
+
+ end:
+
+       if (gateway) {
+               sofia_reg_release_gateway(gateway);
+       }
+
 }
 
 
index 821a08688051a46d503f3600607d076d6776a340..fe4f0c57b9e21b925cb0be02dabed72ab508c93d 100644 (file)
@@ -47,7 +47,7 @@ static void sofia_reg_new_handle(sofia_gateway_t *gateway_ptr, int attach)
                nua_handle_bind(gateway_ptr->nh, NULL);
                nua_handle_destroy(gateway_ptr->nh);
                gateway_ptr->nh = NULL;
-               sofia_private_free(gateway_ptr->sofia_private);
+               gateway_ptr->sofia_private = NULL;
        }
 
        gateway_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL,
@@ -56,23 +56,24 @@ static void sofia_reg_new_handle(sofia_gateway_t *gateway_ptr, int attach)
                                                                 NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END());
        if (attach) {
                if (!gateway_ptr->sofia_private) {
-                       gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private));
+                       gateway_ptr->sofia_private = su_alloc(gateway_ptr->nh->nh_home, sizeof(*gateway_ptr->sofia_private));
                        switch_assert(gateway_ptr->sofia_private);
                }
                memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private));
 
-               gateway_ptr->sofia_private->gateway = gateway_ptr;
+               switch_set_string(gateway_ptr->sofia_private->gateway_name, gateway_ptr->name);
                nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private);
        }
 }
 
-static void sofia_reg_new_sub_handle(sofia_gateway_subscription_t *gw_sub_ptr, int attach)
+static void sofia_reg_new_sub_handle(sofia_gateway_subscription_t *gw_sub_ptr)
 {      
        sofia_gateway_t *gateway_ptr = gw_sub_ptr->gateway;
        char *user_via = NULL;
        char *register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy);
        int ss_state = nua_callstate_authenticating;
        
+       
        /* check for NAT and place a Via header if necessary (hostname or non-local IP) */
        if (register_host && sofia_glue_check_nat(gateway_ptr->profile, register_host)) {
                user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
@@ -82,7 +83,7 @@ static void sofia_reg_new_sub_handle(sofia_gateway_subscription_t *gw_sub_ptr, i
                nua_handle_bind(gw_sub_ptr->nh, NULL);
                nua_handle_destroy(gw_sub_ptr->nh);
                gw_sub_ptr->nh = NULL;
-               sofia_private_free(gateway_ptr->sofia_private);
+               gw_sub_ptr->sofia_private = NULL;
        }
                
        gw_sub_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL,
@@ -90,16 +91,14 @@ static void sofia_reg_new_sub_handle(sofia_gateway_subscription_t *gw_sub_ptr, i
                                                                         TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
                                                                         SIPTAG_TO_STR(gateway_ptr->register_to),
                                                                         NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END());
-       if (attach) {
-               if (!gateway_ptr->sofia_private) {
-                       gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private));
-                       switch_assert(gateway_ptr->sofia_private);
-               }
-               memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private));
-
-               gateway_ptr->sofia_private->gateway = gateway_ptr;
-               nua_handle_bind(gw_sub_ptr->nh, gateway_ptr->sofia_private);
+       if (!gw_sub_ptr->sofia_private) {
+               gw_sub_ptr->sofia_private = su_alloc(gw_sub_ptr->nh->nh_home, sizeof(*gw_sub_ptr->sofia_private));
+               switch_assert(gw_sub_ptr->sofia_private);
        }
+       memset(gw_sub_ptr->sofia_private, 0, sizeof(*gw_sub_ptr->sofia_private));
+       
+       switch_set_string(gw_sub_ptr->sofia_private->gateway_name, gateway_ptr->name);
+       nua_handle_bind(gw_sub_ptr->nh, gw_sub_ptr->sofia_private);
 
        switch_safe_free(register_host);
        switch_safe_free(user_via);
@@ -109,6 +108,8 @@ static void sofia_reg_kill_sub(sofia_gateway_subscription_t *gw_sub_ptr)
 {      
        sofia_gateway_t *gateway_ptr = gw_sub_ptr->gateway;
 
+       gw_sub_ptr->sofia_private = NULL;
+
        if (gw_sub_ptr->nh) {
                nua_handle_bind(gw_sub_ptr->nh, NULL);
        }
@@ -141,6 +142,7 @@ static void sofia_reg_kill_reg(sofia_gateway_t *gateway_ptr)
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Destroying registration handle for %s\n", gateway_ptr->name);
        }
 
+       gateway_ptr->sofia_private = NULL;
        nua_handle_bind(gateway_ptr->nh, NULL);
        nua_handle_destroy(gateway_ptr->nh);
        gateway_ptr->nh = NULL;
@@ -175,20 +177,18 @@ void sofia_reg_unregister(sofia_profile_t *profile)
                        nua_handle_bind(gateway_ptr->nh, NULL);
                }
 
-               if (gateway_ptr->sofia_private) {
-                       sofia_private_free(gateway_ptr->sofia_private);
-               }
-
                if (gateway_ptr->state == REG_STATE_REGED) {
                        sofia_reg_kill_reg(gateway_ptr);
                }
 
                for (gw_sub_ptr = gateway_ptr->subscriptions; gw_sub_ptr; gw_sub_ptr = gw_sub_ptr->next) {
+                       
                        if (gw_sub_ptr->state == SUB_STATE_SUBED) {
                                sofia_reg_kill_sub(gw_sub_ptr);
                        }
                }
 
+               gateway_ptr->subscriptions = NULL;
        }
        switch_mutex_unlock(mod_sofia_globals.hash_mutex);
 }
@@ -229,7 +229,7 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now)
                                break;
                        case SUB_STATE_UNSUBED:
 
-                               sofia_reg_new_sub_handle(gw_sub_ptr, 1);
+                               sofia_reg_new_sub_handle(gw_sub_ptr);
                                
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "subscribing to [%s] on gateway [%s]\n", gw_sub_ptr->event, gateway_ptr->name);
                                
@@ -2184,17 +2184,27 @@ void sofia_reg_handle_sip_r_register(int status,
                                                                sofia_dispatch_event_t *de,
                                                                         tagi_t tags[])
 {
+       sofia_gateway_t *gateway = NULL;
+       
+       if (sofia_private && !zstr(sofia_private->gateway_name)) {
+               gateway = sofia_reg_find_gateway(sofia_private->gateway_name); 
+       }
+
+
        if (status >= 500) {
-               if (sofia_private && sofia_private->gateway) {
-                       nua_handle_destroy(sofia_private->gateway->nh);
-                       sofia_private->gateway->nh = NULL;
+               if (sofia_private && gateway) {
+                       nua_handle_bind(gateway->nh, NULL);
+                       gateway->sofia_private = NULL;
+                       nua_handle_destroy(gateway->nh);
+                       gateway->nh = NULL;
+                       
                } else {
                        nua_handle_destroy(nh);
                }
        }
 
-       if (sofia_private && sofia_private->gateway) {
-               reg_state_t ostate = sofia_private->gateway->state;
+       if (sofia_private && gateway) {
+               reg_state_t ostate = gateway->state;
                switch (status) {
                case 200:
                        if (sip && sip->sip_contact) {
@@ -2206,7 +2216,7 @@ void sofia_reg_handle_sip_r_register(int status,
 
                                        for (; contact; contact = contact->m_next) {
                                                if ((full = sip_header_as_string(nh->nh_home, (void *) contact))) {
-                                                       if (switch_stristr(sofia_private->gateway->register_contact, full)) {
+                                                       if (switch_stristr(gateway->register_contact, full)) {
                                                                break;
                                                        }
 
@@ -2223,37 +2233,42 @@ void sofia_reg_handle_sip_r_register(int status,
                                        new_expires = contact->m_expires;
                                        expi = (uint32_t) atoi(new_expires);
 
-                                       if (expi > 0 && expi != sofia_private->gateway->freq) {
-                                               //sofia_private->gateway->freq = expi;
-                                               //sofia_private->gateway->expires_str = switch_core_sprintf(sofia_private->gateway->pool, "%d", expi);
+                                       if (expi > 0 && expi != gateway->freq) {
+                                               //gateway->freq = expi;
+                                               //gateway->expires_str = switch_core_sprintf(gateway->pool, "%d", expi);
                                                
                                                if (expi > 60) {
-                                                       sofia_private->gateway->expires = switch_epoch_time_now(NULL) + (expi - 15);
+                                                       gateway->expires = switch_epoch_time_now(NULL) + (expi - 15);
                                                } else {
-                                                       sofia_private->gateway->expires = switch_epoch_time_now(NULL) + (expi - 2);
+                                                       gateway->expires = switch_epoch_time_now(NULL) + (expi - 2);
                                                }
 
 
                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
-                                                                                 "Changing expire time to %d by request of proxy %s\n", expi, sofia_private->gateway->register_proxy);
+                                                                                 "Changing expire time to %d by request of proxy %s\n", expi, gateway->register_proxy);
                                        }
                                }
                        }
-                       sofia_private->gateway->state = REG_STATE_REGISTER;
+                       gateway->state = REG_STATE_REGISTER;
                        break;
                case 100:
                        break;
                default:
-                       sofia_private->gateway->state = REG_STATE_FAILED;
-                       sofia_private->gateway->failure_status = status;
+                       gateway->state = REG_STATE_FAILED;
+                       gateway->failure_status = status;
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s Registration Failed with status %s [%d]. failure #%d\n",
-                                                         sofia_private->gateway->name, switch_str_nil(phrase), status, ++sofia_private->gateway->failures);
+                                                         gateway->name, switch_str_nil(phrase), status, ++gateway->failures);
                        break;
                }
-               if (ostate != sofia_private->gateway->state) {
-                       sofia_reg_fire_custom_gateway_state_event(sofia_private->gateway, status, phrase);
+               if (ostate != gateway->state) {
+                       sofia_reg_fire_custom_gateway_state_event(gateway, status, phrase);
                }
        }
+
+       if (gateway) {
+               sofia_reg_release_gateway(gateway);
+       }
+
 }
 
 void sofia_reg_handle_sip_r_challenge(int status,
@@ -2282,8 +2297,12 @@ void sofia_reg_handle_sip_r_challenge(int status,
                sip_auth_password = switch_channel_get_variable(channel, "sip_auth_password");
        }
 
-       if (sofia_private && *sofia_private->auth_gateway_name) {
-               gw_name = sofia_private->auth_gateway_name;
+       if (sofia_private) {
+               if (*sofia_private->auth_gateway_name) {
+                       gw_name = sofia_private->auth_gateway_name;
+               } else if (*sofia_private->gateway_name) {
+                       gw_name = sofia_private->gateway_name;
+               }
        }
 
        if (session) {
@@ -2407,7 +2426,7 @@ void sofia_reg_handle_sip_r_challenge(int status,
        tl_gets(tags, NUTAG_CALLSTATE_REF(ss_state), SIPTAG_WWW_AUTHENTICATE_REF(authenticate), TAG_END());
 
        nua_authenticate(nh, 
-                                        TAG_IF(sofia_private && sofia_private->gateway, SIPTAG_EXPIRES_STR(gateway ? gateway->expires_str : "3600")), 
+                                        TAG_IF(gateway, SIPTAG_EXPIRES_STR(gateway ? gateway->expires_str : "3600")), 
                                         NUTAG_AUTH(authentication), TAG_END());
 
        goto end;