diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 8e358d0376..5eb269350f 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -599,6 +599,9 @@ SWITCH_DECLARE(void) switch_core_set_variable(_In_z_ const char *varname, _In_op */ SWITCH_DECLARE(void) switch_core_session_hupall(_In_ switch_call_cause_t cause); +SWITCH_DECLARE(void) switch_core_session_hupall_matching_var(_In_ const char *var_name, _In_ const char *var_val, _In_ switch_call_cause_t cause); +SWITCH_DECLARE(void) switch_core_session_hupall_endpoint(const switch_endpoint_interface_t *endpoint_interface, switch_call_cause_t cause); + /*! \brief Send a message to another session using it's uuid \param uuid_str the unique id of the session you want to send a message to diff --git a/src/include/switch_event.h b/src/include/switch_event.h index 0a5e7da2a6..bb8287d611 100644 --- a/src/include/switch_event.h +++ b/src/include/switch_event.h @@ -70,14 +70,6 @@ SWITCH_BEGIN_EXTERN_C struct switch_event_header *next; }; -/*! \brief A registered custom event subclass */ -struct switch_event_subclass { - /*! the owner of the subclass */ - char *owner; - /*! the subclass name */ - char *name; -}; - /*! \brief Representation of an event */ struct switch_event { /*! the event id (descriptor) */ @@ -87,7 +79,7 @@ struct switch_event { /*! the owner of the event */ char *owner; /*! the subclass of the event */ - switch_event_subclass_t *subclass; + char *subclass_name; /*! the event headers */ switch_event_header_t *headers; /*! the event headers tail pointer */ @@ -103,20 +95,7 @@ struct switch_event { struct switch_event *next; }; -/*! \brief A node to store binded events */ -struct switch_event_node { - /*! the id of the node */ - char *id; - /*! the event id enumeration to bind to */ - switch_event_types_t event_id; - /*! the event subclass to bind to for custom events */ - switch_event_subclass_t *subclass; - /*! a callback function to execute when the event is triggered */ - switch_event_callback_t callback; - /*! private data */ - void *user_data; - struct switch_event_node *next; -}; +struct switch_event_node; #define SWITCH_EVENT_SUBCLASS_ANY NULL @@ -228,6 +207,25 @@ SWITCH_DECLARE(switch_status_t) switch_event_fire_detailed(const char *file, con SWITCH_DECLARE(switch_status_t) switch_event_bind(const char *id, switch_event_types_t event, const char *subclass_name, switch_event_callback_t callback, void *user_data); +/*! + \brief Bind an event callback to a specific event + \param id an identifier token of the binder + \param event the event enumeration to bind to + \param subclass_name the event subclass to bind to in the case if SWITCH_EVENT_CUSTOM + \param callback the callback functon to bind + \param user_data optional user specific data to pass whenever the callback is invoked + \param node bind handle to later remove the binding. + \return SWITCH_STATUS_SUCCESS if the event was binded +*/ +SWITCH_DECLARE(switch_status_t) switch_event_bind_removable(const char *id, switch_event_types_t event, const char *subclass_name, + switch_event_callback_t callback, void *user_data, switch_event_node_t **node); +/*! + \brief Unbind a bound event consumer + \param node node to unbind + \return SWITCH_STATUS_SUCCESS if the consumer was unbinded +*/ +SWITCH_DECLARE(switch_status_t) switch_event_unbind(switch_event_node_t **node); + /*! \brief Render the name of an event id enumeration \param event the event id to render the name of @@ -253,6 +251,8 @@ SWITCH_DECLARE(switch_status_t) switch_name_event(const char *name, switch_event */ SWITCH_DECLARE(switch_status_t) switch_event_reserve_subclass_detailed(const char *owner, const char *subclass_name); +SWITCH_DECLARE(switch_status_t) switch_event_free_subclass_detailed(const char *owner, const char *subclass_name); + /*! \brief Render a string representation of an event sutable for printing or network transport \param event the event to render @@ -311,6 +311,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_pres_in_detailed(_In_z_ char \note the body supplied by this function will supersede an existing body the event may have */ #define switch_event_reserve_subclass(subclass_name) switch_event_reserve_subclass_detailed(__FILE__, subclass_name) +#define switch_event_free_subclass(subclass_name) switch_event_free_subclass_detailed(__FILE__, subclass_name) /*! \brief Create a new event assuming it will not be custom event and therefore hiding the unused parameters diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 784dd205b7..d690607b52 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -195,6 +195,8 @@ struct switch_endpoint_interface { /*! private information */ void *private_info; + switch_thread_rwlock_t *rwlock; + /* to facilitate linking */ struct switch_endpoint_interface *next; }; @@ -245,6 +247,7 @@ struct switch_timer_interface { switch_status_t (*timer_check) (switch_timer_t *, switch_bool_t); /*! function to deallocate the timer */ switch_status_t (*timer_destroy) (switch_timer_t *); + switch_thread_rwlock_t *rwlock; struct switch_timer_interface *next; }; @@ -254,6 +257,7 @@ struct switch_dialplan_interface { const char *interface_name; /*! the function to read an extension and set a channels dialpan */ switch_dialplan_hunt_function_t hunt_function; + switch_thread_rwlock_t *rwlock; struct switch_dialplan_interface *next; }; @@ -277,6 +281,7 @@ struct switch_file_interface { switch_status_t (*file_get_string) (switch_file_handle_t *fh, switch_audio_col_t col, const char **string); /*! list of supported file extensions */ char **extens; + switch_thread_rwlock_t *rwlock; struct switch_file_interface *next; }; @@ -353,6 +358,7 @@ struct switch_asr_interface { switch_status_t (*asr_check_results) (switch_asr_handle_t *ah, switch_asr_flag_t *flags); /*! function to read results from the ASR */ switch_status_t (*asr_get_results) (switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags); + switch_thread_rwlock_t *rwlock; struct switch_asr_interface *next; }; @@ -393,7 +399,7 @@ struct switch_speech_interface { void (*speech_text_param_tts) (switch_speech_handle_t *sh, char *param, const char *val); void (*speech_numeric_param_tts) (switch_speech_handle_t *sh, char *param, int val); void (*speech_float_param_tts) (switch_speech_handle_t *sh, char *param, double val); - + switch_thread_rwlock_t *rwlock; struct switch_speech_interface *next; }; @@ -426,6 +432,7 @@ struct switch_say_interface { const char *interface_name; /*! function to pass down to the module */ switch_say_callback_t say_function; + switch_thread_rwlock_t *rwlock; struct switch_say_interface *next; }; @@ -435,6 +442,7 @@ struct switch_chat_interface { const char *interface_name; /*! function to open the directory interface */ switch_status_t (*chat_send) (char *proto, char *from, char *to, char *subject, char *body, char *hint); + switch_thread_rwlock_t *rwlock; struct switch_chat_interface *next; }; @@ -444,6 +452,7 @@ struct switch_management_interface { const char *relative_oid; /*! function to open the directory interface */ switch_status_t (*management_function) (char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen); + switch_thread_rwlock_t *rwlock; struct switch_management_interface *next; }; @@ -461,7 +470,7 @@ struct switch_directory_interface { switch_status_t (*directory_next) (switch_directory_handle_t *dh); /*! function to advance to the next name/value pair in the current record */ switch_status_t (*directory_next_pair) (switch_directory_handle_t *dh, char **var, char **val); - + switch_thread_rwlock_t *rwlock; struct switch_directory_interface *next; }; @@ -586,6 +595,7 @@ struct switch_codec_interface { /*! a list of codec implementations related to the codec */ switch_codec_implementation_t *implementations; uint32_t codec_id; + switch_thread_rwlock_t *rwlock; struct switch_codec_interface *next; }; @@ -603,6 +613,7 @@ struct switch_application_interface { const char *syntax; /*! flags to control behaviour */ uint32_t flags; + switch_thread_rwlock_t *rwlock; struct switch_application_interface *next; }; @@ -616,6 +627,7 @@ struct switch_api_interface { switch_api_function_t function; /*! an example of the api syntax */ const char *syntax; + switch_thread_rwlock_t *rwlock; struct switch_api_interface *next; }; diff --git a/src/include/switch_types.h b/src/include/switch_types.h index a5ad3e4c73..b7b9fce031 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -100,6 +100,7 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_PATH_SEPARATOR "/" #endif #define SWITCH_URL_SEPARATOR "://" +#define SWITCH_CURRENT_APPLICATION_VARIABLE "current_application" #define SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE "proto_specific_hangup_cause" #define SWITCH_CHANNEL_EXECUTE_ON_ANSWER_VARIABLE "execute_on_answer" #define SWITCH_CHANNEL_EXECUTE_ON_RING_VARIABLE "execute_on_ring" diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index 83f837a314..90796d8d2b 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -242,6 +242,7 @@ static struct { switch_mutex_t *mutex; switch_memory_pool_t *pool; int running; + switch_event_node_t *node; } globals; @@ -1182,7 +1183,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_fifo_load) } /* Subscribe to presence request events */ - if (switch_event_bind(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + if (switch_event_bind_removable(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, + pres_event_handler, NULL, &globals.node) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't subscribe to presence request events!\n"); return SWITCH_STATUS_GENERR; } @@ -1215,7 +1217,10 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fifo_shutdown) fifo_node_t *node; switch_memory_pool_t *pool = globals.pool; switch_mutex_t *mutex = globals.mutex; - + + switch_event_unbind(&globals.node); + switch_event_free_subclass(FIFO_EVENT); + switch_mutex_lock(mutex); globals.running = 0; @@ -1229,6 +1234,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fifo_shutdown) free(pop); } } + switch_core_hash_destroy(&node->caller_hash); switch_core_hash_destroy(&node->consumer_hash); } diff --git a/src/mod/event_handlers/mod_event_multicast/mod_event_multicast.c b/src/mod/event_handlers/mod_event_multicast/mod_event_multicast.c index 342b9168f3..cedb6af7d3 100644 --- a/src/mod/event_handlers/mod_event_multicast/mod_event_multicast.c +++ b/src/mod/event_handlers/mod_event_multicast/mod_event_multicast.c @@ -147,7 +147,7 @@ static void event_handler(switch_event_t *event) return; } - if (event->subclass && !strcmp(event->subclass->name, MULTICAST_EVENT)) { + if (event->subclass_name && !strcmp(event->subclass_name, MULTICAST_EVENT)) { /* ignore our own events to avoid ping pong */ return; } @@ -155,7 +155,7 @@ static void event_handler(switch_event_t *event) if (globals.event_list[(uint8_t) SWITCH_EVENT_ALL]) { send = 1; } else if ((globals.event_list[(uint8_t) event->event_id])) { - if (event->event_id != SWITCH_EVENT_CUSTOM || (event->subclass && switch_core_hash_find(globals.event_hash, event->subclass->name))) { + if (event->event_id != SWITCH_EVENT_CUSTOM || (event->subclass_name && switch_core_hash_find(globals.event_hash, event->subclass_name))) { send = 1; } } diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index dd9e4654b1..d210e901ad 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -162,7 +162,7 @@ static void event_handler(switch_event_t *event) if (l->event_list[SWITCH_EVENT_ALL]) { send = 1; } else if ((l->event_list[event->event_id])) { - if (event->event_id != SWITCH_EVENT_CUSTOM || !event->subclass || (switch_core_hash_find(l->event_hash, event->subclass->name))) { + if (event->event_id != SWITCH_EVENT_CUSTOM || !event->subclass_name || (switch_core_hash_find(l->event_hash, event->subclass_name))) { send = 1; } } diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 1925bb15cf..0c2719dc3e 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -72,6 +72,50 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(const char *u return session; } + +SWITCH_DECLARE(void) switch_core_session_hupall_matching_var(const char *var_name, const char *var_val, switch_call_cause_t cause) +{ + switch_hash_index_t *hi; + void *val; + switch_core_session_t *session; + + switch_mutex_lock(runtime.throttle_mutex); + for (hi = switch_hash_first(NULL, session_manager.session_table); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, NULL, NULL, &val); + if (val) { + const char *this_val; + session = (switch_core_session_t *) val; + switch_core_session_read_lock(session); + if ((this_val = switch_channel_get_variable(session->channel, var_name)) && (!strcmp(this_val, var_val))) { + switch_channel_hangup(switch_core_session_get_channel(session), cause); + } + switch_core_session_rwunlock(session); + } + } + switch_mutex_unlock(runtime.throttle_mutex); +} + +SWITCH_DECLARE(void) switch_core_session_hupall_endpoint(const switch_endpoint_interface_t *endpoint_interface, switch_call_cause_t cause) +{ + switch_hash_index_t *hi; + void *val; + switch_core_session_t *session; + + switch_mutex_lock(runtime.throttle_mutex); + for (hi = switch_hash_first(NULL, session_manager.session_table); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, NULL, NULL, &val); + if (val) { + session = (switch_core_session_t *) val; + switch_core_session_read_lock(session); + if (session->endpoint_interface == endpoint_interface) { + switch_channel_hangup(switch_core_session_get_channel(session), cause); + } + switch_core_session_rwunlock(session); + } + } + switch_mutex_unlock(runtime.throttle_mutex); +} + SWITCH_DECLARE(void) switch_core_session_hupall(switch_call_cause_t cause) { switch_hash_index_t *hi; @@ -686,6 +730,8 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t * { switch_memory_pool_t *pool; switch_event_t *event; + const switch_endpoint_interface_t *endpoint_interface = (*session)->endpoint_interface; + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_NOTICE, "Close Channel %s [%s]\n", switch_channel_get_name((*session)->channel), switch_channel_state_name(switch_channel_get_state((*session)->channel))); @@ -720,6 +766,8 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t * *session = NULL; switch_core_destroy_memory_pool(&pool); + switch_thread_rwlock_unlock(endpoint_interface->rwlock); + } static void *SWITCH_THREAD_FUNC switch_core_session_thread(switch_thread_t *thread, void *obj) @@ -827,6 +875,8 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request(const switch return NULL; } + switch_thread_rwlock_rdlock(endpoint_interface->rwlock); + if (pool && *pool) { usepool = *pool; *pool = NULL; @@ -1047,8 +1097,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * switch_assert(application_interface->application_function); - application_interface->application_function(session, arg); + switch_channel_set_variable(session->channel, SWITCH_CURRENT_APPLICATION_VARIABLE, application_interface->interface_name); + switch_thread_rwlock_rdlock(application_interface->rwlock); + application_interface->application_function(session, arg); + switch_thread_rwlock_unlock(application_interface->rwlock); + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(session->channel, event); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "%s", application_interface->interface_name); diff --git a/src/switch_event.c b/src/switch_event.c index b6b5731a52..1656105820 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -38,11 +38,35 @@ #define DISPATCH_QUEUE_LEN 5000 //#define DEBUG_DISPATCH_QUEUES +/*! \brief A node to store binded events */ +struct switch_event_node { + /*! the id of the node */ + char *id; + /*! the event id enumeration to bind to */ + switch_event_types_t event_id; + /*! the event subclass to bind to for custom events */ + switch_event_subclass_t *subclass; + /*! a callback function to execute when the event is triggered */ + switch_event_callback_t callback; + /*! private data */ + void *user_data; + struct switch_event_node *next; +}; + +/*! \brief A registered custom event subclass */ +struct switch_event_subclass { + /*! the owner of the subclass */ + char *owner; + /*! the subclass name */ + char *name; +}; + static int SOFT_MAX_DISPATCH = 0; static char hostname[128] = ""; static char guess_ip_v4[80] = ""; static char guess_ip_v6[80] = ""; static switch_event_node_t *EVENT_NODES[SWITCH_EVENT_ALL + 1] = { NULL }; +static switch_thread_rwlock_t *RWLOCK = NULL; static switch_mutex_t *BLOCK = NULL; static switch_mutex_t *POOL_LOCK = NULL; static switch_memory_pool_t *RUNTIME_POOL = NULL; @@ -148,7 +172,7 @@ static int switch_events_match(switch_event_t *event, switch_event_node_t *node) if (match || event->event_id == node->event_id) { - if (event->subclass && node->subclass) { + if (event->subclass_name && node->subclass) { if (!strncasecmp(node->subclass->name, "file:", 5)) { char *file_header; if ((file_header = switch_event_get_header(event, "file")) != 0) { @@ -159,10 +183,10 @@ static int switch_events_match(switch_event_t *event, switch_event_node_t *node) if ((func_header = switch_event_get_header(event, "function")) != 0) { match = strstr(node->subclass->name + 5, func_header) ? 1 : 0; } - } else { - match = strstr(event->subclass->name, node->subclass->name) ? 1 : 0; + } else if (event->subclass_name && node->subclass->name) { + match = strstr(event->subclass_name, node->subclass->name) ? 1 : 0; } - } else if ((event->subclass && !node->subclass) || (!event->subclass && !node->subclass)) { + } else if ((event->subclass_name && !node->subclass) || (!event->subclass_name && !node->subclass)) { match = 1; } else { match = 0; @@ -276,6 +300,7 @@ SWITCH_DECLARE(void) switch_event_deliver(switch_event_t **event) switch_event_types_t e; switch_event_node_t *node; + switch_thread_rwlock_rdlock(RWLOCK); for (e = (*event)->event_id;; e = SWITCH_EVENT_ALL) { for (node = EVENT_NODES[e]; node; node = node->next) { if (switch_events_match(*event, node)) { @@ -288,6 +313,7 @@ SWITCH_DECLARE(void) switch_event_deliver(switch_event_t **event) break; } } + switch_thread_rwlock_unlock(RWLOCK); switch_event_destroy(event); } @@ -321,6 +347,30 @@ SWITCH_DECLARE(switch_status_t) switch_name_event(const char *name, switch_event return SWITCH_STATUS_FALSE; } +SWITCH_DECLARE(switch_status_t) switch_event_free_subclass_detailed(const char *owner, const char *subclass_name) +{ + switch_event_subclass_t *subclass; + switch_status_t status = SWITCH_STATUS_FALSE; + + switch_assert(RUNTIME_POOL != NULL); + switch_assert(CUSTOM_HASH != NULL); + + if ((subclass = switch_core_hash_find(CUSTOM_HASH, subclass_name))) { + if (!strcmp(owner, subclass->owner)) { + switch_thread_rwlock_wrlock(RWLOCK); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Subclass reservation deleted for %s:%s\n", owner, subclass_name); + switch_core_hash_delete(CUSTOM_HASH, subclass_name); + FREE(subclass->owner); + FREE(subclass->name); + FREE(subclass); + status = SWITCH_STATUS_SUCCESS; + switch_thread_rwlock_unlock(RWLOCK); + } + } + + return status; +} + SWITCH_DECLARE(switch_status_t) switch_event_reserve_subclass_detailed(const char *owner, const char *subclass_name) { switch_event_subclass_t *subclass; @@ -332,13 +382,11 @@ SWITCH_DECLARE(switch_status_t) switch_event_reserve_subclass_detailed(const cha return SWITCH_STATUS_INUSE; } - if ((subclass = switch_core_alloc(RUNTIME_POOL, sizeof(*subclass))) == 0) { - return SWITCH_STATUS_MEMERR; - } - - subclass->owner = switch_core_strdup(RUNTIME_POOL, owner); - subclass->name = switch_core_strdup(RUNTIME_POOL, subclass_name); + switch_zmalloc(subclass, sizeof(*subclass)); + subclass->owner = DUP(owner); + subclass->name = DUP(subclass_name); + switch_core_hash_insert(CUSTOM_HASH, subclass->name, subclass); return SWITCH_STATUS_SUCCESS; @@ -448,6 +496,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_init(switch_memory_pool_t *pool) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activate Eventing Engine.\n"); + switch_thread_rwlock_create(&RWLOCK, RUNTIME_POOL); switch_mutex_init(&BLOCK, SWITCH_MUTEX_NESTED, RUNTIME_POOL); switch_mutex_init(&POOL_LOCK, SWITCH_MUTEX_NESTED, RUNTIME_POOL); switch_mutex_init(&EVENT_QUEUE_MUTEX, SWITCH_MUTEX_NESTED, RUNTIME_POOL); @@ -492,10 +541,15 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_subclass(switch_event_t **ev (*event)->event_id = event_id; if (subclass_name) { - if (!((*event)->subclass = switch_core_hash_find(CUSTOM_HASH, subclass_name))) { + switch_event_subclass_t *subclass; + + if (!(subclass = switch_core_hash_find(CUSTOM_HASH, subclass_name))) { switch_event_reserve_subclass((char *) subclass_name); - (*event)->subclass = switch_core_hash_find(CUSTOM_HASH, subclass_name); + subclass = switch_core_hash_find(CUSTOM_HASH, subclass_name); } + + (*event)->subclass_name = DUP(subclass_name); + switch_event_add_header_string(*event, SWITCH_STACK_BOTTOM, "Event-Subclass", subclass_name); } @@ -662,6 +716,7 @@ SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event) } } FREE(ep->body); + FREE(ep->subclass_name); memset(ep, 0, sizeof(*ep)); if (switch_queue_trypush(EVENT_RECYCLE_QUEUE, ep) != SWITCH_STATUS_SUCCESS) { FREE(ep); @@ -674,11 +729,13 @@ SWITCH_DECLARE(switch_status_t) switch_event_dup(switch_event_t **event, switch_ { switch_event_header_t *header, *hp, *hp2, *last = NULL; - if (switch_event_create_subclass(event, todup->event_id, todup->subclass ? todup->subclass->name : NULL) != SWITCH_STATUS_SUCCESS) { + if (switch_event_create_subclass(event, todup->event_id, todup->subclass_name) != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_GENERR; } - (*event)->subclass = todup->subclass; + if (todup->subclass_name) { + (*event)->subclass_name = DUP(todup->subclass_name); + } (*event)->event_user_data = todup->event_user_data; (*event)->bind_user_data = todup->bind_user_data; @@ -942,9 +999,8 @@ SWITCH_DECLARE(switch_status_t) switch_event_fire_detailed(const char *file, con switch_event_add_header_string(*event, SWITCH_STACK_BOTTOM, "Event-Calling-Function", func); switch_event_add_header(*event, SWITCH_STACK_BOTTOM, "Event-Calling-Line-Number", "%d", line); - if ((*event)->subclass) { - switch_event_add_header_string(*event, SWITCH_STACK_BOTTOM, "Event-Subclass", (*event)->subclass->name); - switch_event_add_header_string(*event, SWITCH_STACK_BOTTOM, "Event-Subclass-Owner", (*event)->subclass->owner); + if ((*event)->subclass_name) { + switch_event_add_header_string(*event, SWITCH_STACK_BOTTOM, "Event-Subclass", (*event)->subclass_name); } if (user_data) { @@ -958,8 +1014,8 @@ SWITCH_DECLARE(switch_status_t) switch_event_fire_detailed(const char *file, con return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(switch_status_t) switch_event_bind(const char *id, switch_event_types_t event, const char *subclass_name, switch_event_callback_t callback, - void *user_data) +SWITCH_DECLARE(switch_status_t) switch_event_bind_removable(const char *id, switch_event_types_t event, const char *subclass_name, + switch_event_callback_t callback, void *user_data, switch_event_node_t **node) { switch_event_node_t *event_node; switch_event_subclass_t *subclass = NULL; @@ -967,21 +1023,27 @@ SWITCH_DECLARE(switch_status_t) switch_event_bind(const char *id, switch_event_t switch_assert(BLOCK != NULL); switch_assert(RUNTIME_POOL != NULL); - if (subclass_name) { - if ((subclass = switch_core_hash_find(CUSTOM_HASH, subclass_name)) == 0) { - if ((subclass = switch_core_alloc(RUNTIME_POOL, sizeof(*subclass))) == 0) { - return SWITCH_STATUS_MEMERR; - } else { - subclass->owner = switch_core_strdup(RUNTIME_POOL, id); - subclass->name = switch_core_strdup(RUNTIME_POOL, subclass_name); - } - } + if (node) { + *node = NULL; } - if (event <= SWITCH_EVENT_ALL && (event_node = switch_core_alloc(RUNTIME_POOL, sizeof(switch_event_node_t))) != 0) { + if (subclass_name) { + if (!(subclass = switch_core_hash_find(CUSTOM_HASH, subclass_name))) { + switch_event_reserve_subclass_detailed(id, subclass_name); + subclass = switch_core_hash_find(CUSTOM_HASH, subclass_name); + } + if (!subclass) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not reserve subclass. '%s'\n", subclass_name); + return SWITCH_STATUS_FALSE; + } + } + + if (event <= SWITCH_EVENT_ALL) { + switch_zmalloc(event_node, sizeof(*event_node)); switch_mutex_lock(BLOCK); + switch_thread_rwlock_wrlock(RWLOCK); /* ----------------------------------------------- */ - event_node->id = switch_core_strdup(RUNTIME_POOL, id); + event_node->id = DUP(id); event_node->event_id = event; event_node->subclass = subclass; event_node->callback = callback; @@ -992,14 +1054,62 @@ SWITCH_DECLARE(switch_status_t) switch_event_bind(const char *id, switch_event_t } EVENT_NODES[event] = event_node; + switch_thread_rwlock_unlock(RWLOCK); switch_mutex_unlock(BLOCK); /* ----------------------------------------------- */ + + if (node) { + *node = event_node; + } + return SWITCH_STATUS_SUCCESS; } return SWITCH_STATUS_MEMERR; } + +SWITCH_DECLARE(switch_status_t) switch_event_bind(const char *id, switch_event_types_t event, const char *subclass_name, + switch_event_callback_t callback, void *user_data) +{ + return switch_event_bind_removable(id, event, subclass_name, callback, user_data, NULL); +} + + +SWITCH_DECLARE(switch_status_t) switch_event_unbind(switch_event_node_t **node) +{ + switch_event_node_t *n, *np, *lnp = NULL; + switch_status_t status = SWITCH_STATUS_FALSE; + + n = *node; + + switch_thread_rwlock_wrlock(RWLOCK); + switch_mutex_lock(BLOCK); + /* ----------------------------------------------- */ + for (np = EVENT_NODES[n->event_id]; np; np = np->next) { + if (np == n) { + if (lnp) { + lnp->next = n->next; + } else { + EVENT_NODES[n->event_id] = n->next; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Event Binding deleted for %s:%s\n", n->id, switch_event_name(n->event_id)); + n->subclass = NULL; + FREE(n->id); + FREE(n); + *node = NULL; + status = SWITCH_STATUS_SUCCESS; + break; + } + lnp = np; + } + switch_mutex_unlock(BLOCK); + switch_thread_rwlock_unlock(RWLOCK); + /* ----------------------------------------------- */ + + return status; +} + SWITCH_DECLARE(switch_status_t) switch_event_create_pres_in_detailed(char *file, char *func, int line, const char *proto, const char *login, const char *from, const char *from_domain, diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index 2cae5c1e0e..d6ac074e02 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -412,8 +412,16 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t if (old_module->module_interface->endpoint_interface) { const switch_endpoint_interface_t *ptr; + for (ptr = old_module->module_interface->endpoint_interface; ptr; ptr = ptr->next) { if (ptr->interface_name) { + + switch_core_session_hupall_endpoint(ptr, SWITCH_CAUSE_SYSTEM_SHUTDOWN); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock interface '%s' to wait for existing references.\n", ptr->interface_name); + switch_thread_rwlock_wrlock(ptr->rwlock); + switch_thread_rwlock_unlock(ptr->rwlock); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Deleting Endpoint '%s'\n", ptr->interface_name); switch_core_hash_delete(loadable_modules.endpoint_hash, ptr->interface_name); } @@ -486,10 +494,14 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t if (old_module->module_interface->application_interface) { const switch_application_interface_t *ptr; - for (ptr = old_module->module_interface->application_interface; ptr; ptr = ptr->next) { if (ptr->interface_name) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Deleting Application '%s'\n", ptr->interface_name); + switch_core_session_hupall_matching_var(SWITCH_CURRENT_APPLICATION_VARIABLE, ptr->interface_name, SWITCH_CAUSE_SYSTEM_SHUTDOWN); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock interface '%s' to wait for existing references.\n", ptr->interface_name); + switch_thread_rwlock_wrlock(ptr->rwlock); + switch_thread_rwlock_unlock(ptr->rwlock); + if (switch_event_create(&event, SWITCH_EVENT_MODULE_UNLOAD) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "type", "%s", "application"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "name", "%s", ptr->interface_name); @@ -508,6 +520,11 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t for (ptr = old_module->module_interface->api_interface; ptr; ptr = ptr->next) { if (ptr->interface_name) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Deleting API Function '%s'\n", ptr->interface_name); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock interface '%s' to wait for existing references.\n", ptr->interface_name); + switch_thread_rwlock_wrlock(ptr->rwlock); + switch_thread_rwlock_unlock(ptr->rwlock); + if (switch_event_create(&event, SWITCH_EVENT_MODULE_UNLOAD) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "type", "%s", "api"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "name", "%s", ptr->interface_name); @@ -1357,9 +1374,11 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char * if (cmd && (api = switch_loadable_module_get_api_interface(cmd)) != 0) { + switch_thread_rwlock_rdlock(api->rwlock); if ((status = api->function(arg, session, stream)) != SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "COMMAND RETURNED ERROR!\n"); } + switch_thread_rwlock_unlock(api->rwlock); } else { status = SWITCH_STATUS_FALSE; stream->write_function(stream, "INVALID COMMAND!\n"); @@ -1398,7 +1417,7 @@ SWITCH_DECLARE(switch_loadable_module_interface_t *) switch_loadable_module_crea } else { \ mod->_TYPE_##_interface = i; \ } \ - \ + switch_thread_rwlock_create(&i->rwlock, mod->pool); \ return i; }