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