From 182da3c128879026e25b10f1f0e26eaf220053d0 Mon Sep 17 00:00:00 2001 From: Giovanni Maruzzelli Date: Thu, 28 Oct 2010 13:20:17 -0500 Subject: [PATCH] skypopen: fixed management of skype clients crash --- src/mod/endpoints/mod_skypopen/mod_skypopen.c | 78 +++++++++++-------- src/mod/endpoints/mod_skypopen/skypopen.h | 1 + .../mod_skypopen/skypopen_protocol.c | 75 +++++++++++++++--- 3 files changed, 110 insertions(+), 44 deletions(-) diff --git a/src/mod/endpoints/mod_skypopen/mod_skypopen.c b/src/mod/endpoints/mod_skypopen/mod_skypopen.c index f2f5c2ac39..357332d1f4 100644 --- a/src/mod/endpoints/mod_skypopen/mod_skypopen.c +++ b/src/mod/endpoints/mod_skypopen/mod_skypopen.c @@ -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) diff --git a/src/mod/endpoints/mod_skypopen/skypopen.h b/src/mod/endpoints/mod_skypopen/skypopen.h index 7eca73ddda..ddeebdfae7 100644 --- a/src/mod/endpoints/mod_skypopen/skypopen.h +++ b/src/mod/endpoints/mod_skypopen/skypopen.h @@ -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 diff --git a/src/mod/endpoints/mod_skypopen/skypopen_protocol.c b/src/mod/endpoints/mod_skypopen/skypopen_protocol.c index bab9d54422..44be83544c 100644 --- a/src/mod/endpoints/mod_skypopen/skypopen_protocol.c +++ b/src/mod/endpoints/mod_skypopen/skypopen_protocol.c @@ -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