diff options
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | include/asterisk/ari.h | 5 | ||||
-rw-r--r-- | main/sorcery.c | 18 | ||||
-rw-r--r-- | res/ari/resource_asterisk.c | 50 | ||||
-rw-r--r-- | res/ari/resource_asterisk.h | 13 | ||||
-rw-r--r-- | res/res_ari.c | 7 | ||||
-rw-r--r-- | res/res_ari_asterisk.c | 61 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 6 | ||||
-rw-r--r-- | res/res_pjsip_outbound_registration.c | 2 | ||||
-rw-r--r-- | res/res_pjsip_session.c | 65 | ||||
-rw-r--r-- | res/res_sorcery_astdb.c | 1 | ||||
-rw-r--r-- | rest-api/api-docs/asterisk.json | 26 |
12 files changed, 240 insertions, 16 deletions
@@ -25,7 +25,7 @@ ARI * A new feature has been added that enables the retrieval of modules and module information through an HTTP request. Information on a single module can be also be retrieved. Individual modules can be loaded to Asterisk, as - well as unloaded. + well as unloaded and reloaded. res_pjsip ------------------ diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h index 00769eea5..c3df46a2b 100644 --- a/include/asterisk/ari.h +++ b/include/asterisk/ari.h @@ -225,6 +225,11 @@ void ast_ari_response_ok(struct ast_ari_response *response, void ast_ari_response_no_content(struct ast_ari_response *response); /*! + * \brief Fill in a <tt>Accepted</tt> (202) \a ast_ari_response. + */ +void ast_ari_response_accepted(struct ast_ari_response *response); + +/*! * \brief Fill in a <tt>Created</tt> (201) \a ast_ari_response. * \param response Response to fill in. * \param url URL to the created resource. diff --git a/main/sorcery.c b/main/sorcery.c index 7a4a7f324..2f451961b 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -1944,9 +1944,7 @@ static int sorcery_wizard_create(void *obj, void *arg, int flags) const struct sorcery_details *details = arg; if (!object_wizard->wizard->callbacks.create) { - ast_assert(0); - ast_log(LOG_ERROR, "Sorcery wizard '%s' doesn't contain a 'create' virtual function.\n", - object_wizard->wizard->callbacks.name); + ast_debug(5, "Sorcery wizard '%s' does not support creation\n", object_wizard->wizard->callbacks.name); return 0; } return (!object_wizard->caching && !object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0; @@ -2039,7 +2037,12 @@ static int sorcery_wizard_update(void *obj, void *arg, int flags) const struct ast_sorcery_object_wizard *object_wizard = obj; const struct sorcery_details *details = arg; - return (object_wizard->wizard->callbacks.update && !object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj) && + if (!object_wizard->wizard->callbacks.update) { + ast_debug(5, "Sorcery wizard '%s' does not support updating\n", object_wizard->wizard->callbacks.name); + return 0; + } + + return (!object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj) && !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0; } @@ -2107,7 +2110,12 @@ static int sorcery_wizard_delete(void *obj, void *arg, int flags) const struct ast_sorcery_object_wizard *object_wizard = obj; const struct sorcery_details *details = arg; - return (object_wizard->wizard->callbacks.delete && !object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj) && + if (!object_wizard->wizard->callbacks.delete) { + ast_debug(5, "Sorcery wizard '%s' does not support deletion\n", object_wizard->wizard->callbacks.name); + return 0; + } + + return (!object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj) && !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0; } diff --git a/res/ari/resource_asterisk.c b/res/ari/resource_asterisk.c index 6fabb2074..a8c37a20a 100644 --- a/res/ari/resource_asterisk.c +++ b/res/ari/resource_asterisk.c @@ -323,6 +323,56 @@ void ast_ari_asterisk_unload_module(struct ast_variable *headers, ast_ari_response_no_content(response); } +void ast_ari_asterisk_reload_module(struct ast_variable *headers, + struct ast_ari_asterisk_reload_module_args *args, + struct ast_ari_response *response) +{ + enum ast_module_reload_result reload_result; + + ast_assert(response != NULL); + + if (!ast_module_check(args->module_name)) { + ast_ari_response_error( + response, 404, "Not Found", + "Module not found in running modules"); + return; + } + + reload_result = ast_module_reload(args->module_name); + + if (reload_result == AST_MODULE_RELOAD_NOT_FOUND) { + ast_ari_response_error( + response, 404, "Not Found", + "Module could not be found"); + return; + } else if (reload_result == AST_MODULE_RELOAD_ERROR) { + ast_ari_response_error( + response, 409, "Conflict", + "An unknown error occurred while reloading the module"); + return; + } else if (reload_result == AST_MODULE_RELOAD_IN_PROGRESS) { + ast_ari_response_error( + response, 409, "Conflict", + "Another reload is currently in progress"); + return; + } else if (reload_result == AST_MODULE_RELOAD_UNINITIALIZED) { + ast_ari_response_error( + response, 409, "Conflict", + "Module has not been initialized"); + return; + } else if (reload_result == AST_MODULE_RELOAD_NOT_IMPLEMENTED) { + ast_ari_response_error( + response, 409, "Conflict", + "Module does not support reloading"); + return; + } else if (reload_result == AST_MODULE_RELOAD_QUEUED) { + ast_ari_response_accepted(response); + return; + } + + ast_ari_response_no_content(response); +} + void ast_ari_asterisk_get_global_var(struct ast_variable *headers, struct ast_ari_asterisk_get_global_var_args *args, struct ast_ari_response *response) diff --git a/res/ari/resource_asterisk.h b/res/ari/resource_asterisk.h index 5e3ff9b15..574d947e4 100644 --- a/res/ari/resource_asterisk.h +++ b/res/ari/resource_asterisk.h @@ -117,6 +117,19 @@ struct ast_ari_asterisk_unload_module_args { * \param[out] response HTTP response */ void ast_ari_asterisk_unload_module(struct ast_variable *headers, struct ast_ari_asterisk_unload_module_args *args, struct ast_ari_response *response); +/*! Argument struct for ast_ari_asterisk_reload_module() */ +struct ast_ari_asterisk_reload_module_args { + /*! Module's name */ + const char *module_name; +}; +/*! + * \brief Reload an Asterisk module. + * + * \param headers HTTP headers + * \param args Swagger parameters + * \param[out] response HTTP response + */ +void ast_ari_asterisk_reload_module(struct ast_variable *headers, struct ast_ari_asterisk_reload_module_args *args, struct ast_ari_response *response); /*! Argument struct for ast_ari_asterisk_get_global_var() */ struct ast_ari_asterisk_get_global_var_args { /*! The variable to get */ diff --git a/res/res_ari.c b/res/res_ari.c index 28f9be18b..761c2dd39 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -284,6 +284,13 @@ void ast_ari_response_no_content(struct ast_ari_response *response) response->response_text = "No Content"; } +void ast_ari_response_accepted(struct ast_ari_response *response) +{ + response->message = ast_json_null(); + response->response_code = 202; + response->response_text = "Accepted"; +} + void ast_ari_response_alloc_failed(struct ast_ari_response *response) { response->message = ast_json_ref(oom_json); diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index 161c64322..ec8b05e52 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -439,6 +439,66 @@ static void ast_ari_asterisk_unload_module_cb( fin: __attribute__((unused)) return; } +/*! + * \brief Parameter parsing callback for /asterisk/modules/{moduleName}. + * \param get_params GET parameters in the HTTP request. + * \param path_vars Path variables extracted from the request. + * \param headers HTTP headers. + * \param[out] response Response to the HTTP request. + */ +static void ast_ari_asterisk_reload_module_cb( + struct ast_tcptls_session_instance *ser, + struct ast_variable *get_params, struct ast_variable *path_vars, + struct ast_variable *headers, struct ast_ari_response *response) +{ + struct ast_ari_asterisk_reload_module_args args = {}; + struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); +#if defined(AST_DEVMODE) + int is_valid; + int code; +#endif /* AST_DEVMODE */ + + for (i = path_vars; i; i = i->next) { + if (strcmp(i->name, "moduleName") == 0) { + args.module_name = (i->value); + } else + {} + } + ast_ari_asterisk_reload_module(headers, &args, response); +#if defined(AST_DEVMODE) + code = response->response_code; + + switch (code) { + case 0: /* Implementation is still a stub, or the code wasn't set */ + is_valid = response->message == NULL; + break; + case 500: /* Internal Server Error */ + case 501: /* Not Implemented */ + case 404: /* Module not found in running modules. */ + case 409: /* Module could not be reloaded. */ + is_valid = 1; + break; + default: + if (200 <= code && code <= 299) { + is_valid = ast_ari_validate_void( + response->message); + } else { + ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules/{moduleName}\n", code); + is_valid = 0; + } + } + + if (!is_valid) { + ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules/{moduleName}\n"); + ast_ari_response_error(response, 500, + "Internal Server Error", "Response validation failed"); + } +#endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; +} int ast_ari_asterisk_get_global_var_parse_body( struct ast_json *body, struct ast_ari_asterisk_get_global_var_args *args) @@ -646,6 +706,7 @@ static struct stasis_rest_handlers asterisk_modules_moduleName = { [AST_HTTP_GET] = ast_ari_asterisk_get_module_cb, [AST_HTTP_POST] = ast_ari_asterisk_load_module_cb, [AST_HTTP_DELETE] = ast_ari_asterisk_unload_module_cb, + [AST_HTTP_PUT] = ast_ari_asterisk_reload_module_cb, }, .num_children = 0, .children = { } diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 9a383a25a..90a2650c0 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -700,7 +700,7 @@ static int media_encryption_handler(const struct aco_option *opt, struct ast_var static const char *media_encryption_map[] = { [AST_SIP_MEDIA_TRANSPORT_INVALID] = "invalid", - [AST_SIP_MEDIA_ENCRYPT_NONE] = "none", + [AST_SIP_MEDIA_ENCRYPT_NONE] = "no", [AST_SIP_MEDIA_ENCRYPT_SDES] = "sdes", [AST_SIP_MEDIA_ENCRYPT_DTLS] = "dtls", }; @@ -1925,8 +1925,8 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod ast_sorcery_object_field_register(sip_sorcery, "endpoint", "g726_non_standard", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.g726_non_standard)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, NULL, 0, 0); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, set_var_to_vl, 0, 0); - ast_sorcery_object_field_register(sip_sorcery, "endpoint", "message_context", "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct ast_sip_endpoint, message_context)); - ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accountcode", "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct ast_sip_endpoint, accountcode)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "message_context", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, message_context)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accountcode", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, accountcode)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 26d4a608e..c4d02491b 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1217,7 +1217,7 @@ static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, vo ast_debug(4, "Applying configuration to outbound registration '%s'\n", ast_sorcery_object_get_id(applied)); if (ast_strlen_zero(applied->server_uri)) { - ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'", + ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'\n", ast_sorcery_object_get_id(applied)); return -1; } else if (ast_strlen_zero(applied->client_uri)) { diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 8c04a7cfb..2c2ea616d 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2247,7 +2247,7 @@ static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdat } } -static int session_end(struct ast_sip_session *session) +static void session_end(struct ast_sip_session *session) { struct ast_sip_session_supplement *iter; @@ -2256,14 +2256,28 @@ static int session_end(struct ast_sip_session *session) ao2_ref(session, -1); } - /* Session is dead. Let's get rid of the reference to the session */ + /* Session is dead. Notify the supplements. */ AST_LIST_TRAVERSE(&session->supplements, iter, next) { if (iter->session_end) { iter->session_end(session); } } +} + +/*! + * \internal + * \brief Complete ending session activities. + * \since 13.5.0 + * + * \param vsession Which session to complete stopping. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int session_end_completion(void *vsession) +{ + struct ast_sip_session *session = vsession; - session->inv_session->mod_data[session_module.id] = NULL; ast_sip_dialog_set_serializer(session->inv_session->dlg, NULL); ast_sip_dialog_set_endpoint(session->inv_session->dlg, NULL); ao2_cleanup(session); @@ -2340,9 +2354,7 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans print_debug_details(inv, tsx, e); if (!session) { - /* Transaction likely timed out after the call was hung up. Just - * ignore such transaction changes - */ + /* The session has ended. Ignore the transaction change. */ return; } switch (e->body.tsx_state.type) { @@ -2423,7 +2435,48 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans } break; case PJSIP_EVENT_TRANSPORT_ERROR: + /* + * Clear the module data now to block session_inv_on_state_changed() + * from calling session_end() if it hasn't already done so. + */ + inv->mod_data[session_module.id] = NULL; + + if (inv->state != PJSIP_INV_STATE_DISCONNECTED) { + session_end(session); + } + + /* + * Pass the session ref held by session->inv_session to + * session_end_completion(). + */ + session_end_completion(session); + return; case PJSIP_EVENT_TIMER: + /* + * The timer event is run by the pjsip monitor thread and not + * by the session serializer. + */ + if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { + /* + * We are locking because ast_sip_dialog_get_session() needs + * the dialog locked to get the session by other threads. + */ + pjsip_dlg_inc_lock(inv->dlg); + session = inv->mod_data[session_module.id]; + inv->mod_data[session_module.id] = NULL; + pjsip_dlg_dec_lock(inv->dlg); + + /* + * Pass the session ref held by session->inv_session to + * session_end_completion(). + */ + if (ast_sip_push_task(session->serializer, session_end_completion, session)) { + /* Do it anyway even though this is not the right thread. */ + session_end_completion(session); + } + return; + } + break; case PJSIP_EVENT_USER: case PJSIP_EVENT_UNKNOWN: case PJSIP_EVENT_TSX_STATE: diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index e282d8b68..45a54946a 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -202,6 +202,7 @@ static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void * if (ast_db_get_allocated(family, id, &value) || !(json = ast_json_load_string(value, &error)) || !(objset = sorcery_json_to_objectset(json)) || !(object = ast_sorcery_alloc(sorcery, type, id)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { + ast_debug(3, "Failed to retrieve object '%s' from astdb\n", id); ao2_cleanup(object); return NULL; } diff --git a/rest-api/api-docs/asterisk.json b/rest-api/api-docs/asterisk.json index 28badce80..c6968a5ba 100644 --- a/rest-api/api-docs/asterisk.json +++ b/rest-api/api-docs/asterisk.json @@ -127,6 +127,32 @@ "reason": "Module could not be unloaded." } ] + }, + { + "httpMethod": "PUT", + "summary": "Reload an Asterisk module.", + "nickname": "reloadModule", + "responseClass": "void", + "parameters": [ + { + "name": "moduleName", + "description": "Module's name", + "paramType": "path", + "required": true, + "allowMultiple": false, + "dataType": "string" + } + ], + "errorResponses": [ + { + "code": 404, + "reason": "Module not found in running modules." + }, + { + "code": 409, + "reason": "Module could not be reloaded." + } + ] } ] }, |