]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
skypopen: fixed management of skype clients crash
authorGiovanni Maruzzelli <gmaruzz@gmail.com>
Thu, 28 Oct 2010 18:20:17 +0000 (13:20 -0500)
committerGiovanni Maruzzelli <gmaruzz@gmail.com>
Thu, 28 Oct 2010 18:27:01 +0000 (13:27 -0500)
src/mod/endpoints/mod_skypopen/mod_skypopen.c
src/mod/endpoints/mod_skypopen/skypopen.h
src/mod/endpoints/mod_skypopen/skypopen_protocol.c

index f2f5c2ac39da630d474492f7cd2c336629abe50e..357332d1f49d1984fd2886856788d20a0faac031 100644 (file)
@@ -174,6 +174,7 @@ int running = 0;
 struct SkypopenList global_handles_list;
 extern int xio_error_handler(Display * dpy);
 extern int X11_errors_handler(Display * dpy, XErrorEvent * err);
+extern int xio_error_handler2(Display * dpy, XErrorEvent * err);
 #endif
 
 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_context, globals.context);
@@ -357,6 +358,8 @@ static switch_status_t interface_exists(char *the_interface)
 
        globals.SKYPOPEN_INTERFACES[interface_id].running = 0;
 
+       tech_pvt->interface_state = SKYPOPEN_STATE_DEAD;
+
        if (globals.SKYPOPEN_INTERFACES[interface_id].skypopen_signaling_thread) {
 #ifdef WIN32
                skypopen_signaling_write(tech_pvt, "DIE");
@@ -377,8 +380,8 @@ static switch_status_t interface_exists(char *the_interface)
                if (tech_pvt->running && tech_pvt->SkypopenHandles.disp) {
                        XEvent e;
                        Atom atom1 = XInternAtom(tech_pvt->SkypopenHandles.disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
-                       switch_sleep(1000);     //giovanni
-                       XFlush(tech_pvt->SkypopenHandles.disp); //giovanni
+                       switch_sleep(1000);     
+                       XFlush(tech_pvt->SkypopenHandles.disp);
                        memset(&e, 0, sizeof(e));
                        e.xclient.type = ClientMessage;
                        e.xclient.message_type = atom1; /*  leading message */
@@ -387,7 +390,7 @@ static switch_status_t interface_exists(char *the_interface)
                        e.xclient.format = 8;
 
                        XSendEvent(tech_pvt->SkypopenHandles.disp, tech_pvt->SkypopenHandles.win, False, 0, &e);
-                       XFlush(tech_pvt->SkypopenHandles.disp); //giovanni
+                       XFlush(tech_pvt->SkypopenHandles.disp); 
                }
 #endif
        }
@@ -399,9 +402,6 @@ static switch_status_t interface_exists(char *the_interface)
 
 #ifndef WIN32
        if (tech_pvt->SkypopenHandles.disp) {
-               DEBUGA_SKYPE("REMOVE CLOSIN X\n", SKYPOPEN_P_LOG);
-               XCloseDisplay(tech_pvt->SkypopenHandles.disp);
-               DEBUGA_SKYPE("REMOVE CLOSIN X END\n", SKYPOPEN_P_LOG);
        }
 #endif
 
@@ -420,7 +420,11 @@ static switch_status_t interface_exists(char *the_interface)
        } else {
                DEBUGA_SKYPE("interface '%s' STILL console\n", SKYPOPEN_P_LOG, the_interface);
        }
-       memset(&globals.SKYPOPEN_INTERFACES[interface_id], '\0', sizeof(private_t));
+       if(strlen(tech_pvt->session_uuid_str)){
+
+       }else{
+               memset(&globals.SKYPOPEN_INTERFACES[interface_id], '\0', sizeof(private_t));
+       }
        globals.real_interfaces--;
        switch_mutex_unlock(globals.mutex);
 
@@ -473,7 +477,9 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session)
        if (tech_pvt) {
                DEBUGA_SKYPE("%s CHANNEL DESTROY %s\n", SKYPOPEN_P_LOG, tech_pvt->name, switch_core_session_get_uuid(session));
 
-               tech_pvt->interface_state = SKYPOPEN_STATE_DOWN;
+               if (tech_pvt->interface_state != SKYPOPEN_STATE_DEAD) {
+                       tech_pvt->interface_state = SKYPOPEN_STATE_DOWN;
+               }
 
                switch_mutex_lock(tech_pvt->flag_mutex);
                switch_clear_flag(tech_pvt, TFLAG_IO);
@@ -553,13 +559,13 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session)
                //DEBUGA_SKYPE("debugging_hangup 18\n", SKYPOPEN_P_LOG);
 
                *tech_pvt->session_uuid_str = '\0';
-               tech_pvt->interface_state = SKYPOPEN_STATE_IDLE;
-               tech_pvt->skype_callflow = CALLFLOW_CALL_IDLE;
-#if 0
-               if (tech_pvt->skype_callflow == CALLFLOW_STATUS_FINISHED) {
+
+               if (tech_pvt->interface_state != SKYPOPEN_STATE_DEAD) {
+                       tech_pvt->interface_state = SKYPOPEN_STATE_IDLE;
                        tech_pvt->skype_callflow = CALLFLOW_CALL_IDLE;
+               }else{
+                       memset(tech_pvt, '\0', sizeof(private_t));
                }
-#endif //
                switch_core_session_set_private(session, NULL);
        } else {
                DEBUGA_SKYPE("!!!!!!NO tech_pvt!!!! CHANNEL DESTROY %s\n", SKYPOPEN_P_LOG, switch_core_session_get_uuid(session));
@@ -585,6 +591,9 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
        //DEBUGA_SKYPE("debugging_hangup 1\n", SKYPOPEN_P_LOG);
 
        if (tech_pvt) {
+               if (tech_pvt->interface_state == SKYPOPEN_STATE_DEAD) {
+                       return SWITCH_STATUS_SUCCESS;
+               }
                if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
                        if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
                                tech_pvt->ob_failed_calls++;
@@ -684,6 +693,10 @@ static switch_status_t channel_kill_channel(switch_core_session_t *session, int
                switch (sig) {
                case SWITCH_SIG_KILL:
                        DEBUGA_SKYPE("%s CHANNEL got SWITCH_SIG_KILL\n", SKYPOPEN_P_LOG, switch_channel_get_name(channel));
+                       if (tech_pvt->interface_state == SKYPOPEN_STATE_DEAD) {
+                               switch_channel_set_state(channel, CS_HANGUP);
+                               return SWITCH_STATUS_SUCCESS;
+                       }
                        tech_pvt->interface_state = SKYPOPEN_STATE_HANGUP_REQUESTED;
                        if (tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD) {
                                DEBUGA_SKYPE("FYI %s CHANNEL in CALLFLOW_STATUS_REMOTEHOLD got SWITCH_SIG_KILL\n", SKYPOPEN_P_LOG, switch_channel_get_name(channel));
@@ -1387,6 +1400,9 @@ static void *SWITCH_THREAD_FUNC skypopen_signaling_thread_func(switch_thread_t *
                        DEBUGA_SKYPE("skype call ended\n", SKYPOPEN_P_LOG);
 
                        if (tech_pvt) {
+                               if (tech_pvt->interface_state == SKYPOPEN_STATE_DEAD) {
+                                       break;
+                               }
                                session = switch_core_session_locate(tech_pvt->session_uuid_str);
                                if (session) {
                                        channel = switch_core_session_get_channel(session);
@@ -1935,28 +1951,17 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skypopen_load)
        // CLOUDTREE (Thomas Hazel)
 #ifndef WIN32
        // XXX: these assumes no one will override
-       XSetErrorHandler(X11_errors_handler);
+       //XSetErrorHandler(X11_errors_handler);
+       //XXX giovanni: seems that if Xserver is up, but skype client is crashed, the error is non fatal. Let's use Thomas handler in this case too
+       XSetErrorHandler(xio_error_handler2);
        XSetIOErrorHandler(xio_error_handler);
 
        memset(&global_handles_list, 0, sizeof(global_handles_list));
        switch_mutex_init(&globals.list_mutex, SWITCH_MUTEX_NESTED, skypopen_module_pool);
 #endif
 
-       // CLOUDTREE (Thomas Hazel) - load_configs no longer locks things up, no need to fail load
-       load_config(FULL_RELOAD);
-
-       // CLOUDTREE (Thomas Hazel) - setting "running = 1;" use to be located before "load_config"
        running = 1;
-
-       if (switch_event_reserve_subclass(MY_EVENT_INCOMING_CHATMESSAGE) != SWITCH_STATUS_SUCCESS) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
-               return SWITCH_STATUS_GENERR;
-       }
-
-       if (switch_event_reserve_subclass(MY_EVENT_INCOMING_RAW) != SWITCH_STATUS_SUCCESS) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
-               return SWITCH_STATUS_GENERR;
-       }
+       load_config(FULL_RELOAD);
 
        *module_interface = switch_loadable_module_create_module_interface(pool, modname);
        skypopen_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
@@ -1968,14 +1973,23 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skypopen_load)
 
                SWITCH_ADD_API(commands_api_interface, "sk", "Skypopen console commands", sk_function, SK_SYNTAX);
                SWITCH_ADD_API(commands_api_interface, "skypopen", "Skypopen interface commands", skypopen_function, SKYPOPEN_SYNTAX);
-               SWITCH_ADD_API(commands_api_interface, "skypopen_chat", "Skypopen_chat interface remote_skypename TEXT", skypopen_chat_function,
-                                          SKYPOPEN_CHAT_SYNTAX);
+               SWITCH_ADD_API(commands_api_interface, "skypopen_chat", "Skypopen_chat interface remote_skypename TEXT", skypopen_chat_function, SKYPOPEN_CHAT_SYNTAX);
                SWITCH_ADD_CHAT(chat_interface, MDL_CHAT_PROTO, chat_send);
 
+               if (switch_event_reserve_subclass(MY_EVENT_INCOMING_CHATMESSAGE) != SWITCH_STATUS_SUCCESS) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
+                       return SWITCH_STATUS_FALSE;
+               }
+
+               if (switch_event_reserve_subclass(MY_EVENT_INCOMING_RAW) != SWITCH_STATUS_SUCCESS) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
+                       return SWITCH_STATUS_FALSE;
+               }
+
                /* indicate that the module should continue to be loaded */
                return SWITCH_STATUS_SUCCESS;
-       } else
-               return SWITCH_STATUS_FALSE;
+       }
+       return SWITCH_STATUS_FALSE;
 }
 
 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skypopen_shutdown)
index 7eca73dddaf5ddfd13cb280cac1688e6987fe0c9..ddeebdfae7e04a269b17835d9d5f16ba8008b453 100644 (file)
@@ -132,6 +132,7 @@ typedef enum {
 #define                SKYPOPEN_STATE_SELECTED                         9
 #define        SKYPOPEN_STATE_HANGUP_REQUESTED         10
 #define                SKYPOPEN_STATE_PREANSWER                                11
+#define                SKYPOPEN_STATE_DEAD                             99
 /*********************************/
 /* call flow from the device */
 #define        CALLFLOW_CALL_IDLE                                      0
index bab9d54422a97dd6870ca3000e82f6a3ef2201be..44be83544cf30209e223bb2011035e87d9e473b6 100644 (file)
@@ -1514,6 +1514,30 @@ int xio_error_handler(Display * dpy)
 
        return 0;
 }
+int xio_error_handler2(Display * dpy, XErrorEvent * err)
+{
+       private_t *tech_pvt = NULL;
+       struct SkypopenHandles *handle;
+       global_x_error = err->error_code;
+
+       ERRORA("Received error code %d from X Server\n\n", SKYPOPEN_P_LOG, global_x_error);
+       ERRORA("Display error for %d, %s\n", SKYPOPEN_P_LOG, skypopen_list_size(&global_handles_list), dpy->display_name);
+
+       handle = skypopen_list_remove_by_value(&global_handles_list, dpy);
+       if (handle != NULL) {
+#ifdef XIO_ERROR_BY_SETJMP
+               siglongjmp(handle->ioerror_context, 1);
+#endif
+#ifdef XIO_ERROR_BY_UCONTEXT
+               setcontext(&handle->ioerror_context);
+#endif
+       }
+
+       ERRORA("Fatal display error for %p, %s - failed to siglongjmp\n", SKYPOPEN_P_LOG, (void *) handle, dpy->display_name);
+
+       return 0;
+}
+
 
 int X11_errors_handler(Display * dpy, XErrorEvent * err)
 {
@@ -1685,25 +1709,38 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
        // CLOUDTREE (Thomas Hazel)
 #ifndef WIN32
        {
+               char interfacename[256];
+
                skypopen_list_add(&global_handles_list, SkypopenHandles);
+               sprintf(interfacename, "#%s", tech_pvt->name);
 
 #ifdef XIO_ERROR_BY_SETJMP
                if (sigsetjmp(SkypopenHandles->ioerror_context, 1) != 0) {
                        switch_core_session_t *session = NULL;
+                       tech_pvt->interface_state = SKYPOPEN_STATE_DEAD;
                        ERRORA("Fatal display error for %s - successed to jump\n", SKYPOPEN_P_LOG, tech_pvt->X11_display);
 
                        session = switch_core_session_locate(tech_pvt->session_uuid_str);
                        if (session) {
                                switch_channel_t *channel = switch_core_session_get_channel(session);
-                               WARNINGA("Closing session %s\n", SKYPOPEN_P_LOG, tech_pvt->skype_user);
-                               switch_channel_hangup(channel, SWITCH_CAUSE_CRASH);
+
+
+                               switch_mutex_lock(tech_pvt->flag_mutex);
+                               switch_clear_flag(tech_pvt, TFLAG_IO);
+                               switch_clear_flag(tech_pvt, TFLAG_VOICE);
+                               if (switch_test_flag(tech_pvt, TFLAG_PROGRESS)) {
+                                       switch_clear_flag(tech_pvt, TFLAG_PROGRESS);
+                               }
+                               switch_mutex_unlock(tech_pvt->flag_mutex);
+
+
                                switch_core_session_rwunlock(session);
+                               WARNINGA("Closing session for %s\n", SKYPOPEN_P_LOG, interfacename);
+                               switch_channel_hangup(channel, SWITCH_CAUSE_CRASH);
                        }
 
-                       WARNINGA("Removing skype user %s\n", SKYPOPEN_P_LOG, tech_pvt->skype_user);
-                       tech_pvt->skypopen_api_thread = NULL;
-                       remove_interface(tech_pvt->skype_user, TRUE);
-                       XCloseDisplay(disp);
+                       WARNINGA("Removing skype interface %s\n", SKYPOPEN_P_LOG, interfacename);
+                       remove_interface(interfacename, TRUE);
                        return NULL;
                }
 #endif
@@ -1712,20 +1749,34 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
 
                if (skypopen_list_find(&global_handles_list, SkypopenHandles) == NULL) {
                        switch_core_session_t *session = NULL;
+                       tech_pvt->interface_state = SKYPOPEN_STATE_DEAD;
                        ERRORA("Fatal display error for %s - successed to jump\n", SKYPOPEN_P_LOG, tech_pvt->X11_display);
 
                        session = switch_core_session_locate(tech_pvt->session_uuid_str);
                        if (session) {
                                switch_channel_t *channel = switch_core_session_get_channel(session);
-                               WARNINGA("Closing session %s\n", SKYPOPEN_P_LOG, tech_pvt->skype_user);
-                               switch_channel_hangup(channel, SWITCH_CAUSE_CRASH);
+
+
+                               switch_mutex_lock(tech_pvt->flag_mutex);
+                               switch_clear_flag(tech_pvt, TFLAG_IO);
+                               switch_clear_flag(tech_pvt, TFLAG_VOICE);
+                               if (switch_test_flag(tech_pvt, TFLAG_PROGRESS)) {
+                                       switch_clear_flag(tech_pvt, TFLAG_PROGRESS);
+                               }
+                               switch_mutex_unlock(tech_pvt->flag_mutex);
+
+
                                switch_core_session_rwunlock(session);
+                               WARNINGA("Closing session for %s\n", SKYPOPEN_P_LOG, interfacename);
+                               switch_channel_hangup(channel, SWITCH_CAUSE_CRASH);
+
+                               //skypopen_sleep(500000);
                        }
 
-                       WARNINGA("Removing skype user %s\n", SKYPOPEN_P_LOG, tech_pvt->skype_user);
-                       tech_pvt->skypopen_api_thread = NULL;
-                       remove_interface(tech_pvt->skype_user, TRUE);
-                       XCloseDisplay(disp);
+                       WARNINGA("Removing skype interface %s\n", SKYPOPEN_P_LOG, interfacename);
+                       //tech_pvt->skypopen_api_thread = NULL;
+                       remove_interface(interfacename, TRUE);
+                       //XCloseDisplay(disp);
                        return NULL;
                }
 #endif