]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Skinny: Handle network-address-change trap event
authorMathieu Parent <math.parent@gmail.com>
Thu, 2 Sep 2010 22:06:50 +0000 (00:06 +0200)
committerMathieu Parent <math.parent@gmail.com>
Thu, 2 Sep 2010 22:09:10 +0000 (00:09 +0200)
- add auto-restart param to each profile (if true, ip is automaticaly changed)
- some cleaning (unused args in flush_listener, better logs)

conf/skinny_profiles/internal.xml
src/mod/endpoints/mod_skinny/mod_skinny.c
src/mod/endpoints/mod_skinny/mod_skinny.h
src/mod/endpoints/mod_skinny/skinny_api.c
src/mod/endpoints/mod_skinny/skinny_protocol.c

index eaa493c047ddb1b973d3f5087ff190d86f111e5d..e48557b2344f9c4abbcd391ce2fffeec2045dae5 100644 (file)
@@ -11,6 +11,7 @@
     <param name="date-format" value="D/M/Y"/>
     <param name="odbc-dsn" value=""/>
     <param name="debug" value="4"/>
+    <param name="auto-restart" value="true"/>
   </settings>
   <device-types>
     <device-type id="Cisco ATA 186">
index 9ee9e1e45d99ab5d51690f09da84e6838208f3a4..5da1367a3537a8b49099c475f28d843c6c3e6762 100644 (file)
@@ -121,6 +121,7 @@ switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stre
        stream->write_function(stream, "Date-Format       \t%s\n", profile->date_format);
        stream->write_function(stream, "DBName            \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn));
        stream->write_function(stream, "Debug             \t%d\n", profile->debug);
+       stream->write_function(stream, "Auto-Restart      \t%d\n", profile->auto_restart);
        /* stats */
        stream->write_function(stream, "CALLS-IN          \t%d\n", profile->ib_calls);
        stream->write_function(stream, "FAILED-CALLS-IN   \t%d\n", profile->ib_failed_calls);
@@ -1187,7 +1188,8 @@ uint8_t listener_is_ready(listener_t *listener)
                && listener
                && listener->sock
                && switch_test_flag(listener, LFLAG_RUNNING)
-               && listener->profile->listener_ready;
+               && switch_test_flag(listener->profile, PFLAG_LISTENER_READY)
+               && !switch_test_flag(listener->profile, PFLAG_RESPAWN);
 }
 
 static void add_listener(listener_t *listener)
@@ -1248,7 +1250,7 @@ static void walk_listeners(skinny_listener_callback_func_t callback, void *pvt)
        switch_mutex_unlock(globals.mutex);
 }
 
-static void flush_listener(listener_t *listener, switch_bool_t flush_log, switch_bool_t flush_events)
+static void flush_listener(listener_t *listener)
 {
 
        if(!zstr(listener->device_name)) {
@@ -1410,7 +1412,17 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
                status = skinny_read_packet(listener, &request);
 
                if (status != SWITCH_STATUS_SUCCESS) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Socket Error!\n");
+                       switch(status) {
+                               case SWITCH_STATUS_BREAK:
+                                       break;
+                               case SWITCH_STATUS_TIMEOUT:
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Communication Time Out with %s:%d.\n",
+                                               listener->remote_ip, listener->remote_port);
+                                       break;
+                               default: 
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Communication Error with %s:%d.\n",
+                                               listener->remote_ip, listener->remote_port);
+                       }
                        switch_clear_flag_locked(listener, LFLAG_RUNNING);
                        break;
                }
@@ -1432,11 +1444,12 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
        remove_listener(listener);
 
        if (listener->profile->debug > 0) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session complete, waiting for children\n");
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Communication Complete with %s:%d.\n",
+                       listener->remote_ip, listener->remote_port);
        }
 
        switch_thread_rwlock_wrlock(listener->rwlock);
-       flush_listener(listener, SWITCH_TRUE, SWITCH_TRUE);
+       flush_listener(listener);
 
        if (listener->sock) {
                close_socket(&listener->sock, profile);
@@ -1445,19 +1458,10 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
        switch_thread_rwlock_unlock(listener->rwlock);
 
        if (listener->profile->debug > 0) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Closed\n");
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Communication Closed with %s:%d.\n",
+                       listener->remote_ip, listener->remote_port);
        }
 
-       /* TODO
-       for(int line = 0 ; line < SKINNY_MAX_BUTTON_COUNT ; line++) {
-               if(listener->session[line]) {
-                       switch_channel_clear_flag(switch_core_session_get_channel(listener->session[line]), CF_CONTROLLED);
-                       //TODO switch_clear_flag_locked(listener, LFLAG_SESSION);
-                       switch_core_session_rwunlock(listener->session[line]);
-                       destroy_pool = 0;
-               }
-       }
-       */
        if(destroy_pool == 0) {
                goto no_destroy_pool;
        }
@@ -1502,6 +1506,7 @@ static void *SWITCH_THREAD_FUNC skinny_profile_run(switch_thread_t *thread, void
                return NULL;
        }
 
+new_socket:
        while(globals.running) {
                rv = switch_sockaddr_info_get(&sa, profile->ip, SWITCH_INET, profile->port, 0, tmp_pool);
                if (rv)
@@ -1526,7 +1531,7 @@ static void *SWITCH_THREAD_FUNC skinny_profile_run(switch_thread_t *thread, void
                switch_yield(100000);
        }
 
-       profile->listener_ready = 1;
+       switch_set_flag_locked(profile, PFLAG_LISTENER_READY);
 
        while(globals.running) {
 
@@ -1539,6 +1544,10 @@ static void *SWITCH_THREAD_FUNC skinny_profile_run(switch_thread_t *thread, void
                        if (!globals.running) {
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting Down\n");
                                goto end;
+                       } else if (switch_test_flag(profile, PFLAG_RESPAWN)) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Creating a new socket\n");
+                               switch_clear_flag_locked(profile, PFLAG_RESPAWN);
+                               goto new_socket;
                        } else {
                                /* I wish we could use strerror_r here but its not defined everywhere =/ */
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error [%s]\n", strerror(errno));
@@ -1590,6 +1599,17 @@ static void *SWITCH_THREAD_FUNC skinny_profile_run(switch_thread_t *thread, void
        return NULL;
 }
 
+
+void launch_skinny_profile_thread(skinny_profile_t *profile) {
+       switch_thread_t *thread;
+       switch_threadattr_t *thd_attr = NULL;
+
+       switch_threadattr_create(&thd_attr, profile->pool);
+       switch_threadattr_detach_set(thd_attr, 1);
+       switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+       switch_thread_create(&thread, thd_attr, skinny_profile_run, profile, profile->pool);
+}
+
 /*****************************************************************************/
 /* MODULE FUNCTIONS */
 /*****************************************************************************/
@@ -1603,9 +1623,9 @@ switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, c
        if (!var)
                return SWITCH_STATUS_FALSE;
 
-       if (profile->sock && (!strcasecmp(var, "ip") || !strcasecmp(var, "port") || !strcasecmp(var, "odbc-dsn"))) {
+       if (profile->sock && !strcasecmp(var, "odbc-dsn")) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
-                       "Skinny profile settings 'ip', 'port' and 'odbc-dsn' can't be changed while running\n");
+                       "Skinny profile setting 'odbc-dsn' can't be changed while running\n");
                return SWITCH_STATUS_FALSE;
        }
 
@@ -1643,9 +1663,17 @@ switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, c
                }
        } else if (!strcasecmp(var, "debug")) {
                profile->debug = atoi(val);
+       } else if (!strcasecmp(var, "auto-restart")) {
+               profile->auto_restart = switch_true(val);
        } else {
                return SWITCH_STATUS_FALSE;
        }
+       if (profile->sock && (!strcasecmp(var, "ip") || !strcasecmp(var, "port"))) {
+               switch_set_flag_locked(profile, PFLAG_RESPAWN);
+               switch_clear_flag_locked(profile, PFLAG_LISTENER_READY);
+               close_socket(&profile->sock, profile);
+       }
+
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -1684,9 +1712,11 @@ static switch_status_t load_skinny_config(void)
                                profile = switch_core_alloc(profile_pool, sizeof(skinny_profile_t));
                                profile->pool = profile_pool;
                                profile->name = switch_core_strdup(profile->pool, profile_name);
-                               switch_mutex_init(&profile->listener_mutex, SWITCH_MUTEX_NESTED, profile->pool);
+                               profile->auto_restart = SWITCH_TRUE;
                                switch_mutex_init(&profile->sql_mutex, SWITCH_MUTEX_NESTED, profile->pool);
+                               switch_mutex_init(&profile->listener_mutex, SWITCH_MUTEX_NESTED, profile->pool);
                                switch_mutex_init(&profile->sock_mutex, SWITCH_MUTEX_NESTED, profile->pool);
+                               switch_mutex_init(&profile->flag_mutex, SWITCH_MUTEX_NESTED, profile->pool);
                
                                for (param = switch_xml_child(xsettings, "param"); param; param = param->next) {
                                        char *var = (char *) switch_xml_attr_soft(param, "name");
@@ -1950,6 +1980,41 @@ static void skinny_message_waiting_event_handler(switch_event_t *event)
 }
 
 
+static void skinny_trap_event_handler(switch_event_t *event)
+{
+       const char *cond = switch_event_get_header(event, "condition");
+
+
+       if (cond && !strcmp(cond, "network-address-change") && globals.auto_restart) {
+               const char *old_ip4 = switch_event_get_header_nil(event, "network-address-previous-v4");
+               const char *new_ip4 = switch_event_get_header_nil(event, "network-address-change-v4");
+               const char *old_ip6 = switch_event_get_header_nil(event, "network-address-previous-v6");
+               const char *new_ip6 = switch_event_get_header_nil(event, "network-address-change-v6");
+               switch_hash_index_t *hi;
+               const void *var;
+               void *val;
+               skinny_profile_t *profile;
+
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "EVENT_TRAP: IP change detected\n");
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "IP change detected [%s]->[%s] [%s]->[%s]\n", old_ip4, new_ip4, old_ip6, new_ip6);
+
+               switch_mutex_lock(globals.mutex);
+               if (globals.profile_hash) {
+                       for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+                               switch_hash_this(hi, &var, NULL, &val);
+                               if ((profile = (skinny_profile_t *) val) && profile->auto_restart) {
+                                       if (!strcmp(profile->ip, old_ip4)) {
+                                               skinny_profile_set(profile, "ip", new_ip4);
+                                       } else if (!strcmp(profile->ip, old_ip6)) {
+                                               skinny_profile_set(profile, "ip", new_ip6);
+                                       }
+                               }
+                       }
+               }
+               switch_mutex_unlock(globals.mutex);
+       }
+
+}
 /*****************************************************************************/
 SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
 {
@@ -1964,6 +2029,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
        switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
        switch_core_hash_init(&globals.profile_hash, globals.pool);
        globals.running = 1;
+       globals.auto_restart = SWITCH_TRUE;
 
        load_skinny_config();
 
@@ -1980,6 +2046,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our message waiting handler!\n");
                /* Not such severe to prevent loading */
        }
+       if ((switch_event_bind_removable(modname, SWITCH_EVENT_TRAP, NULL, skinny_trap_event_handler, NULL, &globals.trap_node) != SWITCH_STATUS_SUCCESS)) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our trap handler!\n");
+               /* Not such severe to prevent loading */
+       }
 
        /* reserve events */
        if (switch_event_reserve_subclass(SKINNY_EVENT_REGISTER) != SWITCH_STATUS_SUCCESS) {
@@ -2017,16 +2087,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
        for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) {
                void *val;
                skinny_profile_t *profile;
-               switch_thread_t *thread;
-               switch_threadattr_t *thd_attr = NULL;
 
                switch_hash_this(hi, NULL, NULL, &val);
                profile = (skinny_profile_t *) val;
-
-               switch_threadattr_create(&thd_attr, profile->pool);
-               switch_threadattr_detach_set(thd_attr, 1);
-               switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
-               switch_thread_create(&thread, thd_attr, skinny_profile_run, profile, profile->pool);
+               
+               launch_skinny_profile_thread(profile);
        }
        switch_mutex_unlock(globals.mutex);
 
@@ -2048,6 +2113,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown)
        switch_event_unbind(&globals.heartbeat_node);
        switch_event_unbind(&globals.call_state_node);
        switch_event_unbind(&globals.message_waiting_node);
+       switch_event_unbind(&globals.trap_node);
        switch_event_free_subclass(SKINNY_EVENT_REGISTER);
        switch_event_free_subclass(SKINNY_EVENT_UNREGISTER);
        switch_event_free_subclass(SKINNY_EVENT_EXPIRE);
index 41b9b72a6e9bde5a9a084f9f6697ed24ca37221d..f52f171fdc2c5d70d2a843e716d5f7642702c820 100644 (file)
@@ -52,11 +52,18 @@ struct skinny_globals {
     switch_event_node_t *heartbeat_node;
     switch_event_node_t *call_state_node;
     switch_event_node_t *message_waiting_node;
+    switch_event_node_t *trap_node;
+    int auto_restart;
 };
 typedef struct skinny_globals skinny_globals_t;
 
 extern skinny_globals_t globals;
 
+typedef enum {
+    PFLAG_LISTENER_READY = (1 << 0),
+    PFLAG_RESPAWN = (1 << 1),
+} profile_flag_t;
+
 struct skinny_profile {
     /* prefs */
     char *name;
@@ -70,6 +77,7 @@ struct skinny_profile {
     uint32_t keep_alive;
     char date_format[6];
     int debug;
+       int auto_restart;
     switch_hash_t *device_type_params_hash;
     /* db */
     char *dbname;
@@ -89,7 +97,8 @@ struct skinny_profile {
     switch_socket_t *sock;
     switch_mutex_t *sock_mutex;
     struct listener *listeners;
-    uint8_t listener_ready;
+    int flags;
+    switch_mutex_t *flag_mutex;
     /* call id */
     uint32_t next_call_id;
     /* others */
@@ -114,7 +123,7 @@ typedef enum {
 
 typedef enum {
     LFLAG_RUNNING = (1 << 0),
-} event_flag_t;
+} listener_flag_t;
 
 #define SKINNY_MAX_LINES 42
 struct listener {
index 0ef0beb2d55507acd87fc0535757afc17cbefb28..86eea74fc832012827dcde45a91cfd9b266196dc 100644 (file)
@@ -230,6 +230,7 @@ static switch_status_t skinny_api_list_settings(const char *line, const char *cu
     switch_console_push_match(&my_matches, "date-format");
     switch_console_push_match(&my_matches, "odbc-dsn");
     switch_console_push_match(&my_matches, "debug");
+    switch_console_push_match(&my_matches, "auto-restart");
 
     if (my_matches) {
            *matches = my_matches;
index ba4cba70db62ccd3eec58023bcdb547f18cec571..28699b9c039e770953c4e579cb64f7bd64aae43e 100644 (file)
@@ -119,7 +119,7 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req)
        }
 
        if (!listener_is_ready(listener)) {
-               return SWITCH_STATUS_FALSE;
+               return SWITCH_STATUS_BREAK;
        }
 
        ptr = mbuf;
@@ -136,7 +136,10 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req)
 
                status = switch_socket_recv(listener->sock, ptr, &mlen);
 
-               if (!listener_is_ready(listener) || (!SWITCH_STATUS_IS_BREAK(status) && status != SWITCH_STATUS_SUCCESS)) {
+               if (!listener_is_ready(listener)) {
+                       return SWITCH_STATUS_BREAK;
+               }
+               if (!SWITCH_STATUS_IS_BREAK(status) && status != SWITCH_STATUS_SUCCESS) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Socket break.\n");
                        return SWITCH_STATUS_FALSE;
                }
@@ -167,20 +170,13 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req)
                                }
                                if(bytes >= request->length + 2*SKINNY_MESSAGE_FIELD_SIZE) {
                                        /* Message body */
-#ifdef SKINNY_MEGA_DEBUG
-                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
-                                               "Got complete request: length=%d,reserved=%x,type=%x,data=%d\n",
-                                               request->length,request->reserved,request->type,request->data.as_char);
-#endif
                                        *req = request;
                                        return  SWITCH_STATUS_SUCCESS;
                                }
                        }
                }
                if (listener->expire_time && listener->expire_time < switch_epoch_time_now(NULL)) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Listener timed out.\n");
-                       switch_clear_flag_locked(listener, LFLAG_RUNNING);
-                       return SWITCH_STATUS_FALSE;
+                       return SWITCH_STATUS_TIMEOUT;
                }
                if (do_sleep) {
                        switch_cond_next();