pjsip: Handle outbound unregister correctly
[asterisk/asterisk.git] / res / res_pjsip_outbound_registration.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
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.
13  *
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.
17  */
18
19 /*** MODULEINFO
20         <depend>pjproject</depend>
21         <depend>res_pjsip</depend>
22         <support_level>core</support_level>
23  ***/
24
25 #include "asterisk.h"
26
27 #include <pjsip.h>
28 #include <pjsip_ua.h>
29
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 "res_pjsip/include/res_pjsip_private.h"
37
38 /*** DOCUMENTATION
39         <configInfo name="res_pjsip_outbound_registration" language="en_US">
40                 <synopsis>SIP resource for outbound registrations</synopsis>
41                 <description><para>
42                         <emphasis>Outbound Registration</emphasis>
43                         </para>
44                         <para>This module allows <literal>res_pjsip</literal> to register to other SIP servers.</para>
45                 </description>
46                 <configFile name="pjsip.conf">
47                         <configObject name="registration">
48                                 <synopsis>The configuration for outbound registration</synopsis>
49                                 <description><para>
50                                         Registration is <emphasis>COMPLETELY</emphasis> separate from the rest of
51                                         <literal>pjsip.conf</literal>. A minimal configuration consists of
52                                         setting a <literal>server_uri</literal> and a <literal>client_uri</literal>.
53                                 </para></description>
54                                 <configOption name="auth_rejection_permanent" default="yes">
55                                         <synopsis>Determines whether failed authentication challenges are treated
56                                         as permanent failures.</synopsis>
57                                         <description><para>If this option is enabled and an authentication challenge fails,
58                                         registration will not be attempted again until the configuration is reloaded.</para></description>
59                                 </configOption>
60                                 <configOption name="client_uri">
61                                         <synopsis>Client SIP URI used when attemping outbound registration</synopsis>
62                                         <description><para>
63                                                 This is the address-of-record for the outbound registration (i.e. the URI in
64                                                 the To header of the REGISTER).</para>
65                                                 <para>For registration with an ITSP, the client SIP URI may need to consist of
66                                                 an account name or number and the provider's hostname for their registrar, e.g.
67                                                 client_uri=1234567890@example.com. This may differ between providers.</para>
68                                                 <para>For registration to generic registrars, the client SIP URI will depend
69                                                 on networking specifics and configuration of the registrar.
70                                         </para></description>
71                                 </configOption>
72                                 <configOption name="contact_user">
73                                         <synopsis>Contact User to use in request</synopsis>
74                                 </configOption>
75                                 <configOption name="expiration" default="3600">
76                                         <synopsis>Expiration time for registrations in seconds</synopsis>
77                                 </configOption>
78                                 <configOption name="max_retries" default="10">
79                                         <synopsis>Maximum number of registration attempts.</synopsis>
80                                 </configOption>
81                                 <configOption name="outbound_auth" default="">
82                                         <synopsis>Authentication object to be used for outbound registrations.</synopsis>
83                                 </configOption>
84                                 <configOption name="outbound_proxy" default="">
85                                         <synopsis>Outbound Proxy used to send registrations</synopsis>
86                                 </configOption>
87                                 <configOption name="retry_interval" default="60">
88                                         <synopsis>Interval in seconds between retries if outbound registration is unsuccessful</synopsis>
89                                 </configOption>
90                                 <configOption name="forbidden_retry_interval" default="0">
91                                         <synopsis>Interval used when receiving a 403 Forbidden response.</synopsis>
92                                         <description><para>
93                                                 If a 403 Forbidden is received, chan_pjsip will wait
94                                                 <replaceable>forbidden_retry_interval</replaceable> seconds before
95                                                 attempting registration again. If 0 is specified, chan_pjsip will not
96                                                 retry after receiving a 403 Forbidden response. Setting this to a non-zero
97                                                 value goes against a "SHOULD NOT" in RFC3261, but can be used to work around
98                                                 buggy registrars.
99                                         </para></description>
100                                 </configOption>
101                                 <configOption name="server_uri">
102                                         <synopsis>SIP URI of the server to register against</synopsis>
103                                         <description><para>
104                                                 This is the URI at which to find the registrar to send the outbound REGISTER. This URI
105                                                 is used as the request URI of the outbound REGISTER request from Asterisk.</para>
106                                                 <para>For registration with an ITSP, the setting may often be just the domain of
107                                                 the registrar, e.g. sip:sip.example.com.
108                                         </para></description>
109                                 </configOption>
110                                 <configOption name="transport">
111                                         <synopsis>Transport used for outbound authentication</synopsis>
112                                         <description>
113                                                 <note><para>A <replaceable>transport</replaceable> configured in
114                                                 <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>
115                                         </description>
116                                 </configOption>
117                                 <configOption name="type">
118                                         <synopsis>Must be of type 'registration'.</synopsis>
119                                 </configOption>
120                                 <configOption name="support_path">
121                                         <synopsis>Enables Path support for outbound REGISTER requests.</synopsis>
122                                         <description><para>
123                                                 When this option is enabled, outbound REGISTER requests will advertise
124                                                 support for Path headers so that intervening proxies can add to the Path
125                                                 header as necessary.
126                                         </para></description>
127                                 </configOption>
128                         </configObject>
129                 </configFile>
130         </configInfo>
131         <manager name="PJSIPUnregister" language="en_US">
132                 <synopsis>
133                         Unregister an outbound registration.
134                 </synopsis>
135                 <syntax>
136                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
137                         <parameter name="Registration" required="true">
138                                 <para>The outbound registration to unregister.</para>
139                         </parameter>
140                 </syntax>
141                 <description>
142                         <para>
143                         Send a SIP REGISTER request to the specified outbound registration with an expiration of 0.
144                         This will cause the contact added by this registration to be removed on the remote system.
145                         Note: The specified outbound registration will attempt to re-register according to it's last
146                         registration expiration.
147                         </para>
148                 </description>
149         </manager>
150         <manager name="PJSIPShowRegistrationsOutbound" language="en_US">
151                 <synopsis>
152                         Lists PJSIP outbound registrations.
153                 </synopsis>
154                 <syntax />
155                 <description>
156                         <para>
157                         In response <literal>OutboundRegistrationDetail</literal> events showing configuration and status
158                         information are raised for each outbound registration object. <literal>AuthDetail</literal>
159                         events are raised for each associated auth object as well.  Once all events are completed an
160                         <literal>OutboundRegistrationDetailComplete</literal> is issued.
161                         </para>
162                 </description>
163         </manager>
164  ***/
165
166 /*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
167 #define REREGISTER_BUFFER_TIME 10
168
169 /*! \brief Various states that an outbound registration may be in */
170 enum sip_outbound_registration_status {
171         /*! \brief Currently unregistered */
172         SIP_REGISTRATION_UNREGISTERED = 0,
173         /*! \brief Registered, yay! */
174         SIP_REGISTRATION_REGISTERED,
175         /*! \brief Registration was rejected, but response was temporal */
176         SIP_REGISTRATION_REJECTED_TEMPORARY,
177         /*! \brief Registration was rejected, permanently */
178         SIP_REGISTRATION_REJECTED_PERMANENT,
179         /*! \brief Registration has been stopped */
180         SIP_REGISTRATION_STOPPED,
181 };
182
183 static const char *sip_outbound_registration_status_str[] = {
184         [SIP_REGISTRATION_UNREGISTERED] = "Unregistered",
185         [SIP_REGISTRATION_REGISTERED] = "Registered",
186         [SIP_REGISTRATION_REJECTED_TEMPORARY] = "Rejected",
187         [SIP_REGISTRATION_REJECTED_PERMANENT] = "Rejected",
188         [SIP_REGISTRATION_STOPPED] = "Stopped",
189 };
190
191 /*! \brief Outbound registration client state information (persists for lifetime of regc) */
192 struct sip_outbound_registration_client_state {
193         /*! \brief Current status of this registration */
194         enum sip_outbound_registration_status status;
195         /*! \brief Outbound registration client */
196         pjsip_regc *client;
197         /*! \brief Timer entry for retrying on temporal responses */
198         pj_timer_entry timer;
199         /*! \brief Current number of retries */
200         unsigned int retries;
201         /*! \brief Maximum number of retries permitted */
202         unsigned int max_retries;
203         /*! \brief Interval at which retries should occur for temporal responses */
204         unsigned int retry_interval;
205         /*! \brief Interval at which retries should occur for permanent responses */
206         unsigned int forbidden_retry_interval;
207         /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
208         unsigned int auth_rejection_permanent;
209         /*! \brief Determines whether SIP Path support should be advertised */
210         unsigned int support_path;
211         /*! \brief Serializer for stuff and things */
212         struct ast_taskprocessor *serializer;
213         /*! \brief Configured authentication credentials */
214         struct ast_sip_auth_vector outbound_auths;
215         /*! \brief Registration should be destroyed after completion of transaction */
216         unsigned int destroy:1;
217 };
218
219 /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
220 struct sip_outbound_registration_state {
221         /*! \brief Client state information */
222         struct sip_outbound_registration_client_state *client_state;
223 };
224
225 /*! \brief Outbound registration information */
226 struct sip_outbound_registration {
227         /*! \brief Sorcery object details */
228         SORCERY_OBJECT(details);
229         /*! \brief Stringfields */
230         AST_DECLARE_STRING_FIELDS(
231                 /*! \brief URI for the registrar */
232                 AST_STRING_FIELD(server_uri);
233                 /*! \brief URI for the AOR */
234                 AST_STRING_FIELD(client_uri);
235                 /*! \brief Optional user for contact header */
236                 AST_STRING_FIELD(contact_user);
237                 /*! \brief Explicit transport to use for registration */
238                 AST_STRING_FIELD(transport);
239                 /*! \brief Outbound proxy to use */
240                 AST_STRING_FIELD(outbound_proxy);
241         );
242         /*! \brief Requested expiration time */
243         unsigned int expiration;
244         /*! \brief Interval at which retries should occur for temporal responses */
245         unsigned int retry_interval;
246         /*! \brief Interval at which retries should occur for permanent responses */
247         unsigned int forbidden_retry_interval;
248         /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
249         unsigned int auth_rejection_permanent;
250         /*! \brief Maximum number of retries permitted */
251         unsigned int max_retries;
252         /*! \brief Outbound registration state */
253         struct sip_outbound_registration_state *state;
254         /*! \brief Configured authentication credentials */
255         struct ast_sip_auth_vector outbound_auths;
256         /*! \brief Whether Path support is enabled */
257         unsigned int support_path;
258 };
259
260 /*! \brief Helper function which cancels the timer on a client */
261 static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
262 {
263         if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &client_state->timer)) {
264                 /* The timer was successfully cancelled, drop the refcount of client_state */
265                 ao2_ref(client_state, -1);
266         }
267 }
268
269 static pj_str_t PATH_NAME = { "path", 4 };
270
271 /*! \brief Callback function for registering */
272 static int handle_client_registration(void *data)
273 {
274         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
275         pjsip_tx_data *tdata;
276         pjsip_regc_info info;
277         char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
278
279         cancel_registration(client_state);
280
281         if ((client_state->status == SIP_REGISTRATION_STOPPED) ||
282                 (pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS)) {
283                 return 0;
284         }
285
286         pjsip_regc_get_info(client_state->client, &info);
287         ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
288         ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
289         ast_debug(3, "REGISTER attempt %u to '%s' with client '%s'\n",
290                   client_state->retries + 1, server_uri, client_uri);
291
292         if (client_state->support_path) {
293                 pjsip_supported_hdr *hdr;
294
295                 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
296                 if (!hdr) {
297                         /* insert a new Supported header */
298                         hdr = pjsip_supported_hdr_create(tdata->pool);
299                         if (!hdr) {
300                                 return -1;
301                         }
302
303                         pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
304                 }
305
306                 /* add on to the existing Supported header */
307                 pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
308         }
309
310         /* Due to the registration the callback may now get called, so bump the ref count */
311         ao2_ref(client_state, +1);
312         if (pjsip_regc_send(client_state->client, tdata) != PJ_SUCCESS) {
313                 ao2_ref(client_state, -1);
314         }
315
316         return 0;
317 }
318
319 /*! \brief Timer callback function, used just for registrations */
320 static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
321 {
322         struct sip_outbound_registration_client_state *client_state = entry->user_data;
323
324         ao2_ref(client_state, +1);
325         if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
326                 ast_log(LOG_WARNING, "Failed to pass outbound registration to threadpool\n");
327                 ao2_ref(client_state, -1);
328         }
329
330         entry->id = 0;
331 }
332
333 /*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
334 static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
335 {
336         pj_time_val delay = { .sec = seconds, };
337
338         cancel_registration(client_state);
339
340         ao2_ref(client_state, +1);
341         if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
342                 ast_log(LOG_WARNING, "Failed to pass timed registration to scheduler\n");
343                 ao2_ref(client_state, -1);
344         }
345 }
346
347 /*! \brief Callback function for unregistering (potentially) and destroying state */
348 static int handle_client_state_destruction(void *data)
349 {
350         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
351
352         cancel_registration(client_state);
353
354         if (client_state->client) {
355                 pjsip_regc_info info;
356
357                 pjsip_regc_get_info(client_state->client, &info);
358
359                 if (info.is_busy == PJ_TRUE) {
360                         /* If a client transaction is in progress we defer until it is complete */
361                         client_state->destroy = 1;
362                         return 0;
363                 }
364
365                 if (client_state->status != SIP_REGISTRATION_UNREGISTERED && client_state->status != SIP_REGISTRATION_REJECTED_PERMANENT) {
366                         pjsip_tx_data *tdata;
367
368                         if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS) {
369                                 pjsip_regc_send(client_state->client, tdata);
370                         }
371                 }
372
373                 pjsip_regc_destroy(client_state->client);
374         }
375
376         client_state->status = SIP_REGISTRATION_STOPPED;
377         ast_sip_auth_vector_destroy(&client_state->outbound_auths);
378
379         return 0;
380 }
381
382 /*! \brief Structure for registration response */
383 struct registration_response {
384         /*! \brief Response code for the registration attempt */
385         int code;
386         /*! \brief Expiration time for registration */
387         int expiration;
388         /*! \brief Retry-After value */
389         int retry_after;
390         /*! \brief Outbound registration client state */
391         struct sip_outbound_registration_client_state *client_state;
392         /*! \brief The response message */
393         pjsip_rx_data *rdata;
394         /*! \brief The response transaction */
395         pjsip_transaction *tsx;
396 };
397
398 /*! \brief Registration response structure destructor */
399 static void registration_response_destroy(void *obj)
400 {
401         struct registration_response *response = obj;
402
403         if (response->rdata) {
404                 pjsip_rx_data_free_cloned(response->rdata);
405         }
406
407         ao2_cleanup(response->client_state);
408 }
409
410 /* \brief Helper funtion which determines if a response code is temporal or not */
411 static int sip_outbound_registration_is_temporal(unsigned int code,
412                 struct sip_outbound_registration_client_state *client_state)
413 {
414         /* Shamelessly taken from pjsua */
415         if (code == PJSIP_SC_REQUEST_TIMEOUT ||
416                 code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
417                 code == PJSIP_SC_BAD_GATEWAY ||
418                 code == PJSIP_SC_SERVICE_UNAVAILABLE ||
419                 code == PJSIP_SC_SERVER_TIMEOUT ||
420                 ((code == PJSIP_SC_UNAUTHORIZED ||
421                   code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
422                  !client_state->auth_rejection_permanent) ||
423                 PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
424                 return 1;
425         } else {
426                 return 0;
427         }
428 }
429
430 static void schedule_retry(struct registration_response *response, unsigned int interval,
431                            const char *server_uri, const char *client_uri)
432 {
433         response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
434         schedule_registration(response->client_state, interval);
435
436         if (response->rdata) {
437                 ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
438                         "registration attempt to '%s', retrying in '%u'\n",
439                         response->code, server_uri, client_uri, interval);
440         } else {
441                 ast_log(LOG_WARNING, "No response received from '%s' on "
442                         "registration attempt to '%s', retrying in '%u'\n",
443                         server_uri, client_uri, interval);
444         }
445 }
446
447 /*! \brief Callback function for handling a response to a registration attempt */
448 static int handle_registration_response(void *data)
449 {
450         RAII_VAR(struct registration_response *, response, data, ao2_cleanup);
451         pjsip_regc_info info;
452         char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
453
454         if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
455                 return 0;
456         }
457
458         pjsip_regc_get_info(response->client_state->client, &info);
459         ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
460         ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
461
462         if (response->code == 401 || response->code == 407) {
463                 pjsip_tx_data *tdata;
464                 if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
465                                 response->rdata, response->tsx, &tdata)) {
466                         ao2_ref(response->client_state, +1);
467                         if (pjsip_regc_send(response->client_state->client, tdata) != PJ_SUCCESS) {
468                                 ao2_cleanup(response->client_state);
469                         }
470                         return 0;
471                 }
472                 /* Otherwise, fall through so the failure is processed appropriately */
473         }
474
475         if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
476                 /* Check if this is in regards to registering or unregistering */
477                 if (response->expiration) {
478                         /* If the registration went fine simply reschedule registration for the future */
479                         ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
480                         response->client_state->status = SIP_REGISTRATION_REGISTERED;
481                         response->client_state->retries = 0;
482                         schedule_registration(response->client_state, response->expiration - REREGISTER_BUFFER_TIME);
483                 } else {
484                         ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
485                         response->client_state->status = SIP_REGISTRATION_UNREGISTERED;
486                 }
487         } else if (response->retry_after) {
488                 /* If we have been instructed to retry after a period of time, schedule it as such */
489                 schedule_retry(response, response->retry_after, server_uri, client_uri);
490         } else if (response->client_state->retry_interval && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
491                 if (response->client_state->retries == response->client_state->max_retries) {
492                         /* If we received enough temporal responses to exceed our maximum give up permanently */
493                         response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
494                         ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
495                                 server_uri, client_uri);
496                 } else {
497                         /* On the other hand if we can still try some more do so */
498                         response->client_state->retries++;
499                         schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
500                 }
501         } else {
502                 if (response->code == 403
503                         && response->client_state->forbidden_retry_interval
504                         && response->client_state->retries < response->client_state->max_retries) {
505                         /* A forbidden response retry interval is configured and there are retries remaining */
506                         response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
507                         response->client_state->retries++;
508                         schedule_registration(response->client_state, response->client_state->forbidden_retry_interval);
509                         ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
510                                 server_uri, client_uri, response->client_state->forbidden_retry_interval);
511                 } else {
512                         /* Finally if there's no hope of registering give up */
513                         response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
514                         if (response->rdata) {
515                                 ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
516                                         response->code, server_uri, client_uri);
517                         } else {
518                                 ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
519                         }
520                 }
521         }
522
523         ast_system_publish_registry("PJSIP", client_uri, server_uri, sip_outbound_registration_status_str[response->client_state->status], NULL);
524
525         /* If deferred destruction is in use see if we need to destroy now */
526         if (response->client_state->destroy) {
527                 handle_client_state_destruction(response->client_state);
528         }
529
530         return 0;
531 }
532
533 /*! \brief Callback function for outbound registration client */
534 static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
535 {
536         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, param->token, ao2_cleanup);
537         struct registration_response *response = ao2_alloc(sizeof(*response), registration_response_destroy);
538
539         response->code = param->code;
540         response->expiration = param->expiration;
541         response->client_state = client_state;
542         ao2_ref(response->client_state, +1);
543
544         if (param->rdata) {
545                 struct pjsip_retry_after_hdr *retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER, NULL);
546
547                 response->retry_after = retry_after ? retry_after->ivalue : 0;
548                 response->tsx = pjsip_rdata_get_tsx(param->rdata);
549                 pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
550         }
551
552         if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
553                 ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
554                 ao2_cleanup(response);
555         }
556 }
557
558 /*! \brief Destructor function for registration state */
559 static void sip_outbound_registration_state_destroy(void *obj)
560 {
561         struct sip_outbound_registration_state *state = obj;
562
563         if (!state->client_state) {
564                 return;
565         }
566
567         if (state->client_state->serializer && ast_sip_push_task(state->client_state->serializer, handle_client_state_destruction, state->client_state)) {
568                 ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
569                 ao2_ref(state->client_state, -1);
570         }
571 }
572
573 /*! \brief Destructor function for client registration state */
574 static void sip_outbound_registration_client_state_destroy(void *obj)
575 {
576         struct sip_outbound_registration_client_state *client_state = obj;
577
578         ast_taskprocessor_unreference(client_state->serializer);
579 }
580
581 /*! \brief Allocator function for registration state */
582 static struct sip_outbound_registration_state *sip_outbound_registration_state_alloc(void)
583 {
584         struct sip_outbound_registration_state *state = ao2_alloc(sizeof(*state), sip_outbound_registration_state_destroy);
585
586         if (!state || !(state->client_state = ao2_alloc(sizeof(*state->client_state), sip_outbound_registration_client_state_destroy))) {
587                 ao2_cleanup(state);
588                 return NULL;
589         }
590
591         if (!(state->client_state->serializer = ast_sip_create_serializer())) {
592                 ao2_cleanup(state->client_state);
593                 ao2_cleanup(state);
594                 return NULL;
595         }
596
597         state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
598         state->client_state->timer.user_data = state->client_state;
599         state->client_state->timer.cb = sip_outbound_registration_timer_cb;
600
601         return state;
602 }
603
604 /*! \brief Destructor function for registration information */
605 static void sip_outbound_registration_destroy(void *obj)
606 {
607         struct sip_outbound_registration *registration = obj;
608
609         ao2_cleanup(registration->state);
610         ast_sip_auth_vector_destroy(&registration->outbound_auths);
611
612         ast_string_field_free_memory(registration);
613 }
614
615 /*! \brief Allocator function for registration information */
616 static void *sip_outbound_registration_alloc(const char *name)
617 {
618         struct sip_outbound_registration *registration = ast_sorcery_generic_alloc(sizeof(*registration), sip_outbound_registration_destroy);
619
620         if (!registration || ast_string_field_init(registration, 256)) {
621                 ao2_cleanup(registration);
622                 return NULL;
623         }
624
625         return registration;
626 }
627
628 /*! \brief Helper function which populates a pj_str_t with a contact header */
629 static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user, const pj_str_t *target, pjsip_tpselector *selector)
630 {
631         pj_str_t tmp, local_addr;
632         pjsip_uri *uri;
633         pjsip_sip_uri *sip_uri;
634         pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
635         int local_port;
636
637         pj_strdup_with_null(pool, &tmp, target);
638
639         if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
640             (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
641                 return -1;
642         }
643
644         sip_uri = pjsip_uri_get_uri(uri);
645
646         if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
647                 type = PJSIP_TRANSPORT_TLS;
648         } else if (!sip_uri->transport_param.slen) {
649                 type = PJSIP_TRANSPORT_UDP;
650         } else {
651                 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
652         }
653
654         if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
655                 return -1;
656         }
657
658         if (pj_strchr(&sip_uri->host, ':')) {
659                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
660         }
661
662         if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
663                                                               &local_addr, &local_port) != PJ_SUCCESS) {
664                 return -1;
665         }
666
667         if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
668                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
669         }
670
671         contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
672         contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
673                                       "<%s:%s@%s%.*s%s:%d%s%s>",
674                                       (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
675                                       user,
676                                       (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
677                                       (int)local_addr.slen,
678                                       local_addr.ptr,
679                                       (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
680                                       local_port,
681                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
682                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
683
684         return 0;
685 }
686
687 /*!
688  * \internal
689  * \brief Check if a registration can be reused
690  *
691  * This checks if the existing outbound registration's configuration differs from a newly-applied
692  * outbound registration to see if the applied one.
693  *
694  * \param existing The pre-existing outbound registration
695  * \param applied The newly-created registration
696  */
697 static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
698 {
699         int i;
700
701         if (strcmp(existing->server_uri, applied->server_uri) || strcmp(existing->client_uri, applied->client_uri) ||
702                 strcmp(existing->transport, applied->transport) || strcmp(existing->contact_user, applied->contact_user) ||
703                 strcmp(existing->outbound_proxy, applied->outbound_proxy) ||
704                 AST_VECTOR_SIZE(&existing->outbound_auths) != AST_VECTOR_SIZE(&applied->outbound_auths) ||
705                 existing->auth_rejection_permanent != applied->auth_rejection_permanent) {
706                 return 0;
707         }
708
709         for (i = 0; i < AST_VECTOR_SIZE(&existing->outbound_auths); ++i) {
710                 if (strcmp(AST_VECTOR_GET(&existing->outbound_auths, i), AST_VECTOR_GET(&applied->outbound_auths, i))) {
711                         return 0;
712                 }
713         }
714
715         return 1;
716 }
717
718 /*! \brief Helper function that allocates a pjsip registration client and configures it */
719 static int sip_outbound_registration_regc_alloc(void *data)
720 {
721         struct sip_outbound_registration *registration = data;
722         pj_pool_t *pool;
723         pj_str_t tmp;
724         pjsip_uri *uri;
725         pj_str_t server_uri, client_uri, contact_uri;
726         pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
727
728         pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
729         if (!pool) {
730                 ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
731                         ast_sorcery_object_get_id(registration));
732                 return -1;
733         }
734
735         pj_strdup2_with_null(pool, &tmp, registration->server_uri);
736         uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
737         if (!uri) {
738                 ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
739                         registration->server_uri, ast_sorcery_object_get_id(registration));
740                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
741                 return -1;
742         }
743
744         pj_strdup2_with_null(pool, &tmp, registration->client_uri);
745         uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
746         if (!uri) {
747                 ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
748                         registration->client_uri, ast_sorcery_object_get_id(registration));
749                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
750                 return -1;
751         }
752
753         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
754
755         if (!ast_strlen_zero(registration->transport)) {
756                 RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", registration->transport), ao2_cleanup);
757
758                 if (!transport || !transport->state) {
759                         ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' "
760                                 " for outbound registration", registration->transport);
761                         return -1;
762                 }
763
764                 if (transport->state->transport) {
765                         selector.type = PJSIP_TPSELECTOR_TRANSPORT;
766                         selector.u.transport = transport->state->transport;
767                 } else if (transport->state->factory) {
768                         selector.type = PJSIP_TPSELECTOR_LISTENER;
769                         selector.u.listener = transport->state->factory;
770                 } else {
771                         return -1;
772                 }
773         }
774
775         if (!registration->state->client_state->client &&
776                 pjsip_regc_create(ast_sip_get_pjsip_endpoint(), registration->state->client_state, sip_outbound_registration_response_cb,
777                 &registration->state->client_state->client) != PJ_SUCCESS) {
778                 return -1;
779         }
780
781         pjsip_regc_set_transport(registration->state->client_state->client, &selector);
782
783         if (!ast_strlen_zero(registration->outbound_proxy)) {
784                 pjsip_route_hdr route_set, *route;
785                 static const pj_str_t ROUTE_HNAME = { "Route", 5 };
786                 pj_str_t tmp;
787
788                 pj_list_init(&route_set);
789
790                 pj_strdup2_with_null(pjsip_regc_get_pool(registration->state->client_state->client), &tmp, registration->outbound_proxy);
791                 if (!(route = pjsip_parse_hdr(pjsip_regc_get_pool(registration->state->client_state->client), &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
792                         return -1;
793                 }
794                 pj_list_insert_nodes_before(&route_set, route);
795
796                 pjsip_regc_set_route_set(registration->state->client_state->client, &route_set);
797         }
798
799         pj_cstr(&server_uri, registration->server_uri);
800
801         if (sip_dialog_create_contact(pjsip_regc_get_pool(registration->state->client_state->client), &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector)) {
802                 return -1;
803         }
804
805         pj_cstr(&client_uri, registration->client_uri);
806
807         if (pjsip_regc_init(registration->state->client_state->client, &server_uri, &client_uri, &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
808                 return -1;
809         }
810
811         return 0;
812 }
813
814 /*! \brief Apply function which finds or allocates a state structure */
815 static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
816 {
817         RAII_VAR(struct sip_outbound_registration *, existing, ast_sorcery_retrieve_by_id(sorcery, "registration", ast_sorcery_object_get_id(obj)), ao2_cleanup);
818         struct sip_outbound_registration *applied = obj;
819
820         if (ast_strlen_zero(applied->server_uri)) {
821                 ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'",
822                         ast_sorcery_object_get_id(applied));
823                 return -1;
824         } else if (ast_strlen_zero(applied->client_uri)) {
825                 ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
826                         ast_sorcery_object_get_id(applied));
827                 return -1;
828         }
829
830         if (!existing) {
831                 /* If no existing registration exists we can just start fresh easily */
832                 applied->state = sip_outbound_registration_state_alloc();
833         } else {
834                 /* If there is an existing registration things are more complicated, we can immediately reuse this state if most stuff remains unchanged */
835                 if (can_reuse_registration(existing, applied)) {
836                         applied->state = existing->state;
837                         ao2_ref(applied->state, +1);
838                         return 0;
839                 }
840                 applied->state = sip_outbound_registration_state_alloc();
841         }
842
843         if (!applied->state) {
844                 return -1;
845         }
846
847         return ast_sip_push_task_synchronous(NULL, sip_outbound_registration_regc_alloc, applied);
848 }
849
850 /*! \brief Helper function which performs a single registration */
851 static int sip_outbound_registration_perform(void *data)
852 {
853         RAII_VAR(struct sip_outbound_registration *, registration, data, ao2_cleanup);
854         size_t i;
855
856         /* Just in case the client state is being reused for this registration, free the auth information */
857         ast_sip_auth_vector_destroy(&registration->state->client_state->outbound_auths);
858
859         AST_VECTOR_INIT(&registration->state->client_state->outbound_auths, AST_VECTOR_SIZE(&registration->outbound_auths));
860         for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
861                 const char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
862                 AST_VECTOR_APPEND(&registration->state->client_state->outbound_auths, name);
863         }
864         registration->state->client_state->retry_interval = registration->retry_interval;
865         registration->state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
866         registration->state->client_state->max_retries = registration->max_retries;
867         registration->state->client_state->retries = 0;
868         registration->state->client_state->support_path = registration->support_path;
869         registration->state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
870
871         pjsip_regc_update_expires(registration->state->client_state->client, registration->expiration);
872
873         schedule_registration(registration->state->client_state, (ast_random() % 10) + 1);
874
875         return 0;
876 }
877
878 /*! \brief Helper function which performs all registrations */
879 static void sip_outbound_registration_perform_all(void)
880 {
881         RAII_VAR(struct ao2_container *, registrations, ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL), ao2_cleanup);
882         struct ao2_iterator i;
883         struct sip_outbound_registration *registration;
884
885         if (!registrations) {
886                 return;
887         }
888
889         i = ao2_iterator_init(registrations, 0);
890         while ((registration = ao2_iterator_next(&i))) {
891                 if (ast_sip_push_task(registration->state->client_state->serializer, sip_outbound_registration_perform, registration)) {
892                         ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", ast_sorcery_object_get_id(registration));
893                         ao2_ref(registration, -1);
894                 }
895         }
896         ao2_iterator_destroy(&i);
897 }
898
899 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
900 {
901         struct sip_outbound_registration *registration = obj;
902
903         return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
904 }
905
906 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
907 {
908         const struct sip_outbound_registration *registration = obj;
909
910         return ast_sip_auths_to_str(&registration->outbound_auths, buf);
911 }
912
913 static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
914 {
915         const struct sip_outbound_registration *registration = obj;
916         int i;
917         struct ast_variable *head = NULL;
918
919         for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
920                 ast_variable_list_append(&head, ast_variable_new("outbound_auth",
921                         AST_VECTOR_GET(&registration->outbound_auths, i), ""));
922         }
923
924         if (head) {
925                 *fields = head;
926         }
927
928         return 0;
929 }
930
931 static struct sip_outbound_registration *retrieve_registration(const char *registration_name)
932 {
933         return ast_sorcery_retrieve_by_id(
934                 ast_sip_get_sorcery(),
935                 "registration",
936                 registration_name);
937 }
938
939 static int unregister_task(void *obj)
940 {
941         RAII_VAR(struct sip_outbound_registration*, registration, obj, ao2_cleanup);
942         struct pjsip_regc *client = registration->state->client_state->client;
943         pjsip_tx_data *tdata;
944
945         if (pjsip_regc_unregister(client, &tdata) != PJ_SUCCESS) {
946                 return 0;
947         }
948
949         ao2_ref(registration->state->client_state, +1);
950         if (pjsip_regc_send(client, tdata) != PJ_SUCCESS) {
951                 ao2_cleanup(registration->state->client_state);
952         }
953
954         return 0;
955 }
956
957 static int queue_unregister(struct sip_outbound_registration *registration)
958 {
959         ao2_ref(registration, +1);
960         if (ast_sip_push_task(registration->state->client_state->serializer, unregister_task, registration)) {
961                 ao2_cleanup(registration);
962                 return -1;
963         }
964         return 0;
965 }
966
967 static char *cli_complete_registration(const char *line, const char *word,
968 int pos, int state)
969 {
970         char *result = NULL;
971         int wordlen;
972         int which = 0;
973         struct sip_outbound_registration *registration;
974         RAII_VAR(struct ao2_container *, registrations, NULL, ao2_cleanup);
975         struct ao2_iterator i;
976
977         if (pos != 3) {
978                 return NULL;
979         }
980
981         wordlen = strlen(word);
982         registrations = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
983                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
984         if (!registrations) {
985                 return NULL;
986         }
987
988         i = ao2_iterator_init(registrations, 0);
989         while ((registration = ao2_iterator_next(&i))) {
990                 const char *name = ast_sorcery_object_get_id(registration);
991                 if (!strncasecmp(word, name, wordlen) && ++which > state) {
992                         result = ast_strdup(name);
993                 }
994
995                 ao2_cleanup(registration);
996                 if (result) {
997                         break;
998                 }
999         }
1000         ao2_iterator_destroy(&i);
1001         return result;
1002 }
1003
1004 static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1005 {
1006         RAII_VAR(struct sip_outbound_registration *, registration, NULL, ao2_cleanup);
1007         const char *registration_name;
1008
1009         switch (cmd) {
1010         case CLI_INIT:
1011                 e->command = "pjsip send unregister";
1012                 e->usage =
1013                         "Usage: pjsip send unregister <registration>\n"
1014                         "       Send a SIP REGISTER request to the specified outbound "
1015                         "registration with an expiration of 0. This will cause the contact "
1016                         "added by this registration to be removed on the remote system. Note: "
1017                         "The specified outbound registration will attempt to re-register "
1018                         "according to its last registration expiration.\n";
1019                 return NULL;
1020         case CLI_GENERATE:
1021                 return cli_complete_registration(a->line, a->word, a->pos, a->n);
1022         }
1023
1024         if (a->argc != 4) {
1025                 return CLI_SHOWUSAGE;
1026         }
1027
1028         registration_name = a->argv[3];
1029
1030         registration = retrieve_registration(registration_name);
1031         if (!registration) {
1032                 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
1033                 return CLI_FAILURE;
1034         }
1035
1036         if (queue_unregister(registration)) {
1037                 ast_cli(a->fd, "Failed to queue unregistration");
1038                 return 0;
1039         }
1040
1041         return CLI_SUCCESS;
1042 }
1043
1044 static int ami_unregister(struct mansession *s, const struct message *m)
1045 {
1046         const char *registration_name = astman_get_header(m, "Registration");
1047         RAII_VAR(struct sip_outbound_registration *, registration, NULL, ao2_cleanup);
1048
1049         if (ast_strlen_zero(registration_name)) {
1050                 astman_send_error(s, m, "Registration parameter missing.");
1051                 return 0;
1052         }
1053
1054         registration = retrieve_registration(registration_name);
1055         if (!registration) {
1056                 astman_send_error(s, m, "Unable to retrieve registration entry\n");
1057                 return 0;
1058         }
1059
1060
1061         if (queue_unregister(registration)) {
1062                 astman_send_ack(s, m, "Failed to queue unregistration");
1063                 return 0;
1064         }
1065
1066         astman_send_ack(s, m, "Unregistration sent");
1067         return 0;
1068 }
1069
1070 struct sip_ami_outbound {
1071         struct ast_sip_ami *ami;
1072         int registered;
1073         int not_registered;
1074         struct sip_outbound_registration *registration;
1075 };
1076
1077 static int ami_outbound_registration_task(void *obj)
1078 {
1079         struct sip_ami_outbound *ami = obj;
1080         RAII_VAR(struct ast_str *, buf,
1081                  ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami), ast_free);
1082
1083         if (!buf) {
1084                 return -1;
1085         }
1086
1087         ast_sip_sorcery_object_to_ami(ami->registration, &buf);
1088
1089         if (ami->registration->state) {
1090                 pjsip_regc_info info;
1091                 if (ami->registration->state->client_state->status ==
1092                     SIP_REGISTRATION_REGISTERED) {
1093                         ++ami->registered;
1094                 } else {
1095                         ++ami->not_registered;
1096                 }
1097
1098                 ast_str_append(&buf, 0, "Status: %s%s",
1099                                sip_outbound_registration_status_str[
1100                                        ami->registration->state->client_state->status], "\r\n");
1101
1102                 pjsip_regc_get_info(ami->registration->state->client_state->client, &info);
1103                 ast_str_append(&buf, 0, "NextReg: %d%s", info.next_reg, "\r\n");
1104         }
1105
1106         astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
1107         return ast_sip_format_auths_ami(&ami->registration->outbound_auths, ami->ami);
1108 }
1109
1110 static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
1111 {
1112         struct sip_ami_outbound *ami = arg;
1113
1114         ami->registration = obj;
1115         return ast_sip_push_task_synchronous(
1116                 NULL, ami_outbound_registration_task, ami);
1117 }
1118
1119 static int ami_show_outbound_registrations(struct mansession *s,
1120                                            const struct message *m)
1121 {
1122         struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
1123         struct sip_ami_outbound ami_outbound = { .ami = &ami };
1124         RAII_VAR(struct ao2_container *, regs, ast_sorcery_retrieve_by_fields(
1125                          ast_sip_get_sorcery(), "registration", AST_RETRIEVE_FLAG_MULTIPLE |
1126                          AST_RETRIEVE_FLAG_ALL, NULL), ao2_cleanup);
1127
1128         if (!regs) {
1129                 astman_send_error(s, m, "Unable to retreive "
1130                                   "outbound registrations\n");
1131                 return -1;
1132         }
1133
1134         astman_send_listack(s, m, "Following are Events for each Outbound "
1135                             "registration", "start");
1136
1137         ao2_callback(regs, OBJ_NODATA, ami_outbound_registration_detail, &ami_outbound);
1138
1139         astman_append(s, "Event: OutboundRegistrationDetailComplete\r\n");
1140         if (!ast_strlen_zero(ami.action_id)) {
1141                 astman_append(s, "ActionID: %s\r\n", ami.action_id);
1142         }
1143         astman_append(s, "EventList: Complete\r\n"
1144                       "Registered: %d\r\n"
1145                       "NotRegistered: %d\r\n\r\n",
1146                       ami_outbound.registered,
1147                       ami_outbound.not_registered);
1148         return 0;
1149 }
1150
1151 static struct ao2_container *cli_get_container(void)
1152 {
1153         RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
1154         struct ao2_container *s_container;
1155
1156         container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
1157                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1158         if (!container) {
1159                 return NULL;
1160         }
1161
1162         s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
1163                 ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
1164         if (!s_container) {
1165                 return NULL;
1166         }
1167
1168         if (ao2_container_dup(s_container, container, 0)) {
1169                 ao2_ref(s_container, -1);
1170                 return NULL;
1171         }
1172
1173         return s_container;
1174 }
1175
1176 static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
1177 {
1178         ao2_callback(container, OBJ_NODATA, callback, args);
1179
1180         return 0;
1181 }
1182
1183 static void *cli_retrieve_by_id(const char *id)
1184 {
1185         return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
1186 }
1187
1188 static int cli_print_header(void *obj, void *arg, int flags)
1189 {
1190         struct ast_sip_cli_context *context = arg;
1191
1192         ast_assert(context->output_buffer != NULL);
1193
1194         ast_str_append(&context->output_buffer, 0,
1195                 " <Registration/ServerURI..............................>  <Auth..........>  <Status.......>\n");
1196
1197         return 0;
1198 }
1199
1200 static int cli_print_body(void *obj, void *arg, int flags)
1201 {
1202         struct sip_outbound_registration *registration = obj;
1203         struct ast_sip_cli_context *context = arg;
1204         const char *id = ast_sorcery_object_get_id(registration);
1205 #define REGISTRATION_URI_FIELD_LEN      53
1206
1207         ast_assert(context->output_buffer != NULL);
1208
1209         ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s  %-16s  %-16s\n",
1210                 id,
1211                 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
1212                 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
1213                 registration->server_uri,
1214                 AST_VECTOR_SIZE(&registration->outbound_auths)
1215                         ? AST_VECTOR_GET(&registration->outbound_auths, 0)
1216                         : "n/a",
1217                 sip_outbound_registration_status_str[registration->state->client_state->status]);
1218
1219         if (context->show_details
1220                 || (context->show_details_only_level_0 && context->indent_level == 0)) {
1221                 ast_str_append(&context->output_buffer, 0, "\n");
1222                 ast_sip_cli_print_sorcery_objectset(registration, context, 0);
1223         }
1224
1225         return 0;
1226 }
1227
1228 /*
1229  * A function pointer to callback needs to be within the
1230  * module in order to avoid problems with an undefined
1231  * symbol when the module is loaded.
1232  */
1233 static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1234 {
1235         return ast_sip_cli_traverse_objects(e, cmd, a);
1236 }
1237
1238 static struct ast_cli_entry cli_outbound_registration[] = {
1239         AST_CLI_DEFINE(cli_unregister, "Send a REGISTER request to an outbound registration target with a expiration of 0"),
1240         AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
1241                 .command = "pjsip list registrations",
1242                 .usage = "Usage: pjsip list registrations\n"
1243                                  "       List the configured PJSIP Registrations\n"),
1244         AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
1245                 .command = "pjsip show registrations",
1246                 .usage = "Usage: pjsip show registrations\n"
1247                                  "       Show the configured PJSIP Registrations\n"),
1248         AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
1249                 .command = "pjsip show registration",
1250                 .usage = "Usage: pjsip show registration <id>\n"
1251                                  "       Show the configured PJSIP Registration\n"),
1252 };
1253
1254 static struct ast_sip_cli_formatter_entry *cli_formatter;
1255
1256 static int load_module(void)
1257 {
1258         CHECK_PJSIP_MODULE_LOADED();
1259
1260         ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
1261
1262         if (ast_sorcery_object_register(ast_sip_get_sorcery(), "registration", sip_outbound_registration_alloc, NULL, sip_outbound_registration_apply)) {
1263                 return AST_MODULE_LOAD_DECLINE;
1264         }
1265
1266         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
1267         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, server_uri));
1268         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
1269         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
1270         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
1271         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
1272         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
1273         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
1274         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));
1275         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
1276         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));
1277         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);
1278         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
1279         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
1280         sip_outbound_registration_perform_all();
1281
1282         ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
1283         ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations);
1284
1285         cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1286         if (!cli_formatter) {
1287                 ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
1288                 return -1;
1289         }
1290         cli_formatter->name = "registration";
1291         cli_formatter->print_header = cli_print_header;
1292         cli_formatter->print_body = cli_print_body;
1293         cli_formatter->get_container = cli_get_container;
1294         cli_formatter->iterate = cli_iterator;
1295         cli_formatter->get_id = ast_sorcery_object_get_id;
1296         cli_formatter->retrieve_by_id = cli_retrieve_by_id;
1297
1298         ast_sip_register_cli_formatter(cli_formatter);
1299         ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1300
1301         return AST_MODULE_LOAD_SUCCESS;
1302 }
1303
1304 static int reload_module(void)
1305 {
1306         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
1307         sip_outbound_registration_perform_all();
1308         return 0;
1309 }
1310
1311 static int unload_module(void)
1312 {
1313         ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1314         ast_sip_unregister_cli_formatter(cli_formatter);
1315         ast_manager_unregister("PJSIPShowRegistrationsOutbound");
1316         ast_manager_unregister("PJSIPUnregister");
1317
1318         return 0;
1319 }
1320
1321 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
1322                 .support_level = AST_MODULE_SUPPORT_CORE,
1323                 .load = load_module,
1324                 .reload = reload_module,
1325                 .unload = unload_module,
1326                 .load_pri = AST_MODPRI_APP_DEPEND,
1327                );