res_pjsip_outbound_registration: Create registration client in pj thread.
[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         pjsip_regc_info info;
311
312         cancel_registration(client_state);
313
314         pjsip_regc_get_info(client_state->client, &info);
315
316         if (info.is_busy == PJ_TRUE) {
317                 /* If a client transaction is in progress we defer until it is complete */
318                 client_state->destroy = 1;
319                 return 0;
320         }
321
322         if (client_state->status != SIP_REGISTRATION_UNREGISTERED && client_state->status != SIP_REGISTRATION_REJECTED_PERMANENT) {
323                 pjsip_tx_data *tdata;
324
325                 if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS) {
326                         pjsip_regc_send(client_state->client, tdata);
327                 }
328         }
329
330         pjsip_regc_destroy(client_state->client);
331
332         client_state->status = SIP_REGISTRATION_STOPPED;
333         ast_sip_auth_vector_destroy(&client_state->outbound_auths);
334
335         return 0;
336 }
337
338 /*! \brief Structure for registration response */
339 struct registration_response {
340         /*! \brief Response code for the registration attempt */
341         int code;
342         /*! \brief Expiration time for registration */
343         int expiration;
344         /*! \brief Retry-After value */
345         int retry_after;
346         /*! \brief Outbound registration client state */
347         struct sip_outbound_registration_client_state *client_state;
348         /*! \brief The response message */
349         pjsip_rx_data *rdata;
350         /*! \brief The response transaction */
351         pjsip_transaction *tsx;
352 };
353
354 /*! \brief Registration response structure destructor */
355 static void registration_response_destroy(void *obj)
356 {
357         struct registration_response *response = obj;
358
359         if (response->rdata) {
360                 pjsip_rx_data_free_cloned(response->rdata);
361         }
362
363         ao2_cleanup(response->client_state);
364 }
365
366 /* \brief Helper funtion which determines if a response code is temporal or not */
367 static int sip_outbound_registration_is_temporal(unsigned int code,
368                 struct sip_outbound_registration_client_state *client_state)
369 {
370         /* Shamelessly taken from pjsua */
371         if (code == PJSIP_SC_REQUEST_TIMEOUT ||
372                 code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
373                 code == PJSIP_SC_BAD_GATEWAY ||
374                 code == PJSIP_SC_SERVICE_UNAVAILABLE ||
375                 code == PJSIP_SC_SERVER_TIMEOUT ||
376                 ((code == PJSIP_SC_UNAUTHORIZED ||
377                   code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
378                  !client_state->auth_rejection_permanent) ||
379                 PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
380                 return 1;
381         } else {
382                 return 0;
383         }
384 }
385
386 static void schedule_retry(struct registration_response *response, unsigned int interval,
387                            const char *server_uri, const char *client_uri)
388 {
389         response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
390         schedule_registration(response->client_state, interval);
391
392         if (response->rdata) {
393                 ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
394                         "registration attempt to '%s', retrying in '%d'\n",
395                         response->code, server_uri, client_uri, interval);
396         } else {
397                 ast_log(LOG_WARNING, "No response received from '%s' on "
398                         "registration attempt to '%s', retrying in '%d'\n",
399                         server_uri, client_uri, interval);
400         }
401 }
402
403 /*! \brief Callback function for handling a response to a registration attempt */
404 static int handle_registration_response(void *data)
405 {
406         RAII_VAR(struct registration_response *, response, data, ao2_cleanup);
407         pjsip_regc_info info;
408         char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
409
410         if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
411                 return 0;
412         }
413
414         pjsip_regc_get_info(response->client_state->client, &info);
415         ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
416         ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
417
418         if (response->code == 401 || response->code == 407) {
419                 pjsip_tx_data *tdata;
420                 if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
421                                 response->rdata, response->tsx, &tdata)) {
422                         ao2_ref(response->client_state, +1);
423                         if (pjsip_regc_send(response->client_state->client, tdata) != PJ_SUCCESS) {
424                                 ao2_cleanup(response->client_state);
425                         }
426                         return 0;
427                 }
428                 /* Otherwise, fall through so the failure is processed appropriately */
429         }
430
431         if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
432                 /* If the registration went fine simply reschedule registration for the future */
433                 ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
434                 response->client_state->status = SIP_REGISTRATION_REGISTERED;
435                 response->client_state->retries = 0;
436                 schedule_registration(response->client_state, response->expiration - REREGISTER_BUFFER_TIME);
437         } else if (response->retry_after) {
438                 /* If we have been instructed to retry after a period of time, schedule it as such */
439                 schedule_retry(response, response->retry_after, server_uri, client_uri);
440         } else if (response->client_state->retry_interval && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
441                 if (response->client_state->retries == response->client_state->max_retries) {
442                         /* If we received enough temporal responses to exceed our maximum give up permanently */
443                         response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
444                         ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
445                                 server_uri, client_uri);
446                 } else {
447                         /* On the other hand if we can still try some more do so */
448                         response->client_state->retries++;
449                         schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
450                 }
451         } else {
452                 if (response->code == 403
453                         && response->client_state->forbidden_retry_interval
454                         && response->client_state->retries < response->client_state->max_retries) {
455                         /* A forbidden response retry interval is configured and there are retries remaining */
456                         response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
457                         response->client_state->retries++;
458                         schedule_registration(response->client_state, response->client_state->forbidden_retry_interval);
459                         ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%d' seconds\n",
460                                 server_uri, client_uri, response->client_state->forbidden_retry_interval);
461                 } else {
462                         /* Finally if there's no hope of registering give up */
463                         response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
464                         if (response->rdata) {
465                                 ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
466                                         response->code, server_uri, client_uri);
467                         } else {
468                                 ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
469                         }
470                 }
471         }
472
473         ast_system_publish_registry("PJSIP", client_uri, server_uri, sip_outbound_registration_status_str[response->client_state->status], NULL);
474
475         /* If deferred destruction is in use see if we need to destroy now */
476         if (response->client_state->destroy) {
477                 handle_client_state_destruction(response->client_state);
478         }
479
480         return 0;
481 }
482
483 /*! \brief Callback function for outbound registration client */
484 static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
485 {
486         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, param->token, ao2_cleanup);
487         struct registration_response *response = ao2_alloc(sizeof(*response), registration_response_destroy);
488
489         response->code = param->code;
490         response->expiration = param->expiration;
491         response->client_state = client_state;
492         ao2_ref(response->client_state, +1);
493
494         if (param->rdata) {
495                 struct pjsip_retry_after_hdr *retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER, NULL);
496
497                 response->retry_after = retry_after ? retry_after->ivalue : 0;
498                 response->tsx = pjsip_rdata_get_tsx(param->rdata);
499                 pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
500         }
501
502         if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
503                 ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
504                 ao2_cleanup(response);
505         }
506 }
507
508 /*! \brief Destructor function for registration state */
509 static void sip_outbound_registration_state_destroy(void *obj)
510 {
511         struct sip_outbound_registration_state *state = obj;
512
513         if (!state->client_state) {
514                 return;
515         }
516
517         if (state->client_state->serializer && ast_sip_push_task(state->client_state->serializer, handle_client_state_destruction, state->client_state)) {
518                 ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
519                 ao2_ref(state->client_state, -1);
520         }
521 }
522
523 /*! \brief Destructor function for client registration state */
524 static void sip_outbound_registration_client_state_destroy(void *obj)
525 {
526         struct sip_outbound_registration_client_state *client_state = obj;
527
528         ast_taskprocessor_unreference(client_state->serializer);
529 }
530
531 /*! \brief Allocator function for registration state */
532 static struct sip_outbound_registration_state *sip_outbound_registration_state_alloc(void)
533 {
534         struct sip_outbound_registration_state *state = ao2_alloc(sizeof(*state), sip_outbound_registration_state_destroy);
535
536         if (!state || !(state->client_state = ao2_alloc(sizeof(*state->client_state), sip_outbound_registration_client_state_destroy))) {
537                 ao2_cleanup(state);
538                 return NULL;
539         }
540
541         if (!(state->client_state->serializer = ast_sip_create_serializer())) {
542                 ao2_cleanup(state->client_state);
543                 ao2_cleanup(state);
544                 return NULL;
545         }
546
547         state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
548         state->client_state->timer.user_data = state->client_state;
549         state->client_state->timer.cb = sip_outbound_registration_timer_cb;
550
551         return state;
552 }
553
554 /*! \brief Destructor function for registration information */
555 static void sip_outbound_registration_destroy(void *obj)
556 {
557         struct sip_outbound_registration *registration = obj;
558
559         ao2_cleanup(registration->state);
560         ast_sip_auth_vector_destroy(&registration->outbound_auths);
561
562         ast_string_field_free_memory(registration);
563 }
564
565 /*! \brief Allocator function for registration information */
566 static void *sip_outbound_registration_alloc(const char *name)
567 {
568         struct sip_outbound_registration *registration = ast_sorcery_generic_alloc(sizeof(*registration), sip_outbound_registration_destroy);
569
570         if (!registration || ast_string_field_init(registration, 256)) {
571                 ao2_cleanup(registration);
572                 return NULL;
573         }
574
575         return registration;
576 }
577
578 /*! \brief Helper function which populates a pj_str_t with a contact header */
579 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)
580 {
581         pj_str_t tmp, local_addr;
582         pjsip_uri *uri;
583         pjsip_sip_uri *sip_uri;
584         pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
585         int local_port;
586
587         pj_strdup_with_null(pool, &tmp, target);
588
589         if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
590             (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
591                 return -1;
592         }
593
594         sip_uri = pjsip_uri_get_uri(uri);
595
596         if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
597                 type = PJSIP_TRANSPORT_TLS;
598         } else if (!sip_uri->transport_param.slen) {
599                 type = PJSIP_TRANSPORT_UDP;
600         } else {
601                 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
602         }
603
604         if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
605                 return -1;
606         }
607
608         if (pj_strchr(&sip_uri->host, ':')) {
609                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
610         }
611
612         if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
613                                                               &local_addr, &local_port) != PJ_SUCCESS) {
614                 return -1;
615         }
616
617         if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
618                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
619         }
620
621         contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
622         contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
623                                       "<%s:%s@%s%.*s%s:%d%s%s>",
624                                       (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
625                                       user,
626                                       (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
627                                       (int)local_addr.slen,
628                                       local_addr.ptr,
629                                       (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
630                                       local_port,
631                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
632                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
633
634         return 0;
635 }
636
637 /*!
638  * \internal
639  * \brief Check if a registration can be reused
640  *
641  * This checks if the existing outbound registration's configuration differs from a newly-applied
642  * outbound registration to see if the applied one.
643  *
644  * \param existing The pre-existing outbound registration
645  * \param applied The newly-created registration
646  */
647 static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
648 {
649         int i;
650
651         if (strcmp(existing->server_uri, applied->server_uri) || strcmp(existing->client_uri, applied->client_uri) ||
652                 strcmp(existing->transport, applied->transport) || strcmp(existing->contact_user, applied->contact_user) ||
653                 strcmp(existing->outbound_proxy, applied->outbound_proxy) ||
654                 AST_VECTOR_SIZE(&existing->outbound_auths) != AST_VECTOR_SIZE(&applied->outbound_auths) ||
655                 existing->auth_rejection_permanent != applied->auth_rejection_permanent) {
656                 return 0;
657         }
658
659         for (i = 0; i < AST_VECTOR_SIZE(&existing->outbound_auths); ++i) {
660                 if (strcmp(AST_VECTOR_GET(&existing->outbound_auths, i), AST_VECTOR_GET(&applied->outbound_auths, i))) {
661                         return 0;
662                 }
663         }
664
665         return 1;
666 }
667
668 /*! \brief Helper function that allocates a pjsip registration client and configures it */
669 static int sip_outbound_registration_regc_alloc(void *data)
670 {
671         struct sip_outbound_registration *registration = data;
672         pj_pool_t *pool;
673         pj_str_t tmp;
674         pjsip_uri *uri;
675         pj_str_t server_uri, client_uri, contact_uri;
676         pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
677
678         pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
679         if (!pool) {
680                 ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
681                         ast_sorcery_object_get_id(registration));
682                 return -1;
683         }
684
685         pj_strdup2_with_null(pool, &tmp, registration->server_uri);
686         uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
687         if (!uri) {
688                 ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
689                         registration->server_uri, ast_sorcery_object_get_id(registration));
690                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
691                 return -1;
692         }
693
694         pj_strdup2_with_null(pool, &tmp, registration->client_uri);
695         uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
696         if (!uri) {
697                 ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
698                         registration->client_uri, ast_sorcery_object_get_id(registration));
699                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
700                 return -1;
701         }
702
703         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
704
705         if (!ast_strlen_zero(registration->transport)) {
706                 RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", registration->transport), ao2_cleanup);
707
708                 if (!transport || !transport->state) {
709                         ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' "
710                                 " for outbound registration", registration->transport);
711                         return -1;
712                 }
713
714                 if (transport->state->transport) {
715                         selector.type = PJSIP_TPSELECTOR_TRANSPORT;
716                         selector.u.transport = transport->state->transport;
717                 } else if (transport->state->factory) {
718                         selector.type = PJSIP_TPSELECTOR_LISTENER;
719                         selector.u.listener = transport->state->factory;
720                 } else {
721                         return -1;
722                 }
723         }
724
725         if (!registration->state->client_state->client &&
726                 pjsip_regc_create(ast_sip_get_pjsip_endpoint(), registration->state->client_state, sip_outbound_registration_response_cb,
727                 &registration->state->client_state->client) != PJ_SUCCESS) {
728                 return -1;
729         }
730
731         pjsip_regc_set_transport(registration->state->client_state->client, &selector);
732
733         if (!ast_strlen_zero(registration->outbound_proxy)) {
734                 pjsip_route_hdr route_set, *route;
735                 static const pj_str_t ROUTE_HNAME = { "Route", 5 };
736                 pj_str_t tmp;
737
738                 pj_list_init(&route_set);
739
740                 pj_strdup2_with_null(pjsip_regc_get_pool(registration->state->client_state->client), &tmp, registration->outbound_proxy);
741                 if (!(route = pjsip_parse_hdr(pjsip_regc_get_pool(registration->state->client_state->client), &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
742                         return -1;
743                 }
744                 pj_list_push_back(&route_set, route);
745
746                 pjsip_regc_set_route_set(registration->state->client_state->client, &route_set);
747         }
748
749         pj_cstr(&server_uri, registration->server_uri);
750
751         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)) {
752                 return -1;
753         }
754
755         pj_cstr(&client_uri, registration->client_uri);
756
757         if (pjsip_regc_init(registration->state->client_state->client, &server_uri, &client_uri, &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
758                 return -1;
759         }
760
761         return 0;
762 }
763
764 /*! \brief Apply function which finds or allocates a state structure */
765 static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
766 {
767         RAII_VAR(struct sip_outbound_registration *, existing, ast_sorcery_retrieve_by_id(sorcery, "registration", ast_sorcery_object_get_id(obj)), ao2_cleanup);
768         struct sip_outbound_registration *applied = obj;
769
770         if (ast_strlen_zero(applied->server_uri)) {
771                 ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'",
772                         ast_sorcery_object_get_id(applied));
773                 return -1;
774         } else if (ast_strlen_zero(applied->client_uri)) {
775                 ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
776                         ast_sorcery_object_get_id(applied));
777                 return -1;
778         }
779
780         if (!existing) {
781                 /* If no existing registration exists we can just start fresh easily */
782                 applied->state = sip_outbound_registration_state_alloc();
783         } else {
784                 /* If there is an existing registration things are more complicated, we can immediately reuse this state if most stuff remains unchanged */
785                 if (can_reuse_registration(existing, applied)) {
786                         applied->state = existing->state;
787                         ao2_ref(applied->state, +1);
788                         return 0;
789                 }
790                 applied->state = sip_outbound_registration_state_alloc();
791         }
792
793         if (!applied->state) {
794                 return -1;
795         }
796
797         return ast_sip_push_task_synchronous(NULL, sip_outbound_registration_regc_alloc, applied);
798 }
799
800 /*! \brief Helper function which performs a single registration */
801 static int sip_outbound_registration_perform(void *data)
802 {
803         RAII_VAR(struct sip_outbound_registration *, registration, data, ao2_cleanup);
804         size_t i;
805
806         /* Just in case the client state is being reused for this registration, free the auth information */
807         ast_sip_auth_vector_destroy(&registration->state->client_state->outbound_auths);
808
809         AST_VECTOR_INIT(&registration->state->client_state->outbound_auths, AST_VECTOR_SIZE(&registration->outbound_auths));
810         for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
811                 const char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
812                 AST_VECTOR_APPEND(&registration->state->client_state->outbound_auths, name);
813         }
814         registration->state->client_state->retry_interval = registration->retry_interval;
815         registration->state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
816         registration->state->client_state->max_retries = registration->max_retries;
817         registration->state->client_state->retries = 0;
818
819         pjsip_regc_update_expires(registration->state->client_state->client, registration->expiration);
820
821         schedule_registration(registration->state->client_state, (ast_random() % 10) + 1);
822
823         return 0;
824 }
825
826 /*! \brief Helper function which performs all registrations */
827 static void sip_outbound_registration_perform_all(void)
828 {
829         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);
830         struct ao2_iterator i;
831         struct sip_outbound_registration *registration;
832
833         if (!registrations) {
834                 return;
835         }
836
837         i = ao2_iterator_init(registrations, 0);
838         while ((registration = ao2_iterator_next(&i))) {
839                 if (ast_sip_push_task(registration->state->client_state->serializer, sip_outbound_registration_perform, registration)) {
840                         ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", ast_sorcery_object_get_id(registration));
841                         ao2_ref(registration, -1);
842                 }
843         }
844         ao2_iterator_destroy(&i);
845 }
846
847 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
848 {
849         struct sip_outbound_registration *registration = obj;
850
851         return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
852 }
853
854 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
855 {
856         const struct sip_outbound_registration *registration = obj;
857         return ast_sip_auths_to_str(&registration->outbound_auths, buf);
858 }
859
860 static struct sip_outbound_registration *retrieve_registration(const char *registration_name)
861 {
862         return ast_sorcery_retrieve_by_id(
863                 ast_sip_get_sorcery(),
864                 "registration",
865                 registration_name);
866 }
867
868 static int unregister_task(void *obj)
869 {
870         RAII_VAR(struct sip_outbound_registration*, registration, obj, ao2_cleanup);
871         struct pjsip_regc *client = registration->state->client_state->client;
872         pjsip_tx_data *tdata;
873
874         if (pjsip_regc_unregister(client, &tdata) != PJ_SUCCESS) {
875                 return 0;
876         }
877
878         ao2_ref(registration->state->client_state, +1);
879         if (pjsip_regc_send(client, tdata) != PJ_SUCCESS) {
880                 ao2_cleanup(registration->state->client_state);
881         }
882
883         return 0;
884 }
885
886 static int queue_unregister(struct sip_outbound_registration *registration)
887 {
888         ao2_ref(registration, +1);
889         if (ast_sip_push_task(registration->state->client_state->serializer, unregister_task, registration)) {
890                 ao2_cleanup(registration);
891                 return -1;
892         }
893         return 0;
894 }
895
896 static char *cli_complete_registration(const char *line, const char *word,
897 int pos, int state)
898 {
899         char *result = NULL;
900         int wordlen;
901         int which = 0;
902         struct sip_outbound_registration *registration;
903         RAII_VAR(struct ao2_container *, registrations, NULL, ao2_cleanup);
904         struct ao2_iterator i;
905
906         if (pos != 3) {
907                 return NULL;
908         }
909
910         wordlen = strlen(word);
911         registrations = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
912                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
913         if (!registrations) {
914                 return NULL;
915         }
916
917         i = ao2_iterator_init(registrations, 0);
918         while ((registration = ao2_iterator_next(&i))) {
919                 const char *name = ast_sorcery_object_get_id(registration);
920                 if (!strncasecmp(word, name, wordlen) && ++which > state) {
921                         result = ast_strdup(name);
922                 }
923
924                 ao2_cleanup(registration);
925                 if (result) {
926                         break;
927                 }
928         }
929         ao2_iterator_destroy(&i);
930         return result;
931 }
932
933 static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
934 {
935         RAII_VAR(struct sip_outbound_registration *, registration, NULL, ao2_cleanup);
936         const char *registration_name;
937
938         switch (cmd) {
939         case CLI_INIT:
940                 e->command = "pjsip send unregister";
941                 e->usage =
942                         "Usage: pjsip send unregister <registration>\n"
943                         "       Send a SIP REGISTER request to the specified outbound "
944                         "registration with an expiration of 0. This will cause the contact "
945                         "added by this registration to be removed on the remote system.\n";
946                 return NULL;
947         case CLI_GENERATE:
948                 return cli_complete_registration(a->line, a->word, a->pos, a->n);
949         }
950
951         if (a->argc != 4) {
952                 return CLI_SHOWUSAGE;
953         }
954
955         registration_name = a->argv[3];
956
957         registration = retrieve_registration(registration_name);
958         if (!registration) {
959                 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
960                 return CLI_FAILURE;
961         }
962
963         if (queue_unregister(registration)) {
964                 ast_cli(a->fd, "Failed to queue unregistration");
965                 return 0;
966         }
967
968         return CLI_SUCCESS;
969 }
970
971 static int ami_unregister(struct mansession *s, const struct message *m)
972 {
973         const char *registration_name = astman_get_header(m, "Registration");
974         RAII_VAR(struct sip_outbound_registration *, registration, NULL, ao2_cleanup);
975
976         if (ast_strlen_zero(registration_name)) {
977                 astman_send_error(s, m, "Registration parameter missing.");
978                 return 0;
979         }
980
981         registration = retrieve_registration(registration_name);
982         if (!registration) {
983                 astman_send_error(s, m, "Unable to retrieve registration entry\n");
984                 return 0;
985         }
986
987
988         if (queue_unregister(registration)) {
989                 astman_send_ack(s, m, "Failed to queue unregistration");
990                 return 0;
991         }
992
993         astman_send_ack(s, m, "Unregistration sent");
994         return 0;
995 }
996
997 static struct ast_cli_entry cli_outbound_registration[] = {
998         AST_CLI_DEFINE(cli_unregister, "Send a REGISTER request to an outbound registration target with a expiration of 0")
999 };
1000
1001 struct sip_ami_outbound {
1002         struct ast_sip_ami *ami;
1003         int registered;
1004         int not_registered;
1005         struct sip_outbound_registration *registration;
1006 };
1007
1008 static int ami_outbound_registration_task(void *obj)
1009 {
1010         struct sip_ami_outbound *ami = obj;
1011         RAII_VAR(struct ast_str *, buf,
1012                  ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami), ast_free);
1013
1014         if (!buf) {
1015                 return -1;
1016         }
1017
1018         ast_sip_sorcery_object_to_ami(ami->registration, &buf);
1019
1020         if (ami->registration->state) {
1021                 pjsip_regc_info info;
1022                 if (ami->registration->state->client_state->status ==
1023                     SIP_REGISTRATION_REGISTERED) {
1024                         ++ami->registered;
1025                 } else {
1026                         ++ami->not_registered;
1027                 }
1028
1029                 ast_str_append(&buf, 0, "Status: %s%s",
1030                                sip_outbound_registration_status_str[
1031                                        ami->registration->state->client_state->status], "\r\n");
1032
1033                 pjsip_regc_get_info(ami->registration->state->client_state->client, &info);
1034                 ast_str_append(&buf, 0, "NextReg: %d%s", info.next_reg, "\r\n");
1035         }
1036
1037         astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
1038         return ast_sip_format_auths_ami(&ami->registration->outbound_auths, ami->ami);
1039 }
1040
1041 static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
1042 {
1043         struct sip_ami_outbound *ami = arg;
1044
1045         ami->registration = obj;
1046         return ast_sip_push_task_synchronous(
1047                 NULL, ami_outbound_registration_task, ami);
1048 }
1049
1050 static int ami_show_outbound_registrations(struct mansession *s,
1051                                            const struct message *m)
1052 {
1053         struct ast_sip_ami ami = { s = s, m = m };
1054         struct sip_ami_outbound ami_outbound = { .ami = &ami };
1055         RAII_VAR(struct ao2_container *, regs, ast_sorcery_retrieve_by_fields(
1056                          ast_sip_get_sorcery(), "registration", AST_RETRIEVE_FLAG_MULTIPLE |
1057                          AST_RETRIEVE_FLAG_ALL, NULL), ao2_cleanup);
1058
1059         if (!regs) {
1060                 astman_send_error(s, m, "Unable to retreive "
1061                                   "outbound registrations\n");
1062                 return -1;
1063         }
1064
1065         astman_send_listack(s, m, "Following are Events for each Outbound "
1066                             "registration", "start");
1067
1068         ao2_callback(regs, OBJ_NODATA, ami_outbound_registration_detail, &ami_outbound);
1069
1070         astman_append(s,
1071                       "Event: OutboundRegistrationDetailComplete\r\n"
1072                       "EventList: Complete\r\n"
1073                       "Registered: %d\r\n"
1074                       "NotRegistered: %d\r\n\r\n",
1075                       ami_outbound.registered,
1076                       ami_outbound.not_registered);
1077         return 0;
1078 }
1079
1080 static int load_module(void)
1081 {
1082         ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
1083
1084         if (ast_sorcery_object_register(ast_sip_get_sorcery(), "registration", sip_outbound_registration_alloc, NULL, sip_outbound_registration_apply)) {
1085                 return AST_MODULE_LOAD_DECLINE;
1086         }
1087
1088         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
1089         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, server_uri));
1090         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
1091         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
1092         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
1093         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
1094         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
1095         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
1096         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));
1097         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
1098         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));
1099         ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, 0, 0);
1100         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
1101         sip_outbound_registration_perform_all();
1102
1103         ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1104         ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
1105         ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING,ami_show_outbound_registrations);
1106         return AST_MODULE_LOAD_SUCCESS;
1107 }
1108
1109 static int reload_module(void)
1110 {
1111         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
1112         sip_outbound_registration_perform_all();
1113         return 0;
1114 }
1115
1116 static int unload_module(void)
1117 {
1118         ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1119         ast_manager_unregister("PJSIPShowRegistrationsOutbound");
1120         ast_manager_unregister("PJSIPUnregister");
1121         return 0;
1122 }
1123
1124 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
1125                 .load = load_module,
1126                 .reload = reload_module,
1127                 .unload = unload_module,
1128                 .load_pri = AST_MODPRI_APP_DEPEND,
1129                );