diff --git a/CHANGES b/CHANGES index f4940045c9..05c2f60537 100644 --- a/CHANGES +++ b/CHANGES @@ -102,10 +102,18 @@ res_musiconhold * New 'PJSIP_AOR' and 'PJSIP_CONTACT' dialplan functions have been added which allow examining PJSIP AORs or contacts from the dialplan. +res_pjsip_outbound_registration +------------------ + * The 'pjsip send unregister' command now stops further registrations. + + * A new command 'pjsip send register' has been added which allows you to + start or restart periodic registration. It can be used after a + 'send unregister' or after a 401 permanent error. + res_pjsip_config_wizard ------------------ * This is a new module that adds streamlined configuration capability for - chan_pjsip. It's targetted at users who have lots of basic configuration + chan_pjsip. It's targeted at users who have lots of basic configuration scenarios like 'phone' or 'agent' or 'trunk'. Additional information can be found in the sample configuration file at config/samples/pjsip_wizard.conf.sample. diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index bb9904a399..1faa93e5ad 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -156,11 +156,27 @@ - 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. - Note: The specified outbound registration will attempt to re-register according to it's last - registration expiration. - + Unregisters the specified outbound registration and stops future registration attempts. + Call PJSIPRegister to start registration and schedule re-registrations according to configuration. + + + + + + Register an outbound registration. + + + + + The outbound registration to register. + + + + + Unregisters the specified outbound registration then starts registration and schedules re-registrations + according to configuration. + future registrations. + @@ -1124,6 +1140,8 @@ static int unregister_task(void *obj) struct pjsip_regc *client = state->client_state->client; pjsip_tx_data *tdata; + cancel_registration(state->client_state); + if (pjsip_regc_unregister(client, &tdata) != PJ_SUCCESS) { return 0; } @@ -1143,6 +1161,18 @@ static int queue_unregister(struct sip_outbound_registration_state *state) ao2_ref(state, -1); return -1; } + + return 0; +} + +static int queue_register(struct sip_outbound_registration_state *state) +{ + ao2_ref(state, +1); + if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) { + ao2_ref(state, -1); + return -1; + } + return 0; } @@ -1193,11 +1223,7 @@ static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg e->command = "pjsip send unregister"; e->usage = "Usage: pjsip send unregister \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. Note: " - "The specified outbound registration will attempt to re-register " - "according to its last registration expiration.\n"; + " Unregisters the specified outbound registration and stops future registration attempts.\n"; return NULL; case CLI_GENERATE: return cli_complete_registration(a->line, a->word, a->pos, a->n); @@ -1223,6 +1249,50 @@ static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg return CLI_SUCCESS; } +static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup); + const char *registration_name; + + switch (cmd) { + case CLI_INIT: + e->command = "pjsip send register"; + e->usage = + "Usage: pjsip send register \n" + " Unregisters the specified outbound " + "registration then re-registers and re-schedules it.\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]; + + state = get_state(registration_name); + if (!state) { + ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name); + return CLI_FAILURE; + } + + /* We need to serialize the unregister and register so they need + * to be queued as separate tasks. + */ + if (queue_unregister(state)) { + ast_cli(a->fd, "Failed to queue unregistration"); + return 0; + } + if (queue_register(state)) { + ast_cli(a->fd, "Failed to queue registration"); + 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"); @@ -1248,6 +1318,38 @@ static int ami_unregister(struct mansession *s, const struct message *m) return 0; } +static int ami_register(struct mansession *s, const struct message *m) +{ + const char *registration_name = astman_get_header(m, "Registration"); + RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup); + + if (ast_strlen_zero(registration_name)) { + astman_send_error(s, m, "Registration parameter missing."); + return 0; + } + + state = get_state(registration_name); + if (!state) { + astman_send_error(s, m, "Unable to retrieve registration entry\n"); + return 0; + } + + /* We need to serialize the unregister and register so they need + * to be queued as separate tasks. + */ + if (queue_unregister(state)) { + astman_send_ack(s, m, "Failed to queue unregistration"); + return 0; + } + if (queue_register(state)) { + astman_send_ack(s, m, "Failed to queue unregistration"); + return 0; + } + + astman_send_ack(s, m, "Reregistration sent"); + return 0; +} + struct sip_ami_outbound { struct ast_sip_ami *ami; int registered; @@ -1426,7 +1528,8 @@ static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct as } 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"), + AST_CLI_DEFINE(cli_unregister, "Unregisters outbound registration target"), + AST_CLI_DEFINE(cli_register, "Registers an outbound registration target"), AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations", .command = "pjsip list registrations", .usage = "Usage: pjsip list registrations\n" @@ -1450,6 +1553,7 @@ static int unload_module(void) ast_sip_unregister_cli_formatter(cli_formatter); ast_manager_unregister("PJSIPShowRegistrationsOutbound"); ast_manager_unregister("PJSIPUnregister"); + ast_manager_unregister("PJSIPRegister"); ao2_global_obj_release(current_states); @@ -1486,6 +1590,7 @@ static int load_module(void) ast_sip_register_endpoint_identifier(&line_identifier); ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister); + ast_manager_register_xml("PJSIPRegister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_register); ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations); cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);