summaryrefslogtreecommitdiff
path: root/res/res_pjsip_outbound_registration.c
diff options
context:
space:
mode:
authorKinsey Moore <kmoore@digium.com>2013-08-02 12:40:03 +0000
committerKinsey Moore <kmoore@digium.com>2013-08-02 12:40:03 +0000
commit41cd06e03f6e4a783fbe5323efe71990cf35dfb8 (patch)
tree4a83dc964a5993211f8354228e8ab22cb9b0cf46 /res/res_pjsip_outbound_registration.c
parent4f07502000d3c9ca3195629597dc0ecf5a25d94d (diff)
Add CLI/AMI commands to force chan_pjsip actions
For chan_pjsip, this introduces CLI/AMI remote unregistration commands, reworks CLI syntax for sending NOTIFYs, adds AMI qualification support, and adds documentation for PJSIPNotify. This also fixes two refcounting bugs in the outbound registration code. Review: https://reviewboard.asterisk.org/r/2695/ (closes issue ASTERISK-21939) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@396087 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_pjsip_outbound_registration.c')
-rw-r--r--res/res_pjsip_outbound_registration.c167
1 files changed, 163 insertions, 4 deletions
diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index 6d9368ec1..c104b3edf 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -30,6 +30,7 @@
#include "asterisk/res_pjsip.h"
#include "asterisk/module.h"
#include "asterisk/taskprocessor.h"
+#include "asterisk/cli.h"
/*** DOCUMENTATION
<configInfo name="res_pjsip_outbound_registration" language="en_US">
@@ -90,6 +91,17 @@
</configObject>
</configFile>
</configInfo>
+ <manager name="PJSIPUnregister" language="en_US">
+ <synopsis>
+ Unregister an outbound registration.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ <parameter name="Registration" required="true">
+ <para>The outbound registration to unregister.</para>
+ </parameter>
+ </syntax>
+ </manager>
***/
/*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
@@ -209,7 +221,7 @@ static int handle_client_registration(void *data)
/*! \brief Timer callback function, used just for registrations */
static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
{
- RAII_VAR(struct sip_outbound_registration_client_state *, client_state, entry->user_data, ao2_cleanup);
+ struct sip_outbound_registration_client_state *client_state = entry->user_data;
ao2_ref(client_state, +1);
if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
@@ -333,7 +345,10 @@ static int handle_registration_response(void *data)
pjsip_tx_data *tdata;
if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
response->rdata, response->tsx, &tdata)) {
- pjsip_regc_send(response->client_state->client, tdata);
+ ao2_ref(response->client_state, +1);
+ if (pjsip_regc_send(response->client_state->client, tdata) != PJ_SUCCESS) {
+ ao2_cleanup(response->client_state);
+ }
return 0;
}
/* Otherwise, fall through so the failure is processed appropriately */
@@ -388,6 +403,7 @@ static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *par
response->code = param->code;
response->expiration = param->expiration;
response->client_state = client_state;
+ ao2_ref(response->client_state, +1);
if (param->rdata) {
struct pjsip_retry_after_hdr *retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER, NULL);
@@ -397,8 +413,6 @@ static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *par
pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
}
- ao2_ref(response->client_state, +1);
-
if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
ao2_cleanup(response);
@@ -704,6 +718,147 @@ static int outbound_auth_handler(const struct aco_option *opt, struct ast_variab
return ast_sip_auth_array_init(&registration->outbound_auths, var->value);
}
+static struct sip_outbound_registration *retrieve_registration(const char *registration_name)
+{
+ return ast_sorcery_retrieve_by_id(
+ ast_sip_get_sorcery(),
+ "registration",
+ registration_name);
+}
+
+static int unregister_task(void *obj)
+{
+ RAII_VAR(struct sip_outbound_registration*, registration, obj, ao2_cleanup);
+ struct pjsip_regc *client = registration->state->client_state->client;
+ pjsip_tx_data *tdata;
+
+ if (pjsip_regc_unregister(client, &tdata) != PJ_SUCCESS) {
+ return 0;
+ }
+
+ ao2_ref(registration->state->client_state, +1);
+ if (pjsip_regc_send(client, tdata) != PJ_SUCCESS) {
+ ao2_cleanup(registration->state->client_state);
+ }
+
+ return 0;
+}
+
+static int queue_unregister(struct sip_outbound_registration *registration)
+{
+ ao2_ref(registration, +1);
+ if (ast_sip_push_task(registration->state->client_state->serializer, unregister_task, registration)) {
+ ao2_cleanup(registration);
+ return -1;
+ }
+ return 0;
+}
+
+static char *cli_complete_registration(const char *line, const char *word,
+int pos, int state)
+{
+ char *result = NULL;
+ int wordlen;
+ int which = 0;
+ struct sip_outbound_registration *registration;
+ RAII_VAR(struct ao2_container *, registrations, NULL, ao2_cleanup);
+ struct ao2_iterator i;
+
+ if (pos != 3) {
+ return NULL;
+ }
+
+ wordlen = strlen(word);
+ registrations = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
+ AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+ if (!registrations) {
+ return NULL;
+ }
+
+ i = ao2_iterator_init(registrations, 0);
+ while ((registration = ao2_iterator_next(&i))) {
+ const char *name = ast_sorcery_object_get_id(registration);
+ if (!strncasecmp(word, name, wordlen) && ++which > state) {
+ result = ast_strdup(name);
+ }
+
+ ao2_cleanup(registration);
+ if (result) {
+ break;
+ }
+ }
+ ao2_iterator_destroy(&i);
+ return result;
+}
+
+static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ RAII_VAR(struct sip_outbound_registration *, registration, NULL, ao2_cleanup);
+ const char *registration_name;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "pjsip send unregister";
+ e->usage =
+ "Usage: pjsip send unregister <registration>\n"
+ " Send a SIP REGISTER request to the specified outbound "
+ "registration with an expiration of 0. This will cause the contact "
+ "added by this registration to be removed on the remote system.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return cli_complete_registration(a->line, a->word, a->pos, a->n);
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ registration_name = a->argv[3];
+
+ registration = retrieve_registration(registration_name);
+ if (!registration) {
+ ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
+ return CLI_FAILURE;
+ }
+
+ if (queue_unregister(registration)) {
+ ast_cli(a->fd, "Failed to queue unregistration");
+ return 0;
+ }
+
+ return CLI_SUCCESS;
+}
+
+static int ami_unregister(struct mansession *s, const struct message *m)
+{
+ const char *registration_name = astman_get_header(m, "Registration");
+ RAII_VAR(struct sip_outbound_registration *, registration, NULL, ao2_cleanup);
+
+ if (ast_strlen_zero(registration_name)) {
+ astman_send_error(s, m, "Registration parameter missing.");
+ return 0;
+ }
+
+ registration = retrieve_registration(registration_name);
+ if (!registration) {
+ astman_send_error(s, m, "Unable to retrieve registration entry\n");
+ return 0;
+ }
+
+
+ if (queue_unregister(registration)) {
+ astman_send_ack(s, m, "Failed to queue unregistration");
+ return 0;
+ }
+
+ astman_send_ack(s, m, "Unregistration sent");
+ return 0;
+}
+
+static struct ast_cli_entry cli_outbound_registration[] = {
+ AST_CLI_DEFINE(cli_unregister, "Send a REGISTER request to an outbound registration target with a expiration of 0")
+};
+
static int load_module(void)
{
ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
@@ -726,6 +881,8 @@ static int load_module(void)
ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
sip_outbound_registration_perform_all();
+ ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
+ ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
return AST_MODULE_LOAD_SUCCESS;
}
@@ -738,6 +895,8 @@ static int reload_module(void)
static int unload_module(void)
{
+ ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
+ ast_manager_unregister("PJSIPUnregister");
return 0;
}