Index: res/res_pjsip/config_auth.c =================================================================== --- res/res_pjsip/config_auth.c (revision 427203) +++ res/res_pjsip/config_auth.c (working copy) @@ -312,7 +312,7 @@ ast_sorcery_object_field_register_custom(sorcery, SIP_SORCERY_AUTH_TYPE, "auth_type", "userpass", auth_type_handler, auth_type_to_str, NULL, 0, 0); - ast_sip_register_endpoint_formatter(&endpoint_auth_formatter); + pjsip_register_endpoint_formatter(&endpoint_auth_formatter); cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); if (!cli_formatter) { @@ -337,6 +337,7 @@ { ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sip_unregister_cli_formatter(cli_formatter); + pjsip_unregister_endpoint_formatter(&endpoint_auth_formatter); return 0; } Index: res/res_pjsip/config_transport.c =================================================================== --- res/res_pjsip/config_transport.c (revision 427203) +++ res/res_pjsip/config_transport.c (working copy) @@ -760,7 +760,7 @@ ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos)); ast_sorcery_object_field_register(sorcery, "transport", "websocket_write_timeout", AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, write_timeout), 1, INT_MAX); - ast_sip_register_endpoint_formatter(&endpoint_transport_formatter); + pjsip_register_endpoint_formatter(&endpoint_transport_formatter); cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); if (!cli_formatter) { @@ -786,5 +786,7 @@ ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sip_unregister_cli_formatter(cli_formatter); + pjsip_unregister_endpoint_formatter(&endpoint_transport_formatter); + return 0; } Index: res/res_pjsip/include/res_pjsip_private.h =================================================================== --- res/res_pjsip/include/res_pjsip_private.h (revision 427203) +++ res/res_pjsip/include/res_pjsip_private.h (working copy) @@ -112,4 +112,24 @@ int ast_sip_initialize_cli(void); void ast_sip_destroy_cli(void); +/*! + * \internal \brief Used by res_pjsip.so to register a service without adding a self reference + */ +int pjsip_register_service(pjsip_module *module); + +/*! + * \internal \brief Used by res_pjsip.so to unregister a service without removing a self reference + */ +int pjsip_unregister_service(pjsip_module *module); + +/*! + * \internal \brief Used by res_pjsip.so to register an endpoint formatter without adding a self reference + */ +void pjsip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj); + +/*! + * \internal \brief Used by res_pjsip.so to unregister a endpoint formatter without removing a self reference + */ +int pjsip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj); + #endif /* RES_PJSIP_PRIVATE_H_ */ Index: res/res_pjsip/location.c =================================================================== --- res/res_pjsip/location.c (revision 427203) +++ res/res_pjsip/location.c (working copy) @@ -866,7 +866,7 @@ ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path)); - ast_sip_register_endpoint_formatter(&endpoint_aor_formatter); + pjsip_register_endpoint_formatter(&endpoint_aor_formatter); contact_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); if (!contact_formatter) { @@ -907,6 +907,8 @@ ast_sip_unregister_cli_formatter(contact_formatter); ast_sip_unregister_cli_formatter(aor_formatter); + pjsip_unregister_endpoint_formatter(&endpoint_aor_formatter); + return 0; } Index: res/res_pjsip/pjsip_configuration.c =================================================================== --- res/res_pjsip/pjsip_configuration.c (revision 427203) +++ res/res_pjsip/pjsip_configuration.c (working copy) @@ -1670,7 +1670,9 @@ return -1; } - ast_sorcery_internal_object_register(sip_sorcery, "nat_hook", sip_nat_hook_alloc, NULL, NULL); + if (ast_sorcery_internal_object_register(sip_sorcery, "nat_hook", sip_nat_hook_alloc, NULL, NULL)) { + ast_log(LOG_ERROR, "Failed to register nat_hook\n"); + } ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context)); @@ -1846,6 +1848,7 @@ ast_sip_unregister_cli_formatter(endpoint_formatter); ast_sip_unregister_cli_formatter(channel_formatter); ast_sorcery_unref(sip_sorcery); + ao2_cleanup(persistent_endpoints); } int ast_res_pjsip_reload_configuration(void) Index: res/res_pjsip/pjsip_distributor.c =================================================================== --- res/res_pjsip/pjsip_distributor.c (revision 427203) +++ res/res_pjsip/pjsip_distributor.c (working copy) @@ -21,6 +21,7 @@ #include #include "asterisk/res_pjsip.h" +#include "include/res_pjsip_private.h" static int distribute(void *data); static pj_bool_t distributor(pjsip_rx_data *rdata); @@ -222,7 +223,7 @@ return artificial_auth; } -static struct ast_sip_endpoint *artificial_endpoint; +static struct ast_sip_endpoint *artificial_endpoint = NULL; static int create_artificial_endpoint(void) { @@ -236,7 +237,7 @@ * the proper size of the vector is returned. This value is * not actually used anywhere */ - AST_VECTOR_APPEND(&artificial_endpoint->inbound_auths, "artificial-auth"); + AST_VECTOR_APPEND(&artificial_endpoint->inbound_auths, ast_strdup("artificial-auth")); return 0; } @@ -375,13 +376,13 @@ return -1; } - if (ast_sip_register_service(&distributor_mod)) { + if (pjsip_register_service(&distributor_mod)) { return -1; } - if (ast_sip_register_service(&endpoint_mod)) { + if (pjsip_register_service(&endpoint_mod)) { return -1; } - if (ast_sip_register_service(&auth_mod)) { + if (pjsip_register_service(&auth_mod)) { return -1; } @@ -390,9 +391,9 @@ void ast_sip_destroy_distributor(void) { - ast_sip_unregister_service(&distributor_mod); - ast_sip_unregister_service(&endpoint_mod); - ast_sip_unregister_service(&auth_mod); + pjsip_unregister_service(&distributor_mod); + pjsip_unregister_service(&endpoint_mod); + pjsip_unregister_service(&auth_mod); ao2_cleanup(artificial_auth); ao2_cleanup(artificial_endpoint); Index: res/res_pjsip/pjsip_global_headers.c =================================================================== --- res/res_pjsip/pjsip_global_headers.c (revision 427203) +++ res/res_pjsip/pjsip_global_headers.c (working copy) @@ -23,6 +23,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/linkedlists.h" +#include "include/res_pjsip_private.h" static pj_status_t add_request_headers(pjsip_tx_data *tdata); static pj_status_t add_response_headers(pjsip_tx_data *tdata); @@ -151,7 +152,7 @@ AST_RWLIST_HEAD_INIT(&request_headers); AST_RWLIST_HEAD_INIT(&response_headers); - ast_sip_register_service(&global_header_mod); + pjsip_register_service(&global_header_mod); } static void destroy_headers(struct header_list *headers) Index: res/res_pjsip/pjsip_options.c =================================================================== --- res/res_pjsip/pjsip_options.c (revision 427203) +++ res/res_pjsip/pjsip_options.c (working copy) @@ -1101,7 +1101,7 @@ return -1; } - ast_sip_register_endpoint_formatter(&contact_status_formatter); + pjsip_register_endpoint_formatter(&contact_status_formatter); ast_manager_register2("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify, NULL, NULL, NULL); ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options)); @@ -1114,7 +1114,7 @@ { ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options)); ast_manager_unregister("PJSIPQualify"); - ast_sip_unregister_endpoint_formatter(&contact_status_formatter); + pjsip_unregister_endpoint_formatter(&contact_status_formatter); pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module); ao2_cleanup(sched_qualifies); Index: res/res_pjsip/pjsip_outbound_auth.c =================================================================== --- res/res_pjsip/pjsip_outbound_auth.c (revision 427203) +++ res/res_pjsip/pjsip_outbound_auth.c (working copy) @@ -92,5 +92,5 @@ } int ast_sip_initialize_outbound_authentication(void) { - return ast_sip_register_service(&outbound_auth_mod); + return pjsip_register_service(&outbound_auth_mod); } Index: res/res_pjsip.c =================================================================== --- res/res_pjsip.c (revision 427203) +++ res/res_pjsip.c (working copy) @@ -1774,8 +1774,7 @@ static struct ast_threadpool *sip_threadpool; -static int register_service(void *data) -{ +static int register_service_noref(void *data) { pjsip_module **module = data; if (!ast_pjsip_endpoint) { ast_log(LOG_ERROR, "There is no PJSIP endpoint. Unable to register services\n"); @@ -1786,19 +1785,33 @@ return -1; } ast_debug(1, "Registered SIP service %.*s (%p)\n", (int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name), *module); - ast_module_ref(ast_module_info->self); return 0; } +static int register_service(void *data) +{ + int res; + + if (!(res = register_service_noref(data))) { + ast_module_ref(ast_module_info->self); + } + + return res; +} + +int pjsip_register_service(pjsip_module *module) +{ + return ast_sip_push_task_synchronous(NULL, register_service_noref, &module); +} + int ast_sip_register_service(pjsip_module *module) { return ast_sip_push_task_synchronous(NULL, register_service, &module); } -static int unregister_service(void *data) +static int unregister_service_noref(void *data) { pjsip_module **module = data; - ast_module_unref(ast_module_info->self); if (!ast_pjsip_endpoint) { return -1; } @@ -1807,6 +1820,22 @@ return 0; } +static int unregister_service(void *data) +{ + int res; + + if (!(res = unregister_service_noref(data))) { + ast_module_unref(ast_module_info->self); + } + + return res; +} + +int pjsip_unregister_service(pjsip_module *module) +{ + return ast_sip_push_task_synchronous(NULL, unregister_service_noref, &module); +} + void ast_sip_unregister_service(pjsip_module *module) { ast_sip_push_task_synchronous(NULL, unregister_service, &module); @@ -1953,28 +1982,40 @@ AST_RWLIST_HEAD_STATIC(endpoint_formatters, ast_sip_endpoint_formatter); -int ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) +void pjsip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) { SCOPED_LOCK(lock, &endpoint_formatters, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); AST_RWLIST_INSERT_TAIL(&endpoint_formatters, obj, next); +} + +int ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) +{ + pjsip_register_endpoint_formatter(obj); ast_module_ref(ast_module_info->self); return 0; } -void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) +int pjsip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) { struct ast_sip_endpoint_formatter *i; SCOPED_LOCK(lock, &endpoint_formatters, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&endpoint_formatters, i, next) { if (i == obj) { AST_RWLIST_REMOVE_CURRENT(next); - ast_module_unref(ast_module_info->self); break; } } AST_RWLIST_TRAVERSE_SAFE_END; + return i == obj ? 0 : -1; } +void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) +{ + if (!pjsip_unregister_endpoint_formatter(obj)) { + ast_module_unref(ast_module_info->self); + } +} + int ast_sip_format_endpoint_ami(struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami, int *count) { @@ -3134,7 +3175,7 @@ return AST_MODULE_LOAD_DECLINE; } - if (ast_sip_register_service(&supplement_module)) { + if (pjsip_register_service(&supplement_module)) { ast_log(LOG_ERROR, "Failed to initialize supplement hooks. Aborting load\n"); ast_sip_destroy_distributor(); ast_res_pjsip_destroy_configuration(); @@ -3151,7 +3192,7 @@ if (ast_sip_initialize_outbound_authentication()) { ast_log(LOG_ERROR, "Failed to initialize outbound authentication. Aborting load\n"); - ast_sip_unregister_service(&supplement_module); + pjsip_unregister_service(&supplement_module); ast_sip_destroy_distributor(); ast_res_pjsip_destroy_configuration(); ast_sip_destroy_global_headers(); @@ -3167,7 +3208,7 @@ ast_res_pjsip_init_options_handling(0); - ast_module_ref(ast_module_info->self); + ast_module_shutdown_ref(ast_module_info->self); return AST_MODULE_LOAD_SUCCESS; } @@ -3182,9 +3223,39 @@ return 0; } +static int unload_pjsip(void *data) +{ + if (memory_pool) { + pj_pool_release(memory_pool); + memory_pool = NULL; + } + if (ast_pjsip_endpoint) { + pjsip_endpt_destroy(ast_pjsip_endpoint); + ast_pjsip_endpoint = NULL; + } + pj_caching_pool_destroy(&caching_pool); + return 0; +} + static int unload_module(void) { - /* This will never get called as this module can't be unloaded */ + ast_res_pjsip_cleanup_options_handling(); + ast_sip_destroy_distributor(); + ast_res_pjsip_destroy_configuration(); + ast_sip_destroy_system(); + ast_sip_destroy_global_headers(); + pjsip_unregister_service(&supplement_module); + if (monitor_thread) { + stop_monitor_thread(); + } + /* The thread this is called from cannot call PJSIP/PJLIB functions, + * so we have to push the work to the threadpool to handle + */ + ast_sip_push_task_synchronous(NULL, unload_pjsip, NULL); + + ast_threadpool_shutdown(sip_threadpool); + + ast_sip_destroy_cli(); return 0; } Index: res/res_pjsip_notify.c =================================================================== --- res/res_pjsip_notify.c (revision 427203) +++ res/res_pjsip_notify.c (working copy) @@ -1021,6 +1021,7 @@ ast_manager_unregister("PJSIPNotify"); ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options)); aco_info_destroy(¬ify_cfg); + ao2_global_obj_release(globals); return 0; } Index: res/res_pjsip_outbound_publish.c =================================================================== --- res/res_pjsip_outbound_publish.c (revision 427203) +++ res/res_pjsip_outbound_publish.c (working copy) @@ -955,6 +955,7 @@ current = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "outbound-publish", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); ao2_global_obj_replace_unref(active, current); + ao2_cleanup(current); } static struct ast_sorcery_observer outbound_publish_observer = { @@ -1004,6 +1005,7 @@ static int unload_module(void) { + ao2_global_obj_release(active); return 0; } Index: res/res_pjsip_pubsub.c =================================================================== --- res/res_pjsip_pubsub.c (revision 427203) +++ res/res_pjsip_pubsub.c (working copy) @@ -4286,6 +4286,8 @@ AST_TEST_UNREGISTER(loop); AST_TEST_UNREGISTER(bad_event); + ast_sip_unregister_service(&pubsub_module); + return 0; } Index: res/res_pjsip_session.c =================================================================== --- res/res_pjsip_session.c (revision 427203) +++ res/res_pjsip_session.c (working copy) @@ -2315,14 +2315,16 @@ } ast_sip_register_service(&session_reinvite_module); - ast_module_ref(ast_module_info->self); + ast_module_shutdown_ref(ast_module_info->self); return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { - /* This will never get called as this module can't be unloaded */ + ast_sip_unregister_service(&session_module); + ast_sip_unregister_service(&session_reinvite_module); + ao2_cleanup(sdp_handlers); return 0; }