2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * Joshua Colp <jcolp@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 <depend>pjproject</depend>
21 <depend>res_pjsip</depend>
22 <support_level>core</support_level>
30 #include "asterisk/res_pjsip.h"
31 #include "asterisk/res_pjsip_cli.h"
32 #include "asterisk/module.h"
33 #include "asterisk/taskprocessor.h"
34 #include "asterisk/cli.h"
35 #include "asterisk/stasis_system.h"
36 #include "asterisk/threadstorage.h"
37 #include "asterisk/threadpool.h"
38 #include "res_pjsip/include/res_pjsip_private.h"
41 <configInfo name="res_pjsip_outbound_registration" language="en_US">
42 <synopsis>SIP resource for outbound registrations</synopsis>
44 <emphasis>Outbound Registration</emphasis>
46 <para>This module allows <literal>res_pjsip</literal> to register to other SIP servers.</para>
48 <configFile name="pjsip.conf">
49 <configObject name="registration">
50 <synopsis>The configuration for outbound registration</synopsis>
52 Registration is <emphasis>COMPLETELY</emphasis> separate from the rest of
53 <literal>pjsip.conf</literal>. A minimal configuration consists of
54 setting a <literal>server_uri</literal> and a <literal>client_uri</literal>.
56 <configOption name="auth_rejection_permanent" default="yes">
57 <synopsis>Determines whether failed authentication challenges are treated
58 as permanent failures.</synopsis>
59 <description><para>If this option is enabled and an authentication challenge fails,
60 registration will not be attempted again until the configuration is reloaded.</para></description>
62 <configOption name="client_uri">
63 <synopsis>Client SIP URI used when attemping outbound registration</synopsis>
65 This is the address-of-record for the outbound registration (i.e. the URI in
66 the To header of the REGISTER).</para>
67 <para>For registration with an ITSP, the client SIP URI may need to consist of
68 an account name or number and the provider's hostname for their registrar, e.g.
69 client_uri=1234567890@example.com. This may differ between providers.</para>
70 <para>For registration to generic registrars, the client SIP URI will depend
71 on networking specifics and configuration of the registrar.
74 <configOption name="contact_user">
75 <synopsis>Contact User to use in request</synopsis>
77 <configOption name="expiration" default="3600">
78 <synopsis>Expiration time for registrations in seconds</synopsis>
80 <configOption name="max_retries" default="10">
81 <synopsis>Maximum number of registration attempts.</synopsis>
83 <configOption name="outbound_auth" default="">
84 <synopsis>Authentication object to be used for outbound registrations.</synopsis>
86 <configOption name="outbound_proxy" default="">
87 <synopsis>Outbound Proxy used to send registrations</synopsis>
89 <configOption name="retry_interval" default="60">
90 <synopsis>Interval in seconds between retries if outbound registration is unsuccessful</synopsis>
92 <configOption name="forbidden_retry_interval" default="0">
93 <synopsis>Interval used when receiving a 403 Forbidden response.</synopsis>
95 If a 403 Forbidden is received, chan_pjsip will wait
96 <replaceable>forbidden_retry_interval</replaceable> seconds before
97 attempting registration again. If 0 is specified, chan_pjsip will not
98 retry after receiving a 403 Forbidden response. Setting this to a non-zero
99 value goes against a "SHOULD NOT" in RFC3261, but can be used to work around
101 </para></description>
103 <configOption name="server_uri">
104 <synopsis>SIP URI of the server to register against</synopsis>
106 This is the URI at which to find the registrar to send the outbound REGISTER. This URI
107 is used as the request URI of the outbound REGISTER request from Asterisk.</para>
108 <para>For registration with an ITSP, the setting may often be just the domain of
109 the registrar, e.g. sip:sip.example.com.
110 </para></description>
112 <configOption name="transport">
113 <synopsis>Transport used for outbound authentication</synopsis>
115 <note><para>A <replaceable>transport</replaceable> configured in
116 <literal>pjsip.conf</literal>. As with other <literal>res_pjsip</literal> modules, this will use the first available transport of the appropriate type if unconfigured.</para></note>
119 <configOption name="line">
120 <synopsis>Whether to add a 'line' parameter to the Contact for inbound call matching</synopsis>
122 When enabled this option will cause a 'line' parameter to be added to the Contact
123 header placed into the outgoing registration request. If the remote server sends a call
124 this line parameter will be used to establish a relationship to the outbound registration,
125 ultimately causing the configured endpoint to be used.
126 </para></description>
128 <configOption name="endpoint">
129 <synopsis>Endpoint to use for incoming related calls</synopsis>
131 When line support is enabled this configured endpoint name is used for incoming calls
132 that are related to the outbound registration.
133 </para></description>
135 <configOption name="type">
136 <synopsis>Must be of type 'registration'.</synopsis>
138 <configOption name="support_path">
139 <synopsis>Enables Path support for outbound REGISTER requests.</synopsis>
141 When this option is enabled, outbound REGISTER requests will advertise
142 support for Path headers so that intervening proxies can add to the Path
144 </para></description>
149 <manager name="PJSIPUnregister" language="en_US">
151 Unregister an outbound registration.
154 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
155 <parameter name="Registration" required="true">
156 <para>The outbound registration to unregister.</para>
161 Unregisters the specified outbound registration and stops future registration attempts.
162 Call PJSIPRegister to start registration and schedule re-registrations according to configuration.
166 <manager name="PJSIPRegister" language="en_US">
168 Register an outbound registration.
171 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
172 <parameter name="Registration" required="true">
173 <para>The outbound registration to register.</para>
178 Unregisters the specified outbound registration then starts registration and schedules re-registrations
179 according to configuration.
180 future registrations.
184 <manager name="PJSIPShowRegistrationsOutbound" language="en_US">
186 Lists PJSIP outbound registrations.
191 In response <literal>OutboundRegistrationDetail</literal> events showing configuration and status
192 information are raised for each outbound registration object. <literal>AuthDetail</literal>
193 events are raised for each associated auth object as well. Once all events are completed an
194 <literal>OutboundRegistrationDetailComplete</literal> is issued.
200 /*! \brief Some thread local storage used to determine if the running thread invoked the callback */
201 AST_THREADSTORAGE(register_callback_invoked);
203 /*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
204 #define REREGISTER_BUFFER_TIME 10
206 /*! \brief Size of the buffer for creating a unique string for the line */
207 #define LINE_PARAMETER_SIZE 8
209 /*! \brief Various states that an outbound registration may be in */
210 enum sip_outbound_registration_status {
211 /*! \brief Currently unregistered */
212 SIP_REGISTRATION_UNREGISTERED = 0,
213 /*! \brief Registered, yay! */
214 SIP_REGISTRATION_REGISTERED,
215 /*! \brief Registration was rejected, but response was temporal */
216 SIP_REGISTRATION_REJECTED_TEMPORARY,
217 /*! \brief Registration was rejected, permanently */
218 SIP_REGISTRATION_REJECTED_PERMANENT,
219 /*! \brief Registration is stopping. */
220 SIP_REGISTRATION_STOPPING,
221 /*! \brief Registration has been stopped */
222 SIP_REGISTRATION_STOPPED,
227 * \brief Convert the internal registration state to an external status string.
230 * \param state Current outbound registration state.
232 * \return External registration status string.
234 static const char *sip_outbound_registration_status_str(enum sip_outbound_registration_status state)
238 str = "Unregistered";
240 case SIP_REGISTRATION_STOPPING:
241 case SIP_REGISTRATION_STOPPED:
242 case SIP_REGISTRATION_UNREGISTERED:
244 case SIP_REGISTRATION_REGISTERED:
247 case SIP_REGISTRATION_REJECTED_TEMPORARY:
248 case SIP_REGISTRATION_REJECTED_PERMANENT:
255 /*! \brief Outbound registration information */
256 struct sip_outbound_registration {
257 /*! \brief Sorcery object details */
258 SORCERY_OBJECT(details);
259 /*! \brief Stringfields */
260 AST_DECLARE_STRING_FIELDS(
261 /*! \brief URI for the registrar */
262 AST_STRING_FIELD(server_uri);
263 /*! \brief URI for the AOR */
264 AST_STRING_FIELD(client_uri);
265 /*! \brief Optional user for contact header */
266 AST_STRING_FIELD(contact_user);
267 /*! \brief Explicit transport to use for registration */
268 AST_STRING_FIELD(transport);
269 /*! \brief Outbound proxy to use */
270 AST_STRING_FIELD(outbound_proxy);
271 /*! \brief Endpoint to use for related incoming calls */
272 AST_STRING_FIELD(endpoint);
274 /*! \brief Requested expiration time */
275 unsigned int expiration;
276 /*! \brief Interval at which retries should occur for temporal responses */
277 unsigned int retry_interval;
278 /*! \brief Interval at which retries should occur for permanent responses */
279 unsigned int forbidden_retry_interval;
280 /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
281 unsigned int auth_rejection_permanent;
282 /*! \brief Maximum number of retries permitted */
283 unsigned int max_retries;
284 /*! \brief Whether to add a line parameter to the outbound Contact or not */
286 /*! \brief Configured authentication credentials */
287 struct ast_sip_auth_vector outbound_auths;
288 /*! \brief Whether Path support is enabled */
289 unsigned int support_path;
292 /*! \brief Outbound registration client state information (persists for lifetime of regc) */
293 struct sip_outbound_registration_client_state {
294 /*! \brief Current state of this registration */
295 enum sip_outbound_registration_status status;
297 * \brief Outbound registration client
298 * \note May only be accessed within the serializer thread
299 * because it might get destroyed and set to NULL for
303 /*! \brief Timer entry for retrying on temporal responses */
304 pj_timer_entry timer;
305 /*! \brief Optional line parameter placed into Contact */
306 char line[LINE_PARAMETER_SIZE];
307 /*! \brief Current number of retries */
308 unsigned int retries;
309 /*! \brief Maximum number of retries permitted */
310 unsigned int max_retries;
311 /*! \brief Interval at which retries should occur for temporal responses */
312 unsigned int retry_interval;
313 /*! \brief Interval at which retries should occur for permanent responses */
314 unsigned int forbidden_retry_interval;
315 /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
316 unsigned int auth_rejection_permanent;
317 /*! \brief Determines whether SIP Path support should be advertised */
318 unsigned int support_path;
319 /*! \brief Serializer for stuff and things */
320 struct ast_taskprocessor *serializer;
321 /*! \brief Configured authentication credentials */
322 struct ast_sip_auth_vector outbound_auths;
323 /*! \brief Registration should be destroyed after completion of transaction */
324 unsigned int destroy:1;
325 /*! \brief Non-zero if we have attempted sending a REGISTER with authentication */
326 unsigned int auth_attempted:1;
329 /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
330 struct sip_outbound_registration_state {
331 /*! \brief Outbound registration configuration object */
332 struct sip_outbound_registration *registration;
333 /*! \brief Client state information */
334 struct sip_outbound_registration_client_state *client_state;
337 /*! Time needs to be long enough for a transaction to timeout if nothing replies. */
338 #define MAX_UNLOAD_TIMEOUT_TIME 35 /* Seconds */
340 /*! Shutdown group to monitor sip_outbound_registration_client_state serializers. */
341 static struct ast_serializer_shutdown_group *shutdown_group;
343 /*! \brief Default number of state container buckets */
344 #define DEFAULT_STATE_BUCKETS 53
345 static AO2_GLOBAL_OBJ_STATIC(current_states);
347 /*! \brief hashing function for state objects */
348 static int registration_state_hash(const void *obj, const int flags)
350 const struct sip_outbound_registration_state *object;
353 switch (flags & OBJ_SEARCH_MASK) {
357 case OBJ_SEARCH_OBJECT:
359 key = ast_sorcery_object_get_id(object->registration);
365 return ast_str_hash(key);
368 /*! \brief comparator function for state objects */
369 static int registration_state_cmp(void *obj, void *arg, int flags)
371 const struct sip_outbound_registration_state *object_left = obj;
372 const struct sip_outbound_registration_state *object_right = arg;
373 const char *right_key = arg;
376 switch (flags & OBJ_SEARCH_MASK) {
377 case OBJ_SEARCH_OBJECT:
378 right_key = ast_sorcery_object_get_id(object_right->registration);
381 cmp = strcmp(ast_sorcery_object_get_id(object_left->registration), right_key);
383 case OBJ_SEARCH_PARTIAL_KEY:
384 /* Not supported by container. */
397 static struct sip_outbound_registration_state *get_state(const char *id)
399 struct sip_outbound_registration_state *state = NULL;
400 struct ao2_container *states;
402 states = ao2_global_obj_ref(current_states);
404 state = ao2_find(states, id, OBJ_SEARCH_KEY);
410 static struct ao2_container *get_registrations(void)
412 struct ao2_container *registrations = ast_sorcery_retrieve_by_fields(
413 ast_sip_get_sorcery(), "registration",
414 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
416 return registrations;
419 /*! \brief Callback function for matching an outbound registration based on line */
420 static int line_identify_relationship(void *obj, void *arg, int flags)
422 struct sip_outbound_registration_state *state = obj;
423 pjsip_param *line = arg;
425 return !pj_strcmp2(&line->value, state->client_state->line) ? CMP_MATCH | CMP_STOP : 0;
428 static struct pjsip_param *get_uri_option_line(const void *uri)
430 pjsip_sip_uri *pjuri;
431 static const pj_str_t LINE_STR = { "line", 4 };
433 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
436 pjuri = pjsip_uri_get_uri(uri);
437 return pjsip_param_find(&pjuri->other_param, &LINE_STR);
440 /*! \brief Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing registration */
441 static struct ast_sip_endpoint *line_identify(pjsip_rx_data *rdata)
444 RAII_VAR(struct ao2_container *, states, NULL, ao2_cleanup);
445 RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
447 if (!(line = get_uri_option_line(rdata->msg_info.to->uri))
448 && !(line = get_uri_option_line(rdata->msg_info.msg->line.req.uri))) {
452 states = ao2_global_obj_ref(current_states);
457 state = ao2_callback(states, 0, line_identify_relationship, line);
458 if (!state || ast_strlen_zero(state->registration->endpoint)) {
462 ast_debug(3, "Determined relationship to outbound registration '%s' based on line '%s', using configured endpoint '%s'\n",
463 ast_sorcery_object_get_id(state->registration), state->client_state->line, state->registration->endpoint);
465 return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", state->registration->endpoint);
468 static struct ast_sip_endpoint_identifier line_identifier = {
469 .identify_endpoint = line_identify,
472 /*! \brief Helper function which cancels the timer on a client */
473 static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
475 if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &client_state->timer)) {
476 /* The timer was successfully cancelled, drop the refcount of client_state */
477 ao2_ref(client_state, -1);
481 static pj_str_t PATH_NAME = { "path", 4 };
483 /*! \brief Helper function which sends a message and cleans up, if needed, on failure */
484 static pj_status_t registration_client_send(struct sip_outbound_registration_client_state *client_state,
485 pjsip_tx_data *tdata)
488 int *callback_invoked;
490 callback_invoked = ast_threadstorage_get(®ister_callback_invoked, sizeof(int));
491 if (!callback_invoked) {
494 *callback_invoked = 0;
496 /* Due to the message going out the callback may now be invoked, so bump the count */
497 ao2_ref(client_state, +1);
498 status = pjsip_regc_send(client_state->client, tdata);
500 /* If the attempt to send the message failed and the callback was not invoked we need to
501 * drop the reference we just added
503 if ((status != PJ_SUCCESS) && !(*callback_invoked)) {
504 ao2_ref(client_state, -1);
510 /*! \brief Callback function for registering */
511 static int handle_client_registration(void *data)
513 RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
514 pjsip_tx_data *tdata;
515 pjsip_regc_info info;
516 char server_uri[PJSIP_MAX_URL_SIZE];
517 char client_uri[PJSIP_MAX_URL_SIZE];
519 if (client_state->status == SIP_REGISTRATION_STOPPED
520 || pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
524 pjsip_regc_get_info(client_state->client, &info);
525 ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
526 ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
527 ast_debug(1, "Outbound REGISTER attempt %u to '%s' with client '%s'\n",
528 client_state->retries + 1, server_uri, client_uri);
530 if (client_state->support_path) {
531 pjsip_supported_hdr *hdr;
533 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
535 /* insert a new Supported header */
536 hdr = pjsip_supported_hdr_create(tdata->pool);
541 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
544 /* add on to the existing Supported header */
545 pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
548 registration_client_send(client_state, tdata);
553 /*! \brief Timer callback function, used just for registrations */
554 static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
556 struct sip_outbound_registration_client_state *client_state = entry->user_data;
561 * Transfer client_state reference to serializer task so the
562 * nominal path will not dec the client_state ref in this
563 * pjproject callback thread.
565 if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
566 ast_log(LOG_WARNING, "Scheduled outbound registration could not be executed.\n");
567 ao2_ref(client_state, -1);
571 /*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
572 static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
574 pj_time_val delay = { .sec = seconds, };
575 pjsip_regc_info info;
577 cancel_registration(client_state);
579 pjsip_regc_get_info(client_state->client, &info);
580 ast_debug(1, "Scheduling outbound registration to server '%.*s' from client '%.*s' in %d seconds\n",
581 (int) info.server_uri.slen, info.server_uri.ptr,
582 (int) info.client_uri.slen, info.client_uri.ptr,
585 ao2_ref(client_state, +1);
586 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
587 ast_log(LOG_WARNING, "Failed to schedule registration to server '%.*s' from client '%.*s'\n",
588 (int) info.server_uri.slen, info.server_uri.ptr,
589 (int) info.client_uri.slen, info.client_uri.ptr);
590 ao2_ref(client_state, -1);
594 /*! \brief Callback function for unregistering (potentially) and destroying state */
595 static int handle_client_state_destruction(void *data)
597 struct sip_outbound_registration_client_state *client_state = data;
599 cancel_registration(client_state);
601 if (client_state->client) {
602 pjsip_regc_info info;
603 pjsip_tx_data *tdata;
605 pjsip_regc_get_info(client_state->client, &info);
607 if (info.is_busy == PJ_TRUE) {
608 /* If a client transaction is in progress we defer until it is complete */
610 "Registration transaction is busy with server '%.*s' from client '%.*s'.\n",
611 (int) info.server_uri.slen, info.server_uri.ptr,
612 (int) info.client_uri.slen, info.client_uri.ptr);
613 client_state->destroy = 1;
614 ao2_ref(client_state, -1);
618 switch (client_state->status) {
619 case SIP_REGISTRATION_UNREGISTERED:
621 case SIP_REGISTRATION_REGISTERED:
623 "Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n",
624 (int) info.server_uri.slen, info.server_uri.ptr,
625 (int) info.client_uri.slen, info.client_uri.ptr);
627 client_state->status = SIP_REGISTRATION_STOPPING;
628 client_state->destroy = 1;
629 if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS
630 && registration_client_send(client_state, tdata) == PJ_SUCCESS) {
631 ao2_ref(client_state, -1);
635 case SIP_REGISTRATION_REJECTED_TEMPORARY:
636 case SIP_REGISTRATION_REJECTED_PERMANENT:
637 case SIP_REGISTRATION_STOPPING:
638 case SIP_REGISTRATION_STOPPED:
642 pjsip_regc_destroy(client_state->client);
643 client_state->client = NULL;
646 client_state->status = SIP_REGISTRATION_STOPPED;
647 ast_sip_auth_vector_destroy(&client_state->outbound_auths);
648 ao2_ref(client_state, -1);
653 /*! \brief Structure for registration response */
654 struct registration_response {
655 /*! \brief Response code for the registration attempt */
657 /*! \brief Expiration time for registration */
659 /*! \brief Retry-After value */
661 /*! \brief Outbound registration client state */
662 struct sip_outbound_registration_client_state *client_state;
663 /*! \brief The response message */
664 pjsip_rx_data *rdata;
665 /*! \brief Request for which the response was received */
666 pjsip_tx_data *old_request;
669 /*! \brief Registration response structure destructor */
670 static void registration_response_destroy(void *obj)
672 struct registration_response *response = obj;
674 if (response->rdata) {
675 pjsip_rx_data_free_cloned(response->rdata);
678 if (response->old_request) {
679 pjsip_tx_data_dec_ref(response->old_request);
682 ao2_cleanup(response->client_state);
685 /*! \brief Helper function which determines if a response code is temporal or not */
686 static int sip_outbound_registration_is_temporal(unsigned int code,
687 struct sip_outbound_registration_client_state *client_state)
689 /* Shamelessly taken from pjsua */
690 if (code == PJSIP_SC_REQUEST_TIMEOUT ||
691 code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
692 code == PJSIP_SC_BAD_GATEWAY ||
693 code == PJSIP_SC_SERVICE_UNAVAILABLE ||
694 code == PJSIP_SC_SERVER_TIMEOUT ||
695 ((code == PJSIP_SC_UNAUTHORIZED ||
696 code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
697 !client_state->auth_rejection_permanent) ||
698 PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
705 static void schedule_retry(struct registration_response *response, unsigned int interval,
706 const char *server_uri, const char *client_uri)
708 response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
709 schedule_registration(response->client_state, interval);
711 if (response->rdata) {
712 ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
713 "registration attempt to '%s', retrying in '%u'\n",
714 response->code, server_uri, client_uri, interval);
716 ast_log(LOG_WARNING, "No response received from '%s' on "
717 "registration attempt to '%s', retrying in '%u'\n",
718 server_uri, client_uri, interval);
722 /*! \brief Callback function for handling a response to a registration attempt */
723 static int handle_registration_response(void *data)
725 struct registration_response *response = data;
726 pjsip_regc_info info;
727 char server_uri[PJSIP_MAX_URL_SIZE];
728 char client_uri[PJSIP_MAX_URL_SIZE];
730 if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
731 ao2_ref(response, -1);
735 pjsip_regc_get_info(response->client_state->client, &info);
736 ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
737 ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
739 ast_debug(1, "Processing REGISTER response %d from server '%s' for client '%s'\n",
740 response->code, server_uri, client_uri);
742 if (!response->client_state->auth_attempted &&
743 (response->code == 401 || response->code == 407)) {
744 pjsip_tx_data *tdata;
745 if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
746 response->rdata, response->old_request, &tdata)) {
747 response->client_state->auth_attempted = 1;
748 ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
749 server_uri, client_uri);
750 if (registration_client_send(response->client_state, tdata) == PJ_SUCCESS) {
751 ao2_ref(response, -1);
755 ast_log(LOG_WARNING, "Failed to create authenticated REGISTER request to server '%s' from client '%s'\n",
756 server_uri, client_uri);
758 /* Otherwise, fall through so the failure is processed appropriately */
761 response->client_state->auth_attempted = 0;
763 if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
764 /* Check if this is in regards to registering or unregistering */
765 if (response->expiration) {
766 /* If the registration went fine simply reschedule registration for the future */
767 ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
768 response->client_state->status = SIP_REGISTRATION_REGISTERED;
769 response->client_state->retries = 0;
770 schedule_registration(response->client_state, response->expiration - REREGISTER_BUFFER_TIME);
772 ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
773 response->client_state->status = SIP_REGISTRATION_UNREGISTERED;
775 } else if (response->client_state->destroy) {
776 /* We need to deal with the pending destruction instead. */
777 } else if (response->retry_after) {
778 /* If we have been instructed to retry after a period of time, schedule it as such */
779 schedule_retry(response, response->retry_after, server_uri, client_uri);
780 } else if (response->client_state->retry_interval
781 && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
782 if (response->client_state->retries == response->client_state->max_retries) {
783 /* If we received enough temporal responses to exceed our maximum give up permanently */
784 response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
785 ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
786 server_uri, client_uri);
788 /* On the other hand if we can still try some more do so */
789 response->client_state->retries++;
790 schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
793 if (response->code == 403
794 && response->client_state->forbidden_retry_interval
795 && response->client_state->retries < response->client_state->max_retries) {
796 /* A forbidden response retry interval is configured and there are retries remaining */
797 response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
798 response->client_state->retries++;
799 schedule_registration(response->client_state, response->client_state->forbidden_retry_interval);
800 ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
801 server_uri, client_uri, response->client_state->forbidden_retry_interval);
803 /* Finally if there's no hope of registering give up */
804 response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
805 if (response->rdata) {
806 ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
807 response->code, server_uri, client_uri);
809 ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
814 ast_system_publish_registry("PJSIP", client_uri, server_uri,
815 sip_outbound_registration_status_str(response->client_state->status), NULL);
817 if (response->client_state->destroy) {
818 /* We have a pending deferred destruction to complete now. */
819 ao2_ref(response->client_state, +1);
820 handle_client_state_destruction(response->client_state);
823 ao2_ref(response, -1);
827 /*! \brief Callback function for outbound registration client */
828 static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
830 struct sip_outbound_registration_client_state *client_state = param->token;
831 struct registration_response *response;
832 int *callback_invoked;
834 callback_invoked = ast_threadstorage_get(®ister_callback_invoked, sizeof(int));
836 ast_assert(callback_invoked != NULL);
837 ast_assert(client_state != NULL);
839 *callback_invoked = 1;
841 response = ao2_alloc(sizeof(*response), registration_response_destroy);
843 ao2_ref(client_state, -1);
846 response->code = param->code;
847 response->expiration = param->expiration;
849 * Transfer client_state reference to response so the
850 * nominal path will not dec the client_state ref in this
851 * pjproject callback thread.
853 response->client_state = client_state;
855 ast_debug(1, "Received REGISTER response %d(%.*s)\n",
856 param->code, (int) param->reason.slen, param->reason.ptr);
859 struct pjsip_retry_after_hdr *retry_after;
860 pjsip_transaction *tsx;
862 retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER,
864 response->retry_after = retry_after ? retry_after->ivalue : 0;
865 tsx = pjsip_rdata_get_tsx(param->rdata);
866 response->old_request = tsx->last_tx;
867 pjsip_tx_data_add_ref(response->old_request);
868 pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
872 * Transfer response reference to serializer task so the
873 * nominal path will not dec the response ref in this
874 * pjproject callback thread.
876 if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
877 ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
878 ao2_cleanup(response);
882 /*! \brief Destructor function for registration state */
883 static void sip_outbound_registration_state_destroy(void *obj)
885 struct sip_outbound_registration_state *state = obj;
887 ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n",
888 state->registration->server_uri, state->registration->client_uri);
890 ao2_cleanup(state->registration);
892 if (!state->client_state) {
894 } else if (!state->client_state->serializer) {
895 ao2_ref(state->client_state, -1);
896 } else if (ast_sip_push_task(state->client_state->serializer,
897 handle_client_state_destruction, state->client_state)) {
898 ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
899 ao2_ref(state->client_state, -1);
903 /*! \brief Destructor function for client registration state */
904 static void sip_outbound_registration_client_state_destroy(void *obj)
906 struct sip_outbound_registration_client_state *client_state = obj;
908 ast_taskprocessor_unreference(client_state->serializer);
911 /*! \brief Allocator function for registration state */
912 static struct sip_outbound_registration_state *sip_outbound_registration_state_alloc(struct sip_outbound_registration *registration)
914 struct sip_outbound_registration_state *state;
916 state = ao2_alloc(sizeof(*state), sip_outbound_registration_state_destroy);
920 state->client_state = ao2_alloc(sizeof(*state->client_state),
921 sip_outbound_registration_client_state_destroy);
922 if (!state->client_state) {
927 state->client_state->serializer = ast_sip_create_serializer_group(shutdown_group);
928 if (!state->client_state->serializer) {
932 state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
933 state->client_state->timer.user_data = state->client_state;
934 state->client_state->timer.cb = sip_outbound_registration_timer_cb;
936 state->registration = ao2_bump(registration);
940 /*! \brief Destructor function for registration information */
941 static void sip_outbound_registration_destroy(void *obj)
943 struct sip_outbound_registration *registration = obj;
945 ast_sip_auth_vector_destroy(®istration->outbound_auths);
947 ast_string_field_free_memory(registration);
950 /*! \brief Allocator function for registration information */
951 static void *sip_outbound_registration_alloc(const char *name)
953 struct sip_outbound_registration *registration;
955 registration = ast_sorcery_generic_alloc(sizeof(*registration),
956 sip_outbound_registration_destroy);
957 if (!registration || ast_string_field_init(registration, 256)) {
958 ao2_cleanup(registration);
965 /*! \brief Helper function which populates a pj_str_t with a contact header */
966 static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user,
967 const pj_str_t *target, pjsip_tpselector *selector, const char *line)
969 pj_str_t tmp, local_addr;
971 pjsip_sip_uri *sip_uri;
972 pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
975 pj_strdup_with_null(pool, &tmp, target);
977 if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
978 (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
982 sip_uri = pjsip_uri_get_uri(uri);
984 if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
985 type = PJSIP_TRANSPORT_TLS;
986 } else if (!sip_uri->transport_param.slen) {
987 type = PJSIP_TRANSPORT_UDP;
989 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
992 if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
996 if (pj_strchr(&sip_uri->host, ':')) {
997 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
1000 if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
1001 pool, type, selector, &local_addr, &local_port) != PJ_SUCCESS) {
1005 if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
1006 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
1009 contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
1010 contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
1011 "<%s:%s@%s%.*s%s:%d%s%s%s%s>",
1012 (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
1014 (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
1015 (int)local_addr.slen,
1017 (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
1019 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
1020 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "",
1021 !ast_strlen_zero(line) ? ";line=" : "",
1029 * \brief Check if a registration can be reused
1031 * This checks if the existing outbound registration's configuration differs from a newly-applied
1032 * outbound registration to see if the applied one.
1034 * \param existing The pre-existing outbound registration
1035 * \param applied The newly-created registration
1037 static int can_reuse_registration(struct sip_outbound_registration *existing,
1038 struct sip_outbound_registration *applied)
1041 struct ast_sorcery *sorcery = ast_sip_get_sorcery();
1042 struct ast_variable *ve = ast_sorcery_objectset_create(sorcery, existing);
1043 struct ast_variable *va = ast_sorcery_objectset_create(sorcery, applied);
1044 struct ast_variable *vc = NULL;
1046 if (ast_sorcery_changeset_create(ve, va, &vc) || vc != NULL) {
1048 ast_debug(4, "Registration '%s' changed. Can't re-use.\n", ast_sorcery_object_get_id(existing));
1050 ast_debug(4, "Registration '%s' didn't change. Can re-use\n", ast_sorcery_object_get_id(existing));
1053 ast_variables_destroy(ve);
1054 ast_variables_destroy(va);
1055 ast_variables_destroy(vc);
1060 /*! \brief Helper function that allocates a pjsip registration client and configures it */
1061 static int sip_outbound_registration_regc_alloc(void *data)
1063 struct sip_outbound_registration_state *state = data;
1064 RAII_VAR(struct sip_outbound_registration *, registration,
1065 ao2_bump(state->registration), ao2_cleanup);
1069 pj_str_t server_uri, client_uri, contact_uri;
1070 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
1072 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
1074 ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
1075 ast_sorcery_object_get_id(registration));
1079 pj_strdup2_with_null(pool, &tmp, registration->server_uri);
1080 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1082 ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
1083 registration->server_uri, ast_sorcery_object_get_id(registration));
1084 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1088 pj_strdup2_with_null(pool, &tmp, registration->client_uri);
1089 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1091 ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
1092 registration->client_uri, ast_sorcery_object_get_id(registration));
1093 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1097 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1099 if (!ast_strlen_zero(registration->transport)) {
1100 RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", registration->transport), ao2_cleanup);
1102 if (!transport || !transport->state) {
1103 ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' "
1104 " for outbound registration", registration->transport);
1108 if (transport->state->transport) {
1109 selector.type = PJSIP_TPSELECTOR_TRANSPORT;
1110 selector.u.transport = transport->state->transport;
1111 } else if (transport->state->factory) {
1112 selector.type = PJSIP_TPSELECTOR_LISTENER;
1113 selector.u.listener = transport->state->factory;
1119 ast_assert(state->client_state->client == NULL);
1120 if (pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state,
1121 sip_outbound_registration_response_cb,
1122 &state->client_state->client) != PJ_SUCCESS) {
1126 pjsip_regc_set_transport(state->client_state->client, &selector);
1128 if (!ast_strlen_zero(registration->outbound_proxy)) {
1129 pjsip_route_hdr route_set, *route;
1130 static const pj_str_t ROUTE_HNAME = { "Route", 5 };
1133 pj_list_init(&route_set);
1135 pj_strdup2_with_null(pjsip_regc_get_pool(state->client_state->client), &tmp,
1136 registration->outbound_proxy);
1137 route = pjsip_parse_hdr(pjsip_regc_get_pool(state->client_state->client),
1138 &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL);
1142 pj_list_insert_nodes_before(&route_set, route);
1144 pjsip_regc_set_route_set(state->client_state->client, &route_set);
1147 if (state->registration->line) {
1148 ast_generate_random_string(state->client_state->line, sizeof(state->client_state->line));
1151 pj_cstr(&server_uri, registration->server_uri);
1154 if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client),
1155 &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
1156 state->client_state->line)) {
1160 pj_cstr(&client_uri, registration->client_uri);
1161 if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri,
1162 &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
1169 /*! \brief Helper function which performs a single registration */
1170 static int sip_outbound_registration_perform(void *data)
1172 struct sip_outbound_registration_state *state = data;
1173 struct sip_outbound_registration *registration = ao2_bump(state->registration);
1176 /* Just in case the client state is being reused for this registration, free the auth information */
1177 ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
1179 AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(®istration->outbound_auths));
1180 for (i = 0; i < AST_VECTOR_SIZE(®istration->outbound_auths); ++i) {
1181 const char *name = ast_strdup(AST_VECTOR_GET(®istration->outbound_auths, i));
1184 AST_VECTOR_APPEND(&state->client_state->outbound_auths, name);
1187 state->client_state->retry_interval = registration->retry_interval;
1188 state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
1189 state->client_state->max_retries = registration->max_retries;
1190 state->client_state->retries = 0;
1191 state->client_state->support_path = registration->support_path;
1192 state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
1194 pjsip_regc_update_expires(state->client_state->client, registration->expiration);
1196 schedule_registration(state->client_state, (ast_random() % 10) + 1);
1198 ao2_ref(registration, -1);
1203 /*! \brief Apply function which finds or allocates a state structure */
1204 static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
1206 RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup);
1207 RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
1208 RAII_VAR(struct sip_outbound_registration_state *, new_state, NULL, ao2_cleanup);
1209 struct sip_outbound_registration *applied = obj;
1212 /* Global container has gone. Likely shutting down. */
1215 state = ao2_find(states, ast_sorcery_object_get_id(applied), OBJ_SEARCH_KEY);
1217 ast_debug(4, "Applying configuration to outbound registration '%s'\n", ast_sorcery_object_get_id(applied));
1219 if (ast_strlen_zero(applied->server_uri)) {
1220 ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'",
1221 ast_sorcery_object_get_id(applied));
1223 } else if (ast_strlen_zero(applied->client_uri)) {
1224 ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
1225 ast_sorcery_object_get_id(applied));
1227 } else if (applied->line && ast_strlen_zero(applied->endpoint)) {
1228 ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
1229 ast_sorcery_object_get_id(applied));
1231 } else if (!ast_strlen_zero(applied->endpoint) && !applied->line) {
1232 ast_log(LOG_ERROR, "An endpoint has been specified on outbound registration '%s' without enabling line support\n",
1233 ast_sorcery_object_get_id(applied));
1237 if (state && can_reuse_registration(state->registration, applied)) {
1239 "No change between old configuration and new configuration on outbound registration '%s'. Using previous state\n",
1240 ast_sorcery_object_get_id(applied));
1243 * This is OK to replace without relinking the state in the
1244 * current_states container since state->registration and
1245 * applied have the same key.
1248 ao2_replace(state->registration, applied);
1253 if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
1257 if (ast_sip_push_task_synchronous(new_state->client_state->serializer,
1258 sip_outbound_registration_regc_alloc, new_state)) {
1262 if (ast_sip_push_task(new_state->client_state->serializer,
1263 sip_outbound_registration_perform, ao2_bump(new_state))) {
1264 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n",
1265 ast_sorcery_object_get_id(new_state->registration));
1266 ao2_ref(new_state, -1);
1272 ao2_unlink(states, state);
1274 ao2_link(states, new_state);
1280 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1282 struct sip_outbound_registration *registration = obj;
1284 return ast_sip_auth_vector_init(®istration->outbound_auths, var->value);
1287 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
1289 const struct sip_outbound_registration *registration = obj;
1291 return ast_sip_auths_to_str(®istration->outbound_auths, buf);
1294 static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
1296 const struct sip_outbound_registration *registration = obj;
1298 struct ast_variable *head = NULL;
1300 for (i = 0; i < AST_VECTOR_SIZE(®istration->outbound_auths) ; i++) {
1301 ast_variable_list_append(&head, ast_variable_new("outbound_auth",
1302 AST_VECTOR_GET(®istration->outbound_auths, i), ""));
1312 static int unregister_task(void *obj)
1314 struct sip_outbound_registration_state *state = obj;
1315 struct pjsip_regc *client = state->client_state->client;
1316 pjsip_tx_data *tdata;
1317 pjsip_regc_info info;
1319 pjsip_regc_get_info(client, &info);
1320 ast_debug(1, "Unregistering contacts with server '%s' from client '%s'\n",
1321 state->registration->server_uri, state->registration->client_uri);
1323 cancel_registration(state->client_state);
1325 if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS) {
1326 registration_client_send(state->client_state, tdata);
1333 static int queue_unregister(struct sip_outbound_registration_state *state)
1336 if (ast_sip_push_task(state->client_state->serializer, unregister_task, state)) {
1344 static int queue_register(struct sip_outbound_registration_state *state)
1347 if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) {
1355 static char *cli_complete_registration(const char *line, const char *word,
1358 char *result = NULL;
1361 struct sip_outbound_registration *registration;
1362 struct ao2_container *registrations;
1363 struct ao2_iterator i;
1369 wordlen = strlen(word);
1370 registrations = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
1371 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1372 if (!registrations) {
1376 i = ao2_iterator_init(registrations, 0);
1377 while ((registration = ao2_iterator_next(&i))) {
1378 const char *name = ast_sorcery_object_get_id(registration);
1380 if (!strncasecmp(word, name, wordlen) && ++which > state) {
1381 result = ast_strdup(name);
1384 ao2_ref(registration, -1);
1389 ao2_iterator_destroy(&i);
1391 ao2_ref(registrations, -1);
1395 static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1397 struct sip_outbound_registration_state *state;
1398 const char *registration_name;
1402 e->command = "pjsip send unregister";
1404 "Usage: pjsip send unregister <registration>\n"
1405 " Unregisters the specified outbound registration and stops future registration attempts.\n";
1408 return cli_complete_registration(a->line, a->word, a->pos, a->n);
1412 return CLI_SHOWUSAGE;
1415 registration_name = a->argv[3];
1417 state = get_state(registration_name);
1419 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
1423 if (queue_unregister(state)) {
1424 ast_cli(a->fd, "Failed to queue unregistration\n");
1431 static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1433 struct sip_outbound_registration_state *state;
1434 const char *registration_name;
1438 e->command = "pjsip send register";
1440 "Usage: pjsip send register <registration>\n"
1441 " Unregisters the specified outbound "
1442 "registration then re-registers and re-schedules it.\n";
1445 return cli_complete_registration(a->line, a->word, a->pos, a->n);
1449 return CLI_SHOWUSAGE;
1452 registration_name = a->argv[3];
1454 state = get_state(registration_name);
1456 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
1460 /* We need to serialize the unregister and register so they need
1461 * to be queued as separate tasks.
1463 if (queue_unregister(state)) {
1464 ast_cli(a->fd, "Failed to queue unregistration\n");
1465 } else if (queue_register(state)) {
1466 ast_cli(a->fd, "Failed to queue registration\n");
1473 static int ami_unregister(struct mansession *s, const struct message *m)
1475 const char *registration_name = astman_get_header(m, "Registration");
1476 struct sip_outbound_registration_state *state;
1478 if (ast_strlen_zero(registration_name)) {
1479 astman_send_error(s, m, "Registration parameter missing.");
1483 state = get_state(registration_name);
1485 astman_send_error(s, m, "Unable to retrieve registration entry\n");
1489 if (queue_unregister(state)) {
1490 astman_send_ack(s, m, "Failed to queue unregistration");
1492 astman_send_ack(s, m, "Unregistration sent");
1499 static int ami_register(struct mansession *s, const struct message *m)
1501 const char *registration_name = astman_get_header(m, "Registration");
1502 struct sip_outbound_registration_state *state;
1504 if (ast_strlen_zero(registration_name)) {
1505 astman_send_error(s, m, "Registration parameter missing.");
1509 state = get_state(registration_name);
1511 astman_send_error(s, m, "Unable to retrieve registration entry\n");
1515 /* We need to serialize the unregister and register so they need
1516 * to be queued as separate tasks.
1518 if (queue_unregister(state)) {
1519 astman_send_ack(s, m, "Failed to queue unregistration");
1520 } else if (queue_register(state)) {
1521 astman_send_ack(s, m, "Failed to queue unregistration");
1523 astman_send_ack(s, m, "Reregistration sent");
1530 struct sip_ami_outbound {
1531 struct ast_sip_ami *ami;
1534 struct sip_outbound_registration *registration;
1537 static int ami_outbound_registration_task(void *obj)
1539 struct sip_ami_outbound *ami = obj;
1540 struct ast_str *buf;
1541 struct sip_outbound_registration_state *state;
1543 buf = ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami);
1548 ast_sip_sorcery_object_to_ami(ami->registration, &buf);
1550 if ((state = get_state(ast_sorcery_object_get_id(ami->registration)))) {
1551 pjsip_regc_info info;
1553 if (state->client_state->status == SIP_REGISTRATION_REGISTERED) {
1556 ++ami->not_registered;
1559 ast_str_append(&buf, 0, "Status: %s\r\n",
1560 sip_outbound_registration_status_str(state->client_state->status));
1562 pjsip_regc_get_info(state->client_state->client, &info);
1563 ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg);
1567 astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
1570 return ast_sip_format_auths_ami(&ami->registration->outbound_auths, ami->ami);
1573 static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
1575 struct sip_ami_outbound *ami = arg;
1577 ami->registration = obj;
1578 return ast_sip_push_task_synchronous(
1579 NULL, ami_outbound_registration_task, ami);
1582 static int ami_show_outbound_registrations(struct mansession *s,
1583 const struct message *m)
1585 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
1586 struct sip_ami_outbound ami_outbound = { .ami = &ami };
1587 struct ao2_container *regs;
1589 regs = get_registrations();
1591 astman_send_error(s, m, "Unable to retrieve "
1592 "outbound registrations\n");
1596 astman_send_listack(s, m, "Following are Events for each Outbound registration",
1599 ao2_callback(regs, OBJ_NODATA, ami_outbound_registration_detail, &ami_outbound);
1601 astman_send_list_complete_start(s, m, "OutboundRegistrationDetailComplete",
1602 ami_outbound.registered + ami_outbound.not_registered);
1604 "Registered: %d\r\n"
1605 "NotRegistered: %d\r\n",
1606 ami_outbound.registered,
1607 ami_outbound.not_registered);
1608 astman_send_list_complete_end(s);
1614 static struct ao2_container *cli_get_container(void)
1616 RAII_VAR(struct ao2_container *, container, get_registrations(), ao2_cleanup);
1617 struct ao2_container *s_container;
1623 s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
1624 ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
1629 if (ao2_container_dup(s_container, container, 0)) {
1630 ao2_ref(s_container, -1);
1637 static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
1639 ao2_callback(container, OBJ_NODATA, callback, args);
1644 static void *cli_retrieve_by_id(const char *id)
1646 struct ao2_container *states;
1647 void *obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
1650 /* if the object no longer exists then remove its state */
1651 states = ao2_global_obj_ref(current_states);
1653 ao2_find(states, id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
1654 ao2_ref(states, -1);
1661 static int cli_print_header(void *obj, void *arg, int flags)
1663 struct ast_sip_cli_context *context = arg;
1665 ast_assert(context->output_buffer != NULL);
1667 ast_str_append(&context->output_buffer, 0,
1668 " <Registration/ServerURI..............................> <Auth..........> <Status.......>\n");
1673 static int cli_print_body(void *obj, void *arg, int flags)
1675 struct sip_outbound_registration *registration = obj;
1676 struct ast_sip_cli_context *context = arg;
1677 const char *id = ast_sorcery_object_get_id(registration);
1678 struct sip_outbound_registration_state *state = get_state(id);
1679 #define REGISTRATION_URI_FIELD_LEN 53
1681 ast_assert(context->output_buffer != NULL);
1687 ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-16s %-16s\n",
1689 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
1690 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
1691 registration->server_uri,
1692 AST_VECTOR_SIZE(®istration->outbound_auths)
1693 ? AST_VECTOR_GET(®istration->outbound_auths, 0)
1695 sip_outbound_registration_status_str(state->client_state->status));
1698 if (context->show_details
1699 || (context->show_details_only_level_0 && context->indent_level == 0)) {
1700 ast_str_append(&context->output_buffer, 0, "\n");
1701 ast_sip_cli_print_sorcery_objectset(registration, context, 0);
1708 * A function pointer to callback needs to be within the
1709 * module in order to avoid problems with an undefined
1710 * symbol when the module is loaded.
1712 static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1714 return ast_sip_cli_traverse_objects(e, cmd, a);
1717 static struct ast_cli_entry cli_outbound_registration[] = {
1718 AST_CLI_DEFINE(cli_unregister, "Unregisters outbound registration target"),
1719 AST_CLI_DEFINE(cli_register, "Registers an outbound registration target"),
1720 AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
1721 .command = "pjsip list registrations",
1722 .usage = "Usage: pjsip list registrations\n"
1723 " List the configured PJSIP Registrations\n"),
1724 AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
1725 .command = "pjsip show registrations",
1726 .usage = "Usage: pjsip show registrations\n"
1727 " Show the configured PJSIP Registrations\n"),
1728 AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
1729 .command = "pjsip show registration",
1730 .usage = "Usage: pjsip show registration <id>\n"
1731 " Show the configured PJSIP Registration\n"),
1734 static struct ast_sip_cli_formatter_entry *cli_formatter;
1736 static void auth_observer(const char *type)
1738 struct sip_outbound_registration *registration;
1739 struct sip_outbound_registration_state *state;
1740 struct ao2_container *regs;
1741 const char *registration_id;
1742 struct ao2_iterator i;
1744 ast_debug(4, "Auths updated. Checking for any outbound registrations that are in permanent rejected state so they can be retried\n");
1746 regs = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
1747 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1748 if (!regs || ao2_container_count(regs) == 0) {
1753 i = ao2_iterator_init(regs, 0);
1754 for (; (registration = ao2_iterator_next(&i)); ao2_ref(registration, -1)) {
1755 registration_id = ast_sorcery_object_get_id(registration);
1756 state = get_state(registration_id);
1757 if (state && state->client_state->status == SIP_REGISTRATION_REJECTED_PERMANENT) {
1758 ast_debug(4, "Trying outbound registration '%s' again\n", registration_id);
1760 if (ast_sip_push_task(state->client_state->serializer,
1761 sip_outbound_registration_perform, ao2_bump(state))) {
1762 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", registration_id);
1768 ao2_iterator_destroy(&i);
1772 static const struct ast_sorcery_observer observer_callbacks_auth = {
1773 .loaded = auth_observer,
1776 static int check_state(void *obj, void *arg, int flags)
1778 struct sip_outbound_registration_state *state = obj;
1779 struct sip_outbound_registration *registration;
1781 registration = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration",
1782 ast_sorcery_object_get_id(state->registration));
1783 if (!registration) {
1784 /* This is a dead registration */
1788 ao2_ref(registration, -1);
1794 * \brief Observer to purge dead registration states.
1796 * \param name Module name owning the sorcery instance.
1797 * \param sorcery Instance being observed.
1798 * \param object_type Name of object being observed.
1799 * \param reloaded Non-zero if the object is being reloaded.
1803 static void registration_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
1805 struct ao2_container *states;
1807 if (strcmp(object_type, "registration")) {
1808 /* Not interested */
1812 states = ao2_global_obj_ref(current_states);
1814 /* Global container has gone. Likely shutting down. */
1818 /* Now to purge dead registrations. */
1819 ao2_callback(states, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, check_state, NULL);
1820 ao2_ref(states, -1);
1823 static const struct ast_sorcery_instance_observer observer_callbacks_registrations = {
1824 .object_type_loaded = registration_loaded_observer,
1827 static int unload_module(void)
1831 ast_manager_unregister("PJSIPShowRegistrationsOutbound");
1832 ast_manager_unregister("PJSIPUnregister");
1833 ast_manager_unregister("PJSIPRegister");
1835 ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1836 ast_sip_unregister_cli_formatter(cli_formatter);
1837 cli_formatter = NULL;
1839 ast_sip_unregister_endpoint_identifier(&line_identifier);
1841 ast_sorcery_observer_remove(ast_sip_get_sorcery(), "auth", &observer_callbacks_auth);
1842 ast_sorcery_instance_observer_remove(ast_sip_get_sorcery(), &observer_callbacks_registrations);
1844 ast_sorcery_object_unregister(ast_sip_get_sorcery(), "registration");
1846 ao2_global_obj_release(current_states);
1848 /* Wait for registration serializers to get destroyed. */
1849 ast_debug(2, "Waiting for registration transactions to complete for unload.\n");
1850 remaining = ast_serializer_shutdown_group_join(shutdown_group, MAX_UNLOAD_TIMEOUT_TIME);
1853 * NOTE: We probably have a sip_outbound_registration_client_state
1854 * ref leak if the remaining count cannot reach zero after a few
1855 * minutes of trying to unload.
1857 ast_log(LOG_WARNING, "Unload incomplete. Could not stop %d outbound registrations. Try again later.\n",
1862 ast_debug(2, "Successful shutdown.\n");
1864 ao2_cleanup(shutdown_group);
1865 shutdown_group = NULL;
1870 static int load_module(void)
1872 struct ao2_container *new_states;
1874 CHECK_PJSIP_MODULE_LOADED();
1876 shutdown_group = ast_serializer_shutdown_group_alloc();
1877 if (!shutdown_group) {
1878 return AST_MODULE_LOAD_FAILURE;
1881 /* Create outbound registration states container. */
1882 new_states = ao2_container_alloc(DEFAULT_STATE_BUCKETS,
1883 registration_state_hash, registration_state_cmp);
1885 ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
1887 return AST_MODULE_LOAD_FAILURE;
1889 ao2_global_obj_replace_unref(current_states, new_states);
1890 ao2_ref(new_states, -1);
1893 * Register sorcery object descriptions.
1895 ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_registration");
1896 ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
1898 if (ast_sorcery_object_register(ast_sip_get_sorcery(), "registration", sip_outbound_registration_alloc, NULL, sip_outbound_registration_apply)) {
1900 return AST_MODULE_LOAD_DECLINE;
1903 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
1904 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, server_uri));
1905 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
1906 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
1907 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
1908 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
1909 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
1910 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
1911 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "forbidden_retry_interval", "0", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, forbidden_retry_interval));
1912 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
1913 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));
1914 ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, outbound_auths_to_var_list, 0, 0);
1915 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
1916 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));
1917 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));
1920 * Register sorcery observers.
1922 if (ast_sorcery_instance_observer_add(ast_sip_get_sorcery(),
1923 &observer_callbacks_registrations)
1924 || ast_sorcery_observer_add(ast_sip_get_sorcery(), "auth",
1925 &observer_callbacks_auth)) {
1926 ast_log(LOG_ERROR, "Unable to register observers.\n");
1928 return AST_MODULE_LOAD_FAILURE;
1931 /* Register how this module identifies endpoints. */
1932 ast_sip_register_endpoint_identifier(&line_identifier);
1934 /* Register CLI commands. */
1935 cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1936 if (!cli_formatter) {
1937 ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
1939 return AST_MODULE_LOAD_FAILURE;
1941 cli_formatter->name = "registration";
1942 cli_formatter->print_header = cli_print_header;
1943 cli_formatter->print_body = cli_print_body;
1944 cli_formatter->get_container = cli_get_container;
1945 cli_formatter->iterate = cli_iterator;
1946 cli_formatter->get_id = ast_sorcery_object_get_id;
1947 cli_formatter->retrieve_by_id = cli_retrieve_by_id;
1948 ast_sip_register_cli_formatter(cli_formatter);
1949 ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1951 /* Register AMI actions. */
1952 ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
1953 ast_manager_register_xml("PJSIPRegister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_register);
1954 ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations);
1956 /* Load configuration objects */
1957 ast_sorcery_load_object(ast_sip_get_sorcery(), "registration");
1959 return AST_MODULE_LOAD_SUCCESS;
1962 static int reload_module(void)
1964 ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
1968 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
1969 .support_level = AST_MODULE_SUPPORT_CORE,
1970 .load = load_module,
1971 .reload = reload_module,
1972 .unload = unload_module,
1973 .load_pri = AST_MODPRI_APP_DEPEND,