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