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