b16ea64b1989960b7299d31380f15e72505201b1
[asterisk/asterisk.git] / res / res_pjsip_outbound_registration.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*** MODULEINFO
20         <depend>pjproject</depend>
21         <depend>res_pjsip</depend>
22         <support_level>core</support_level>
23  ***/
24
25 #include "asterisk.h"
26
27 #include <pjsip.h>
28 #include <pjsip_ua.h>
29
30 #include "asterisk/res_pjsip.h"
31 #include "asterisk/res_pjsip_cli.h"
32 #include "asterisk/module.h"
33 #include "asterisk/taskprocessor.h"
34 #include "asterisk/cli.h"
35 #include "asterisk/stasis_system.h"
36 #include "res_pjsip/include/res_pjsip_private.h"
37
38 /*** DOCUMENTATION
39         <configInfo name="res_pjsip_outbound_registration" language="en_US">
40                 <synopsis>SIP resource for outbound registrations</synopsis>
41                 <description><para>
42                         <emphasis>Outbound Registration</emphasis>
43                         </para>
44                         <para>This module allows <literal>res_pjsip</literal> to register to other SIP servers.</para>
45                 </description>
46                 <configFile name="pjsip.conf">
47                         <configObject name="registration">
48                                 <synopsis>The configuration for outbound registration</synopsis>
49                                 <description><para>
50                                         Registration is <emphasis>COMPLETELY</emphasis> separate from the rest of
51                                         <literal>pjsip.conf</literal>. A minimal configuration consists of
52                                         setting a <literal>server_uri</literal> and a <literal>client_uri</literal>.
53                                 </para></description>
54                                 <configOption name="auth_rejection_permanent" default="yes">
55                                         <synopsis>Determines whether failed authentication challenges are treated
56                                         as permanent failures.</synopsis>
57                                         <description><para>If this option is enabled and an authentication challenge fails,
58                                         registration will not be attempted again until the configuration is reloaded.</para></description>
59                                 </configOption>
60                                 <configOption name="client_uri">
61                                         <synopsis>Client SIP URI used when attemping outbound registration</synopsis>
62                                         <description><para>
63                                                 This is the address-of-record for the outbound registration (i.e. the URI in
64                                                 the To header of the REGISTER).</para>
65                                                 <para>For registration with an ITSP, the client SIP URI may need to consist of
66                                                 an account name or number and the provider's hostname for their registrar, e.g.
67                                                 client_uri=1234567890@example.com. This may differ between providers.</para>
68                                                 <para>For registration to generic registrars, the client SIP URI will depend
69                                                 on networking specifics and configuration of the registrar.
70                                         </para></description>
71                                 </configOption>
72                                 <configOption name="contact_user">
73                                         <synopsis>Contact User to use in request</synopsis>
74                                 </configOption>
75                                 <configOption name="expiration" default="3600">
76                                         <synopsis>Expiration time for registrations in seconds</synopsis>
77                                 </configOption>
78                                 <configOption name="max_retries" default="10">
79                                         <synopsis>Maximum number of registration attempts.</synopsis>
80                                 </configOption>
81                                 <configOption name="outbound_auth" default="">
82                                         <synopsis>Authentication object to be used for outbound registrations.</synopsis>
83                                 </configOption>
84                                 <configOption name="outbound_proxy" default="">
85                                         <synopsis>Outbound Proxy used to send registrations</synopsis>
86                                 </configOption>
87                                 <configOption name="retry_interval" default="60">
88                                         <synopsis>Interval in seconds between retries if outbound registration is unsuccessful</synopsis>
89                                 </configOption>
90                                 <configOption name="forbidden_retry_interval" default="0">
91                                         <synopsis>Interval used when receiving a 403 Forbidden response.</synopsis>
92                                         <description><para>
93                                                 If a 403 Forbidden is received, chan_pjsip will wait
94                                                 <replaceable>forbidden_retry_interval</replaceable> seconds before
95                                                 attempting registration again. If 0 is specified, chan_pjsip will not
96                                                 retry after receiving a 403 Forbidden response. Setting this to a non-zero
97                                                 value goes against a "SHOULD NOT" in RFC3261, but can be used to work around
98                                                 buggy registrars.
99                                         </para></description>
100                                 </configOption>
101                                 <configOption name="server_uri">
102                                         <synopsis>SIP URI of the server to register against</synopsis>
103                                         <description><para>
104                                                 This is the URI at which to find the registrar to send the outbound REGISTER. This URI
105                                                 is used as the request URI of the outbound REGISTER request from Asterisk.</para>
106                                                 <para>For registration with an ITSP, the setting may often be just the domain of
107                                                 the registrar, e.g. sip:sip.example.com.
108                                         </para></description>
109                                 </configOption>
110                                 <configOption name="transport">
111                                         <synopsis>Transport used for outbound authentication</synopsis>
112                                         <description>
113                                                 <note><para>A <replaceable>transport</replaceable> configured in
114                                                 <literal>pjsip.conf</literal>. As with other <literal>res_pjsip</literal> modules, this will use the first available transport of the appropriate type if unconfigured.</para></note>
115                                         </description>
116                                 </configOption>
117                                 <configOption name="line">
118                                         <synopsis>Whether to add a 'line' parameter to the Contact for inbound call matching</synopsis>
119                                         <description><para>
120                                                 When enabled this option will cause a 'line' parameter to be added to the Contact
121                                                 header placed into the outgoing registration request. If the remote server sends a call
122                                                 this line parameter will be used to establish a relationship to the outbound registration,
123                                                 ultimately causing the configured endpoint to be used.
124                                         </para></description>
125                                 </configOption>
126                                 <configOption name="endpoint">
127                                         <synopsis>Endpoint to use for incoming related calls</synopsis>
128                                         <description><para>
129                                                 When line support is enabled this configured endpoint name is used for incoming calls
130                                                 that are related to the outbound registration.
131                                         </para></description>
132                                 </configOption>
133                                 <configOption name="type">
134                                         <synopsis>Must be of type 'registration'.</synopsis>
135                                 </configOption>
136                                 <configOption name="support_path">
137                                         <synopsis>Enables Path support for outbound REGISTER requests.</synopsis>
138                                         <description><para>
139                                                 When this option is enabled, outbound REGISTER requests will advertise
140                                                 support for Path headers so that intervening proxies can add to the Path
141                                                 header as necessary.
142                                         </para></description>
143                                 </configOption>
144                         </configObject>
145                 </configFile>
146         </configInfo>
147         <manager name="PJSIPUnregister" language="en_US">
148                 <synopsis>
149                         Unregister an outbound registration.
150                 </synopsis>
151                 <syntax>
152                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
153                         <parameter name="Registration" required="true">
154                                 <para>The outbound registration to unregister.</para>
155                         </parameter>
156                 </syntax>
157                 <description>
158                         <para>
159                         Unregisters the specified outbound registration and stops future registration attempts.
160                         Call PJSIPRegister to start registration and schedule re-registrations according to configuration.
161             </para>
162                 </description>
163         </manager>
164         <manager name="PJSIPRegister" language="en_US">
165                 <synopsis>
166                         Register an outbound registration.
167                 </synopsis>
168                 <syntax>
169                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
170                         <parameter name="Registration" required="true">
171                                 <para>The outbound registration to register.</para>
172                         </parameter>
173                 </syntax>
174                 <description>
175                         <para>
176                         Unregisters the specified outbound registration then starts registration and schedules re-registrations
177                         according to configuration.
178                         future registrations.
179             </para>
180                 </description>
181         </manager>
182         <manager name="PJSIPShowRegistrationsOutbound" language="en_US">
183                 <synopsis>
184                         Lists PJSIP outbound registrations.
185                 </synopsis>
186                 <syntax />
187                 <description>
188                         <para>
189                         In response <literal>OutboundRegistrationDetail</literal> events showing configuration and status
190                         information are raised for each outbound registration object. <literal>AuthDetail</literal>
191                         events are raised for each associated auth object as well.  Once all events are completed an
192                         <literal>OutboundRegistrationDetailComplete</literal> is issued.
193                         </para>
194                 </description>
195         </manager>
196  ***/
197
198 /*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
199 #define REREGISTER_BUFFER_TIME 10
200
201 /*! \brief Size of the buffer for creating a unique string for the line */
202 #define LINE_PARAMETER_SIZE 8
203
204 /*! \brief Various states that an outbound registration may be in */
205 enum sip_outbound_registration_status {
206         /*! \brief Currently unregistered */
207         SIP_REGISTRATION_UNREGISTERED = 0,
208         /*! \brief Registered, yay! */
209         SIP_REGISTRATION_REGISTERED,
210         /*! \brief Registration was rejected, but response was temporal */
211         SIP_REGISTRATION_REJECTED_TEMPORARY,
212         /*! \brief Registration was rejected, permanently */
213         SIP_REGISTRATION_REJECTED_PERMANENT,
214         /*! \brief Registration has been stopped */
215         SIP_REGISTRATION_STOPPED,
216 };
217
218 static const char *sip_outbound_registration_status_str[] = {
219         [SIP_REGISTRATION_UNREGISTERED] = "Unregistered",
220         [SIP_REGISTRATION_REGISTERED] = "Registered",
221         [SIP_REGISTRATION_REJECTED_TEMPORARY] = "Rejected",
222         [SIP_REGISTRATION_REJECTED_PERMANENT] = "Rejected",
223         [SIP_REGISTRATION_STOPPED] = "Stopped",
224 };
225
226 /*! \brief Outbound registration information */
227 struct sip_outbound_registration {
228         /*! \brief Sorcery object details */
229         SORCERY_OBJECT(details);
230         /*! \brief Stringfields */
231         AST_DECLARE_STRING_FIELDS(
232                 /*! \brief URI for the registrar */
233                 AST_STRING_FIELD(server_uri);
234                 /*! \brief URI for the AOR */
235                 AST_STRING_FIELD(client_uri);
236                 /*! \brief Optional user for contact header */
237                 AST_STRING_FIELD(contact_user);
238                 /*! \brief Explicit transport to use for registration */
239                 AST_STRING_FIELD(transport);
240                 /*! \brief Outbound proxy to use */
241                 AST_STRING_FIELD(outbound_proxy);
242                 /*! \brief Endpoint to use for related incoming calls */
243                 AST_STRING_FIELD(endpoint);
244         );
245         /*! \brief Requested expiration time */
246         unsigned int expiration;
247         /*! \brief Interval at which retries should occur for temporal responses */
248         unsigned int retry_interval;
249         /*! \brief Interval at which retries should occur for permanent responses */
250         unsigned int forbidden_retry_interval;
251         /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
252         unsigned int auth_rejection_permanent;
253         /*! \brief Maximum number of retries permitted */
254         unsigned int max_retries;
255         /*! \brief Whether to add a line parameter to the outbound Contact or not */
256         unsigned int line;
257         /*! \brief Configured authentication credentials */
258         struct ast_sip_auth_vector outbound_auths;
259         /*! \brief Whether Path support is enabled */
260         unsigned int support_path;
261 };
262
263 /*! \brief Outbound registration client state information (persists for lifetime of regc) */
264 struct sip_outbound_registration_client_state {
265         /*! \brief Current status of this registration */
266         enum sip_outbound_registration_status status;
267         /*! \brief Outbound registration client */
268         pjsip_regc *client;
269         /*! \brief Timer entry for retrying on temporal responses */
270         pj_timer_entry timer;
271         /*! \brief Optional line parameter placed into Contact */
272         char line[LINE_PARAMETER_SIZE];
273         /*! \brief Current number of retries */
274         unsigned int retries;
275         /*! \brief Maximum number of retries permitted */
276         unsigned int max_retries;
277         /*! \brief Interval at which retries should occur for temporal responses */
278         unsigned int retry_interval;
279         /*! \brief Interval at which retries should occur for permanent responses */
280         unsigned int forbidden_retry_interval;
281         /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
282         unsigned int auth_rejection_permanent;
283         /*! \brief Determines whether SIP Path support should be advertised */
284         unsigned int support_path;
285         /*! \brief Serializer for stuff and things */
286         struct ast_taskprocessor *serializer;
287         /*! \brief Configured authentication credentials */
288         struct ast_sip_auth_vector outbound_auths;
289         /*! \brief Registration should be destroyed after completion of transaction */
290         unsigned int destroy:1;
291         /*! \brief Non-zero if we have attempted sending a REGISTER with authentication */
292         unsigned int auth_attempted:1;
293 };
294
295 /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
296 struct sip_outbound_registration_state {
297         /*! \brief Outbound registration configuration object */
298         struct sip_outbound_registration *registration;
299         /*! \brief Client state information */
300         struct sip_outbound_registration_client_state *client_state;
301 };
302
303 /*! \brief Default number of state container buckets */
304 #define DEFAULT_STATE_BUCKETS 53
305 static AO2_GLOBAL_OBJ_STATIC(current_states);
306
307 /*! \brief hashing function for state objects */
308 static int registration_state_hash(const void *obj, const int flags)
309 {
310         const struct sip_outbound_registration_state *object;
311         const char *key;
312
313         switch (flags & OBJ_SEARCH_MASK) {
314         case OBJ_SEARCH_KEY:
315                 key = obj;
316                 break;
317         case OBJ_SEARCH_OBJECT:
318                 object = obj;
319                 key = ast_sorcery_object_get_id(object->registration);
320                 break;
321         default:
322                 ast_assert(0);
323                 return 0;
324         }
325         return ast_str_hash(key);
326 }
327
328 /*! \brief comparator function for state objects */
329 static int registration_state_cmp(void *obj, void *arg, int flags)
330 {
331         const struct sip_outbound_registration_state *object_left = obj;
332         const struct sip_outbound_registration_state *object_right = arg;
333         const char *right_key = arg;
334         int cmp;
335
336         switch (flags & OBJ_SEARCH_MASK) {
337         case OBJ_SEARCH_OBJECT:
338                 right_key = ast_sorcery_object_get_id(object_right->registration);
339                 /* Fall through */
340         case OBJ_SEARCH_KEY:
341                 cmp = strcmp(ast_sorcery_object_get_id(object_left->registration), right_key);
342                 break;
343         case OBJ_SEARCH_PARTIAL_KEY:
344                 /* Not supported by container. */
345                 ast_assert(0);
346                 return 0;
347         default:
348                 cmp = 0;
349                 break;
350         }
351         if (cmp) {
352                 return 0;
353         }
354         return CMP_MATCH;
355 }
356
357 static struct sip_outbound_registration_state *get_state(const char *id)
358 {
359         RAII_VAR(struct ao2_container *, states,
360                  ao2_global_obj_ref(current_states), ao2_cleanup);
361         return states ? ao2_find(states, id, OBJ_SEARCH_KEY) : NULL;
362 }
363
364 static int registration_state_add(void *obj, void *arg, int flags)
365 {
366         struct sip_outbound_registration_state *state =
367                 get_state(ast_sorcery_object_get_id(obj));
368
369         if (state) {
370                 ao2_link(arg, state);
371                 ao2_ref(state, -1);
372         }
373
374         return 0;
375 }
376
377 static struct ao2_container *get_registrations(void)
378 {
379         RAII_VAR(struct ao2_container *, new_states, NULL, ao2_cleanup);
380         struct ao2_container *registrations = ast_sorcery_retrieve_by_fields(
381                 ast_sip_get_sorcery(), "registration",
382                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
383
384         if (!(new_states = ao2_container_alloc(DEFAULT_STATE_BUCKETS,
385                       registration_state_hash, registration_state_cmp))) {
386                 ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
387                 return NULL;
388         }
389
390         if (registrations && ao2_container_count(registrations)) {
391                 ao2_callback(registrations, OBJ_NODATA, registration_state_add, new_states);
392         }
393
394         ao2_global_obj_replace_unref(current_states, new_states);
395         return registrations;
396 }
397
398 /*! \brief Callback function for matching an outbound registration based on line */
399 static int line_identify_relationship(void *obj, void *arg, int flags)
400 {
401         struct sip_outbound_registration_state *state = obj;
402         pjsip_param *line = arg;
403
404         return !pj_strcmp2(&line->value, state->client_state->line) ? CMP_MATCH | CMP_STOP : 0;
405 }
406
407 /*! \brief Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing registration */
408 static struct ast_sip_endpoint *line_identify(pjsip_rx_data *rdata)
409 {
410         pjsip_sip_uri *uri;
411         static const pj_str_t LINE_STR = { "line", 4 };
412         pjsip_param *line;
413         RAII_VAR(struct ao2_container *, states, NULL, ao2_cleanup);
414         RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
415
416         if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
417                 return NULL;
418         }
419         uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
420
421         line = pjsip_param_find(&uri->other_param, &LINE_STR);
422         if (!line) {
423                 return NULL;
424         }
425
426         states = ao2_global_obj_ref(current_states);
427         if (!states) {
428                 return NULL;
429         }
430
431         state = ao2_callback(states, 0, line_identify_relationship, line);
432         if (!state || ast_strlen_zero(state->registration->endpoint)) {
433                 return NULL;
434         }
435
436         ast_debug(3, "Determined relationship to outbound registration '%s' based on line '%s', using configured endpoint '%s'\n",
437                 ast_sorcery_object_get_id(state->registration), state->client_state->line, state->registration->endpoint);
438
439         return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", state->registration->endpoint);
440 }
441
442 static struct ast_sip_endpoint_identifier line_identifier = {
443         .identify_endpoint = line_identify,
444 };
445
446 /*! \brief Helper function which cancels the timer on a client */
447 static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
448 {
449         if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &client_state->timer)) {
450                 /* The timer was successfully cancelled, drop the refcount of client_state */
451                 ao2_ref(client_state, -1);
452         }
453 }
454
455 static pj_str_t PATH_NAME = { "path", 4 };
456
457 /*! \brief Callback function for registering */
458 static int handle_client_registration(void *data)
459 {
460         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
461         pjsip_tx_data *tdata;
462         pjsip_regc_info info;
463         char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
464
465         if ((client_state->status == SIP_REGISTRATION_STOPPED) ||
466                 (pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS)) {
467                 return 0;
468         }
469
470         pjsip_regc_get_info(client_state->client, &info);
471         ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
472         ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
473         ast_debug(3, "REGISTER attempt %u to '%s' with client '%s'\n",
474                   client_state->retries + 1, server_uri, client_uri);
475
476         if (client_state->support_path) {
477                 pjsip_supported_hdr *hdr;
478
479                 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
480                 if (!hdr) {
481                         /* insert a new Supported header */
482                         hdr = pjsip_supported_hdr_create(tdata->pool);
483                         if (!hdr) {
484                                 return -1;
485                         }
486
487                         pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
488                 }
489
490                 /* add on to the existing Supported header */
491                 pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
492         }
493
494         /* Due to the registration the callback may now get called, so bump the ref count */
495         ao2_ref(client_state, +1);
496         if (pjsip_regc_send(client_state->client, tdata) != PJ_SUCCESS) {
497                 ao2_ref(client_state, -1);
498         }
499
500         return 0;
501 }
502
503 /*! \brief Timer callback function, used just for registrations */
504 static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
505 {
506         struct sip_outbound_registration_client_state *client_state = entry->user_data;
507
508         ao2_ref(client_state, +1);
509         if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
510                 ast_log(LOG_WARNING, "Failed to pass outbound registration to threadpool\n");
511                 ao2_ref(client_state, -1);
512         }
513         ao2_ref(client_state, -1);
514
515         entry->id = 0;
516 }
517
518 /*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
519 static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
520 {
521         pj_time_val delay = { .sec = seconds, };
522
523         cancel_registration(client_state);
524
525         ao2_ref(client_state, +1);
526         if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
527                 ast_log(LOG_WARNING, "Failed to pass timed registration to scheduler\n");
528                 ao2_ref(client_state, -1);
529         }
530 }
531
532 /*! \brief Callback function for unregistering (potentially) and destroying state */
533 static int handle_client_state_destruction(void *data)
534 {
535         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
536
537         cancel_registration(client_state);
538
539         if (client_state->client) {
540                 pjsip_regc_info info;
541
542                 pjsip_regc_get_info(client_state->client, &info);
543
544                 if (info.is_busy == PJ_TRUE) {
545                         /* If a client transaction is in progress we defer until it is complete */
546                         client_state->destroy = 1;
547                         return 0;
548                 }
549
550                 if (client_state->status != SIP_REGISTRATION_UNREGISTERED && client_state->status != SIP_REGISTRATION_REJECTED_PERMANENT) {
551                         pjsip_tx_data *tdata;
552
553                         if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS) {
554                                 pjsip_regc_send(client_state->client, tdata);
555                         }
556                 }
557
558                 pjsip_regc_destroy(client_state->client);
559         }
560
561         client_state->status = SIP_REGISTRATION_STOPPED;
562         ast_sip_auth_vector_destroy(&client_state->outbound_auths);
563
564         return 0;
565 }
566
567 /*! \brief Structure for registration response */
568 struct registration_response {
569         /*! \brief Response code for the registration attempt */
570         int code;
571         /*! \brief Expiration time for registration */
572         int expiration;
573         /*! \brief Retry-After value */
574         int retry_after;
575         /*! \brief Outbound registration client state */
576         struct sip_outbound_registration_client_state *client_state;
577         /*! \brief The response message */
578         pjsip_rx_data *rdata;
579         /*! \brief The response transaction */
580         pjsip_transaction *tsx;
581 };
582
583 /*! \brief Registration response structure destructor */
584 static void registration_response_destroy(void *obj)
585 {
586         struct registration_response *response = obj;
587
588         if (response->rdata) {
589                 pjsip_rx_data_free_cloned(response->rdata);
590         }
591
592         ao2_cleanup(response->client_state);
593 }
594
595 /* \brief Helper funtion which determines if a response code is temporal or not */
596 static int sip_outbound_registration_is_temporal(unsigned int code,
597                 struct sip_outbound_registration_client_state *client_state)
598 {
599         /* Shamelessly taken from pjsua */
600         if (code == PJSIP_SC_REQUEST_TIMEOUT ||
601                 code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
602                 code == PJSIP_SC_BAD_GATEWAY ||
603                 code == PJSIP_SC_SERVICE_UNAVAILABLE ||
604                 code == PJSIP_SC_SERVER_TIMEOUT ||
605                 ((code == PJSIP_SC_UNAUTHORIZED ||
606                   code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
607                  !client_state->auth_rejection_permanent) ||
608                 PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
609                 return 1;
610         } else {
611                 return 0;
612         }
613 }
614
615 static void schedule_retry(struct registration_response *response, unsigned int interval,
616                            const char *server_uri, const char *client_uri)
617 {
618         response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
619         schedule_registration(response->client_state, interval);
620
621         if (response->rdata) {
622                 ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
623                         "registration attempt to '%s', retrying in '%u'\n",
624                         response->code, server_uri, client_uri, interval);
625         } else {
626                 ast_log(LOG_WARNING, "No response received from '%s' on "
627                         "registration attempt to '%s', retrying in '%u'\n",
628                         server_uri, client_uri, interval);
629         }
630 }
631
632 /*! \brief Callback function for handling a response to a registration attempt */
633 static int handle_registration_response(void *data)
634 {
635         RAII_VAR(struct registration_response *, response, data, ao2_cleanup);
636         pjsip_regc_info info;
637         char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
638
639         if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
640                 return 0;
641         }
642
643         pjsip_regc_get_info(response->client_state->client, &info);
644         ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
645         ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
646
647         if (!response->client_state->auth_attempted &&
648                         (response->code == 401 || response->code == 407)) {
649                 pjsip_tx_data *tdata;
650                 if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
651                                 response->rdata, response->tsx, &tdata)) {
652                         ao2_ref(response->client_state, +1);
653                         response->client_state->auth_attempted = 1;
654                         if (pjsip_regc_send(response->client_state->client, tdata) != PJ_SUCCESS) {
655                                 response->client_state->auth_attempted = 0;
656                                 ao2_cleanup(response->client_state);
657                         }
658                         return 0;
659                 }
660                 /* Otherwise, fall through so the failure is processed appropriately */
661         }
662
663         response->client_state->auth_attempted = 0;
664
665         if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
666                 /* Check if this is in regards to registering or unregistering */
667                 if (response->expiration) {
668                         /* If the registration went fine simply reschedule registration for the future */
669                         ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
670                         response->client_state->status = SIP_REGISTRATION_REGISTERED;
671                         response->client_state->retries = 0;
672                         schedule_registration(response->client_state, response->expiration - REREGISTER_BUFFER_TIME);
673                 } else {
674                         ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
675                         response->client_state->status = SIP_REGISTRATION_UNREGISTERED;
676                 }
677         } else if (response->retry_after) {
678                 /* If we have been instructed to retry after a period of time, schedule it as such */
679                 schedule_retry(response, response->retry_after, server_uri, client_uri);
680         } else if (response->client_state->retry_interval && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
681                 if (response->client_state->retries == response->client_state->max_retries) {
682                         /* If we received enough temporal responses to exceed our maximum give up permanently */
683                         response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
684                         ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
685                                 server_uri, client_uri);
686                 } else {
687                         /* On the other hand if we can still try some more do so */
688                         response->client_state->retries++;
689                         schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
690                 }
691         } else {
692                 if (response->code == 403
693                         && response->client_state->forbidden_retry_interval
694                         && response->client_state->retries < response->client_state->max_retries) {
695                         /* A forbidden response retry interval is configured and there are retries remaining */
696                         response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
697                         response->client_state->retries++;
698                         schedule_registration(response->client_state, response->client_state->forbidden_retry_interval);
699                         ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
700                                 server_uri, client_uri, response->client_state->forbidden_retry_interval);
701                 } else {
702                         /* Finally if there's no hope of registering give up */
703                         response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
704                         if (response->rdata) {
705                                 ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
706                                         response->code, server_uri, client_uri);
707                         } else {
708                                 ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
709                         }
710                 }
711         }
712
713         ast_system_publish_registry("PJSIP", client_uri, server_uri, sip_outbound_registration_status_str[response->client_state->status], NULL);
714
715         /* If deferred destruction is in use see if we need to destroy now */
716         if (response->client_state->destroy) {
717                 handle_client_state_destruction(response->client_state);
718         }
719
720         return 0;
721 }
722
723 /*! \brief Callback function for outbound registration client */
724 static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
725 {
726         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, param->token, ao2_cleanup);
727         struct registration_response *response;
728
729         ast_assert(client_state != NULL);
730
731         response = ao2_alloc(sizeof(*response), registration_response_destroy);
732         if (!response) {
733                 return;
734         }
735         response->code = param->code;
736         response->expiration = param->expiration;
737         response->client_state = client_state;
738         ao2_ref(response->client_state, +1);
739
740         if (param->rdata) {
741                 struct pjsip_retry_after_hdr *retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER, NULL);
742
743                 response->retry_after = retry_after ? retry_after->ivalue : 0;
744                 response->tsx = pjsip_rdata_get_tsx(param->rdata);
745                 pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
746         }
747
748         if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
749                 ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
750                 ao2_cleanup(response);
751         }
752 }
753
754 /*! \brief Destructor function for registration state */
755 static void sip_outbound_registration_state_destroy(void *obj)
756 {
757         struct sip_outbound_registration_state *state = obj;
758
759         ao2_cleanup(state->registration);
760
761         if (!state->client_state) {
762                 /* Nothing to do */
763         } else if (!state->client_state->serializer) {
764                 ao2_ref(state->client_state, -1);
765         } else if (ast_sip_push_task(state->client_state->serializer,
766                 handle_client_state_destruction, state->client_state)) {
767                 ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
768                 ao2_ref(state->client_state, -1);
769         }
770 }
771
772 /*! \brief Destructor function for client registration state */
773 static void sip_outbound_registration_client_state_destroy(void *obj)
774 {
775         struct sip_outbound_registration_client_state *client_state = obj;
776
777         ast_taskprocessor_unreference(client_state->serializer);
778 }
779
780 /*! \brief Allocator function for registration state */
781 static struct sip_outbound_registration_state *sip_outbound_registration_state_alloc(struct sip_outbound_registration *registration)
782 {
783         struct sip_outbound_registration_state *state;
784
785         state = ao2_alloc(sizeof(*state), sip_outbound_registration_state_destroy);
786         if (!state) {
787                 return NULL;
788         }
789         state->client_state = ao2_alloc(sizeof(*state->client_state),
790                 sip_outbound_registration_client_state_destroy);
791         if (!state->client_state) {
792                 ao2_cleanup(state);
793                 return NULL;
794         }
795
796         state->client_state->serializer = ast_sip_create_serializer();
797         if (!state->client_state->serializer) {
798                 ao2_cleanup(state);
799                 return NULL;
800         }
801         state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
802         state->client_state->timer.user_data = state->client_state;
803         state->client_state->timer.cb = sip_outbound_registration_timer_cb;
804
805         state->registration = ao2_bump(registration);
806         return state;
807 }
808
809 /*! \brief Destructor function for registration information */
810 static void sip_outbound_registration_destroy(void *obj)
811 {
812         struct sip_outbound_registration *registration = obj;
813
814         ast_sip_auth_vector_destroy(&registration->outbound_auths);
815
816         ast_string_field_free_memory(registration);
817 }
818
819 /*! \brief Allocator function for registration information */
820 static void *sip_outbound_registration_alloc(const char *name)
821 {
822         struct sip_outbound_registration *registration = ast_sorcery_generic_alloc(sizeof(*registration), sip_outbound_registration_destroy);
823         if (!registration || ast_string_field_init(registration, 256)) {
824                 ao2_cleanup(registration);
825                 return NULL;
826         }
827
828         return registration;
829 }
830
831 /*! \brief Helper function which populates a pj_str_t with a contact header */
832 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,
833         const char *line)
834 {
835         pj_str_t tmp, local_addr;
836         pjsip_uri *uri;
837         pjsip_sip_uri *sip_uri;
838         pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
839         int local_port;
840
841         pj_strdup_with_null(pool, &tmp, target);
842
843         if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
844             (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
845                 return -1;
846         }
847
848         sip_uri = pjsip_uri_get_uri(uri);
849
850         if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
851                 type = PJSIP_TRANSPORT_TLS;
852         } else if (!sip_uri->transport_param.slen) {
853                 type = PJSIP_TRANSPORT_UDP;
854         } else {
855                 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
856         }
857
858         if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
859                 return -1;
860         }
861
862         if (pj_strchr(&sip_uri->host, ':')) {
863                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
864         }
865
866         if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
867                                                               &local_addr, &local_port) != PJ_SUCCESS) {
868                 return -1;
869         }
870
871         if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
872                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
873         }
874
875         contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
876         contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
877                                       "<%s:%s@%s%.*s%s:%d%s%s%s%s>",
878                                       (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
879                                       user,
880                                       (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
881                                       (int)local_addr.slen,
882                                       local_addr.ptr,
883                                       (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
884                                       local_port,
885                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
886                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "",
887                                       !ast_strlen_zero(line) ? ";line=" : "",
888                                       S_OR(line, ""));
889
890         return 0;
891 }
892
893 /*!
894  * \internal
895  * \brief Check if a registration can be reused
896  *
897  * This checks if the existing outbound registration's configuration differs from a newly-applied
898  * outbound registration to see if the applied one.
899  *
900  * \param existing The pre-existing outbound registration
901  * \param applied The newly-created registration
902  */
903 static int can_reuse_registration(struct sip_outbound_registration *existing,
904         struct sip_outbound_registration *applied)
905 {
906         int rc = 1;
907         struct ast_sorcery *sorcery = ast_sip_get_sorcery();
908         struct ast_variable *ve = ast_sorcery_objectset_create(sorcery, existing);
909         struct ast_variable *va = ast_sorcery_objectset_create(sorcery, applied);
910         struct ast_variable *vc = NULL;
911
912         if (ast_sorcery_changeset_create(ve, va, &vc) || vc != NULL) {
913                 rc = 0;
914                 ast_debug(4, "Registration '%s' changed.  Can't re-use.\n", ast_sorcery_object_get_id(existing));
915         } else {
916                 ast_debug(4, "Registration '%s' didn't change.  Can re-use\n", ast_sorcery_object_get_id(existing));
917         }
918
919         ast_variables_destroy(ve);
920         ast_variables_destroy(va);
921         ast_variables_destroy(vc);
922
923         return rc;
924 }
925
926 /*! \brief Helper function that allocates a pjsip registration client and configures it */
927 static int sip_outbound_registration_regc_alloc(void *data)
928 {
929         struct sip_outbound_registration_state *state = data;
930         RAII_VAR(struct sip_outbound_registration *, registration,
931                  ao2_bump(state->registration), ao2_cleanup);
932         pj_pool_t *pool;
933         pj_str_t tmp;
934         pjsip_uri *uri;
935         pj_str_t server_uri, client_uri, contact_uri;
936         pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
937
938         pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
939         if (!pool) {
940                 ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
941                         ast_sorcery_object_get_id(registration));
942                 return -1;
943         }
944
945         pj_strdup2_with_null(pool, &tmp, registration->server_uri);
946         uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
947         if (!uri) {
948                 ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
949                         registration->server_uri, ast_sorcery_object_get_id(registration));
950                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
951                 return -1;
952         }
953
954         pj_strdup2_with_null(pool, &tmp, registration->client_uri);
955         uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
956         if (!uri) {
957                 ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
958                         registration->client_uri, ast_sorcery_object_get_id(registration));
959                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
960                 return -1;
961         }
962
963         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
964
965         if (!ast_strlen_zero(registration->transport)) {
966                 RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", registration->transport), ao2_cleanup);
967
968                 if (!transport || !transport->state) {
969                         ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' "
970                                 " for outbound registration", registration->transport);
971                         return -1;
972                 }
973
974                 if (transport->state->transport) {
975                         selector.type = PJSIP_TPSELECTOR_TRANSPORT;
976                         selector.u.transport = transport->state->transport;
977                 } else if (transport->state->factory) {
978                         selector.type = PJSIP_TPSELECTOR_LISTENER;
979                         selector.u.listener = transport->state->factory;
980                 } else {
981                         return -1;
982                 }
983         }
984
985         if (!state->client_state->client
986                 && pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state,
987                         sip_outbound_registration_response_cb,
988                         &state->client_state->client) != PJ_SUCCESS) {
989                 return -1;
990         }
991
992         pjsip_regc_set_transport(state->client_state->client, &selector);
993
994         if (!ast_strlen_zero(registration->outbound_proxy)) {
995                 pjsip_route_hdr route_set, *route;
996                 static const pj_str_t ROUTE_HNAME = { "Route", 5 };
997                 pj_str_t tmp;
998
999                 pj_list_init(&route_set);
1000
1001                 pj_strdup2_with_null(pjsip_regc_get_pool(state->client_state->client), &tmp, registration->outbound_proxy);
1002                 if (!(route = pjsip_parse_hdr(pjsip_regc_get_pool(state->client_state->client), &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
1003                         return -1;
1004                 }
1005                 pj_list_insert_nodes_before(&route_set, route);
1006
1007                 pjsip_regc_set_route_set(state->client_state->client, &route_set);
1008         }
1009
1010         if (state->registration->line) {
1011                 ast_generate_random_string(state->client_state->line, sizeof(state->client_state->line));
1012         }
1013
1014         pj_cstr(&server_uri, registration->server_uri);
1015
1016
1017         if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client), &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
1018                 state->client_state->line)) {
1019                 return -1;
1020         }
1021
1022         pj_cstr(&client_uri, registration->client_uri);
1023         if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri, &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
1024                 return -1;
1025         }
1026
1027         return 0;
1028 }
1029
1030 /*! \brief Helper function which performs a single registration */
1031 static int sip_outbound_registration_perform(void *data)
1032 {
1033         RAII_VAR(struct sip_outbound_registration_state *, state, data, ao2_cleanup);
1034         RAII_VAR(struct sip_outbound_registration *, registration, ao2_bump(state->registration), ao2_cleanup);
1035         size_t i;
1036
1037         /* Just in case the client state is being reused for this registration, free the auth information */
1038         ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
1039
1040         AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(&registration->outbound_auths));
1041         for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
1042                 const char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
1043                 AST_VECTOR_APPEND(&state->client_state->outbound_auths, name);
1044         }
1045         state->client_state->retry_interval = registration->retry_interval;
1046         state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
1047         state->client_state->max_retries = registration->max_retries;
1048         state->client_state->retries = 0;
1049         state->client_state->support_path = registration->support_path;
1050         state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
1051
1052         pjsip_regc_update_expires(state->client_state->client, registration->expiration);
1053
1054         schedule_registration(state->client_state, (ast_random() % 10) + 1);
1055
1056         return 0;
1057 }
1058
1059 /*! \brief Apply function which finds or allocates a state structure */
1060 static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
1061 {
1062         RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup);
1063         RAII_VAR(struct sip_outbound_registration_state *, state,
1064                  ao2_find(states, ast_sorcery_object_get_id(obj), OBJ_SEARCH_KEY), ao2_cleanup);
1065         RAII_VAR(struct sip_outbound_registration_state *, new_state, NULL, ao2_cleanup);
1066         struct sip_outbound_registration *applied = obj;
1067
1068         ast_debug(4, "Applying configuration to outbound registration '%s'\n", ast_sorcery_object_get_id(applied));
1069
1070         if (ast_strlen_zero(applied->server_uri)) {
1071                 ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'",
1072                         ast_sorcery_object_get_id(applied));
1073                 return -1;
1074         } else if (ast_strlen_zero(applied->client_uri)) {
1075                 ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
1076                         ast_sorcery_object_get_id(applied));
1077                 return -1;
1078         } else if (applied->line && ast_strlen_zero(applied->endpoint)) {
1079                 ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
1080                         ast_sorcery_object_get_id(applied));
1081                 return -1;
1082         } else if (!ast_strlen_zero(applied->endpoint) && !applied->line) {
1083                 ast_log(LOG_ERROR, "An endpoint has been specified on outbound registration '%s' without enabling line support\n",
1084                         ast_sorcery_object_get_id(applied));
1085                 return -1;
1086         }
1087
1088         if (state && can_reuse_registration(state->registration, applied)) {
1089                 ast_debug(4,
1090                         "No change between old configuration and new configuration on outbound registration '%s'. Using previous state\n",
1091                         ast_sorcery_object_get_id(applied));
1092                 ao2_replace(state->registration, applied);
1093                 return 0;
1094         }
1095
1096         if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
1097                 return -1;
1098         }
1099
1100         if (ast_sip_push_task_synchronous(NULL, sip_outbound_registration_regc_alloc, new_state)) {
1101                 return -1;
1102         }
1103
1104         if (ast_sip_push_task(new_state->client_state->serializer,
1105                               sip_outbound_registration_perform, ao2_bump(new_state))) {
1106                 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n",
1107                         ast_sorcery_object_get_id(new_state->registration));
1108                 ao2_ref(new_state, -1);
1109                 return -1;
1110         }
1111
1112         ao2_lock(states);
1113
1114         if (state) {
1115                 ao2_unlink(states, state);
1116         }
1117
1118         ao2_link(states, new_state);
1119         ao2_unlock(states);
1120
1121         return 0;
1122 }
1123
1124 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1125 {
1126         struct sip_outbound_registration *registration = obj;
1127
1128         return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
1129 }
1130
1131 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
1132 {
1133         const struct sip_outbound_registration *registration = obj;
1134
1135         return ast_sip_auths_to_str(&registration->outbound_auths, buf);
1136 }
1137
1138 static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
1139 {
1140         const struct sip_outbound_registration *registration = obj;
1141         int i;
1142         struct ast_variable *head = NULL;
1143
1144         for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
1145                 ast_variable_list_append(&head, ast_variable_new("outbound_auth",
1146                         AST_VECTOR_GET(&registration->outbound_auths, i), ""));
1147         }
1148
1149         if (head) {
1150                 *fields = head;
1151         }
1152
1153         return 0;
1154 }
1155
1156 static int unregister_task(void *obj)
1157 {
1158         RAII_VAR(struct sip_outbound_registration_state*, state, obj, ao2_cleanup);
1159         struct pjsip_regc *client = state->client_state->client;
1160         pjsip_tx_data *tdata;
1161
1162         cancel_registration(state->client_state);
1163
1164         if (pjsip_regc_unregister(client, &tdata) != PJ_SUCCESS) {
1165                 return 0;
1166         }
1167
1168         ao2_ref(state->client_state, +1);
1169         if (pjsip_regc_send(client, tdata) != PJ_SUCCESS) {
1170                 ao2_cleanup(state->client_state);
1171         }
1172
1173         return 0;
1174 }
1175
1176 static int queue_unregister(struct sip_outbound_registration_state *state)
1177 {
1178         ao2_ref(state, +1);
1179         if (ast_sip_push_task(state->client_state->serializer, unregister_task, state)) {
1180                 ao2_ref(state, -1);
1181                 return -1;
1182         }
1183
1184         return 0;
1185 }
1186
1187 static int queue_register(struct sip_outbound_registration_state *state)
1188 {
1189         ao2_ref(state, +1);
1190         if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) {
1191                 ao2_ref(state, -1);
1192                 return -1;
1193         }
1194
1195         return 0;
1196 }
1197
1198 static char *cli_complete_registration(const char *line, const char *word,
1199                                        int pos, int state)
1200 {
1201         char *result = NULL;
1202         int wordlen;
1203         int which = 0;
1204         struct sip_outbound_registration *registration;
1205         RAII_VAR(struct ao2_container *, registrations, NULL, ao2_cleanup);
1206         struct ao2_iterator i;
1207
1208         if (pos != 3) {
1209                 return NULL;
1210         }
1211
1212         wordlen = strlen(word);
1213         registrations = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
1214                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1215         if (!registrations) {
1216                 return NULL;
1217         }
1218
1219         i = ao2_iterator_init(registrations, 0);
1220         while ((registration = ao2_iterator_next(&i))) {
1221                 const char *name = ast_sorcery_object_get_id(registration);
1222                 if (!strncasecmp(word, name, wordlen) && ++which > state) {
1223                         result = ast_strdup(name);
1224                 }
1225
1226                 ao2_cleanup(registration);
1227                 if (result) {
1228                         break;
1229                 }
1230         }
1231         ao2_iterator_destroy(&i);
1232         return result;
1233 }
1234
1235 static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1236 {
1237         RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
1238         const char *registration_name;
1239
1240         switch (cmd) {
1241         case CLI_INIT:
1242                 e->command = "pjsip send unregister";
1243                 e->usage =
1244                         "Usage: pjsip send unregister <registration>\n"
1245                         "       Unregisters the specified outbound registration and stops future registration attempts.\n";
1246                 return NULL;
1247         case CLI_GENERATE:
1248                 return cli_complete_registration(a->line, a->word, a->pos, a->n);
1249         }
1250
1251         if (a->argc != 4) {
1252                 return CLI_SHOWUSAGE;
1253         }
1254
1255         registration_name = a->argv[3];
1256
1257         state = get_state(registration_name);
1258         if (!state) {
1259                 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
1260                 return CLI_FAILURE;
1261         }
1262
1263         if (queue_unregister(state)) {
1264                 ast_cli(a->fd, "Failed to queue unregistration");
1265                 return 0;
1266         }
1267
1268         return CLI_SUCCESS;
1269 }
1270
1271 static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1272 {
1273         RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
1274         const char *registration_name;
1275
1276         switch (cmd) {
1277         case CLI_INIT:
1278                 e->command = "pjsip send register";
1279                 e->usage =
1280                         "Usage: pjsip send register <registration>\n"
1281                         "       Unregisters the specified outbound "
1282                         "registration then re-registers and re-schedules it.\n";
1283                 return NULL;
1284         case CLI_GENERATE:
1285                 return cli_complete_registration(a->line, a->word, a->pos, a->n);
1286         }
1287
1288         if (a->argc != 4) {
1289                 return CLI_SHOWUSAGE;
1290         }
1291
1292         registration_name = a->argv[3];
1293
1294         state = get_state(registration_name);
1295         if (!state) {
1296                 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
1297                 return CLI_FAILURE;
1298         }
1299
1300         /* We need to serialize the unregister and register so they need
1301          * to be queued as separate tasks.
1302          */
1303         if (queue_unregister(state)) {
1304                 ast_cli(a->fd, "Failed to queue unregistration");
1305                 return 0;
1306         }
1307         if (queue_register(state)) {
1308                 ast_cli(a->fd, "Failed to queue registration");
1309                 return 0;
1310         }
1311
1312         return CLI_SUCCESS;
1313 }
1314
1315 static int ami_unregister(struct mansession *s, const struct message *m)
1316 {
1317         const char *registration_name = astman_get_header(m, "Registration");
1318         RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
1319
1320         if (ast_strlen_zero(registration_name)) {
1321                 astman_send_error(s, m, "Registration parameter missing.");
1322                 return 0;
1323         }
1324
1325         state = get_state(registration_name);
1326         if (!state) {
1327                 astman_send_error(s, m, "Unable to retrieve registration entry\n");
1328                 return 0;
1329         }
1330
1331         if (queue_unregister(state)) {
1332                 astman_send_ack(s, m, "Failed to queue unregistration");
1333                 return 0;
1334         }
1335
1336         astman_send_ack(s, m, "Unregistration sent");
1337         return 0;
1338 }
1339
1340 static int ami_register(struct mansession *s, const struct message *m)
1341 {
1342         const char *registration_name = astman_get_header(m, "Registration");
1343         RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
1344
1345         if (ast_strlen_zero(registration_name)) {
1346                 astman_send_error(s, m, "Registration parameter missing.");
1347                 return 0;
1348         }
1349
1350         state = get_state(registration_name);
1351         if (!state) {
1352                 astman_send_error(s, m, "Unable to retrieve registration entry\n");
1353                 return 0;
1354         }
1355
1356         /* We need to serialize the unregister and register so they need
1357          * to be queued as separate tasks.
1358          */
1359         if (queue_unregister(state)) {
1360                 astman_send_ack(s, m, "Failed to queue unregistration");
1361                 return 0;
1362         }
1363         if (queue_register(state)) {
1364                 astman_send_ack(s, m, "Failed to queue unregistration");
1365                 return 0;
1366         }
1367
1368         astman_send_ack(s, m, "Reregistration sent");
1369         return 0;
1370 }
1371
1372 struct sip_ami_outbound {
1373         struct ast_sip_ami *ami;
1374         int registered;
1375         int not_registered;
1376         struct sip_outbound_registration *registration;
1377 };
1378
1379 static int ami_outbound_registration_task(void *obj)
1380 {
1381         struct sip_ami_outbound *ami = obj;
1382         RAII_VAR(struct ast_str *, buf, NULL, ast_free);
1383         struct sip_outbound_registration_state *state;
1384
1385         buf = ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami);
1386         if (!buf) {
1387                 return -1;
1388         }
1389
1390         ast_sip_sorcery_object_to_ami(ami->registration, &buf);
1391
1392         if ((state = get_state(ast_sorcery_object_get_id(ami->registration)))) {
1393                 pjsip_regc_info info;
1394
1395                 if (state->client_state->status == SIP_REGISTRATION_REGISTERED) {
1396                         ++ami->registered;
1397                 } else {
1398                         ++ami->not_registered;
1399                 }
1400
1401                 ast_str_append(&buf, 0, "Status: %s\r\n",
1402                         sip_outbound_registration_status_str[state->client_state->status]);
1403
1404                 pjsip_regc_get_info(state->client_state->client, &info);
1405                 ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg);
1406                 ao2_ref(state, -1);
1407         }
1408
1409         astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
1410         return ast_sip_format_auths_ami(&ami->registration->outbound_auths, ami->ami);
1411 }
1412
1413 static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
1414 {
1415         struct sip_ami_outbound *ami = arg;
1416
1417         ami->registration = obj;
1418         return ast_sip_push_task_synchronous(
1419                 NULL, ami_outbound_registration_task, ami);
1420 }
1421
1422 static int ami_show_outbound_registrations(struct mansession *s,
1423                                            const struct message *m)
1424 {
1425         struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
1426         struct sip_ami_outbound ami_outbound = { .ami = &ami };
1427         RAII_VAR(struct ao2_container *, regs, get_registrations(), ao2_cleanup);
1428
1429         if (!regs) {
1430                 astman_send_error(s, m, "Unable to retreive "
1431                                   "outbound registrations\n");
1432                 return -1;
1433         }
1434
1435         astman_send_listack(s, m, "Following are Events for each Outbound registration",
1436                 "start");
1437
1438         ao2_callback(regs, OBJ_NODATA, ami_outbound_registration_detail, &ami_outbound);
1439
1440         astman_send_list_complete_start(s, m, "OutboundRegistrationDetailComplete",
1441                 ami_outbound.registered + ami_outbound.not_registered);
1442         astman_append(s,
1443                 "Registered: %d\r\n"
1444                 "NotRegistered: %d\r\n",
1445                 ami_outbound.registered,
1446                 ami_outbound.not_registered);
1447         astman_send_list_complete_end(s);
1448         return 0;
1449 }
1450
1451 static struct ao2_container *cli_get_container(void)
1452 {
1453         RAII_VAR(struct ao2_container *, container, get_registrations(), ao2_cleanup);
1454         struct ao2_container *s_container;
1455
1456         if (!container) {
1457                 return NULL;
1458         }
1459
1460         s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
1461                 ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
1462         if (!s_container) {
1463                 return NULL;
1464         }
1465
1466         if (ao2_container_dup(s_container, container, 0)) {
1467                 ao2_ref(s_container, -1);
1468                 return NULL;
1469         }
1470
1471         return s_container;
1472 }
1473
1474 static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
1475 {
1476         ao2_callback(container, OBJ_NODATA, callback, args);
1477
1478         return 0;
1479 }
1480
1481 static void *cli_retrieve_by_id(const char *id)
1482 {
1483         struct ao2_container *states;
1484         void *obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
1485
1486         if (!obj) {
1487                 /* if the object no longer exists then remove its state  */
1488                 ao2_find((states = ao2_global_obj_ref(current_states)),
1489                          id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
1490                 ao2_ref(states, -1);
1491         }
1492
1493         return obj;
1494 }
1495
1496 static int cli_print_header(void *obj, void *arg, int flags)
1497 {
1498         struct ast_sip_cli_context *context = arg;
1499
1500         ast_assert(context->output_buffer != NULL);
1501
1502         ast_str_append(&context->output_buffer, 0,
1503                 " <Registration/ServerURI..............................>  <Auth..........>  <Status.......>\n");
1504
1505         return 0;
1506 }
1507
1508 static int cli_print_body(void *obj, void *arg, int flags)
1509 {
1510         struct sip_outbound_registration *registration = obj;
1511         struct ast_sip_cli_context *context = arg;
1512         const char *id = ast_sorcery_object_get_id(registration);
1513         struct sip_outbound_registration_state *state = get_state(id);
1514 #define REGISTRATION_URI_FIELD_LEN      53
1515
1516         ast_assert(context->output_buffer != NULL);
1517
1518         if (!state) {
1519                 return 0;
1520         }
1521
1522         ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s  %-16s  %-16s\n",
1523                 id,
1524                 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
1525                 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
1526                 registration->server_uri,
1527                 AST_VECTOR_SIZE(&registration->outbound_auths)
1528                         ? AST_VECTOR_GET(&registration->outbound_auths, 0)
1529                         : "n/a",
1530                 sip_outbound_registration_status_str[state->client_state->status]);
1531         ao2_ref(state, -1);
1532
1533         if (context->show_details
1534                 || (context->show_details_only_level_0 && context->indent_level == 0)) {
1535                 ast_str_append(&context->output_buffer, 0, "\n");
1536                 ast_sip_cli_print_sorcery_objectset(registration, context, 0);
1537         }
1538
1539         return 0;
1540 }
1541
1542 /*
1543  * A function pointer to callback needs to be within the
1544  * module in order to avoid problems with an undefined
1545  * symbol when the module is loaded.
1546  */
1547 static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1548 {
1549         return ast_sip_cli_traverse_objects(e, cmd, a);
1550 }
1551
1552 static struct ast_cli_entry cli_outbound_registration[] = {
1553         AST_CLI_DEFINE(cli_unregister, "Unregisters outbound registration target"),
1554         AST_CLI_DEFINE(cli_register, "Registers an outbound registration target"),
1555         AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
1556                 .command = "pjsip list registrations",
1557                 .usage = "Usage: pjsip list registrations\n"
1558                                  "       List the configured PJSIP Registrations\n"),
1559         AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
1560                 .command = "pjsip show registrations",
1561                 .usage = "Usage: pjsip show registrations\n"
1562                                  "       Show the configured PJSIP Registrations\n"),
1563         AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
1564                 .command = "pjsip show registration",
1565                 .usage = "Usage: pjsip show registration <id>\n"
1566                                  "       Show the configured PJSIP Registration\n"),
1567 };
1568
1569 static struct ast_sip_cli_formatter_entry *cli_formatter;
1570
1571 static void auth_observer(const char *type)
1572 {
1573         struct sip_outbound_registration *registration;
1574         struct sip_outbound_registration_state *state;
1575         struct ao2_container *regs;
1576         const char *registration_id;
1577         struct ao2_iterator i;
1578
1579         ast_debug(4, "Auths updated. Checking for any outbound registrations that are in permanent rejected state so they can be retried\n");
1580
1581         regs = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
1582                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1583         if (!regs || ao2_container_count(regs) == 0) {
1584                 ao2_cleanup(regs);
1585                 return;
1586         }
1587
1588         i = ao2_iterator_init(regs, 0);
1589         for (; (registration = ao2_iterator_next(&i)); ao2_ref(registration, -1)) {
1590                 registration_id = ast_sorcery_object_get_id(registration);
1591                 state = get_state(registration_id);
1592                 if (state && state->client_state->status == SIP_REGISTRATION_REJECTED_PERMANENT) {
1593                         ast_debug(4, "Trying outbound registration '%s' again\n", registration_id);
1594
1595                         if (ast_sip_push_task(state->client_state->serializer,
1596                                               sip_outbound_registration_perform, ao2_bump(state))) {
1597                                 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", registration_id);
1598                                 ao2_ref(state, -1);
1599                         }
1600                 }
1601                 ao2_cleanup(state);
1602         }
1603         ao2_iterator_destroy(&i);
1604         ao2_cleanup(regs);
1605 }
1606
1607 const struct ast_sorcery_observer observer_callbacks = {
1608         .loaded = auth_observer,
1609 };
1610
1611 static int unload_module(void)
1612 {
1613         ast_sip_unregister_endpoint_identifier(&line_identifier);
1614         ast_sorcery_observer_remove(ast_sip_get_sorcery(), "auth", &observer_callbacks);
1615         ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1616         ast_sip_unregister_cli_formatter(cli_formatter);
1617         ast_manager_unregister("PJSIPShowRegistrationsOutbound");
1618         ast_manager_unregister("PJSIPUnregister");
1619         ast_manager_unregister("PJSIPRegister");
1620
1621         ao2_global_obj_release(current_states);
1622
1623         return 0;
1624 }
1625
1626 static int load_module(void)
1627 {
1628         struct ao2_container *registrations, *new_states;
1629         CHECK_PJSIP_MODULE_LOADED();
1630
1631         ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_registration");
1632         ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
1633
1634         if (ast_sorcery_object_register(ast_sip_get_sorcery(), "registration", sip_outbound_registration_alloc, NULL, sip_outbound_registration_apply)) {
1635                 return AST_MODULE_LOAD_DECLINE;
1636         }
1637
1638         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
1639         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, server_uri));
1640         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
1641         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
1642         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
1643         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
1644         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
1645         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
1646         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));
1647         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
1648         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));
1649         ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, outbound_auths_to_var_list, 0, 0);
1650         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
1651         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));
1652         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));
1653         ast_sip_register_endpoint_identifier(&line_identifier);
1654
1655         ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
1656         ast_manager_register_xml("PJSIPRegister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_register);
1657         ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations);
1658
1659         cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1660         if (!cli_formatter) {
1661                 ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
1662                 unload_module();
1663                 return -1;
1664         }
1665         cli_formatter->name = "registration";
1666         cli_formatter->print_header = cli_print_header;
1667         cli_formatter->print_body = cli_print_body;
1668         cli_formatter->get_container = cli_get_container;
1669         cli_formatter->iterate = cli_iterator;
1670         cli_formatter->get_id = ast_sorcery_object_get_id;
1671         cli_formatter->retrieve_by_id = cli_retrieve_by_id;
1672
1673         ast_sip_register_cli_formatter(cli_formatter);
1674         ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1675
1676         if (!(new_states = ao2_container_alloc(
1677                       DEFAULT_STATE_BUCKETS, registration_state_hash, registration_state_cmp))) {
1678                 ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
1679                 unload_module();
1680                 return AST_MODULE_LOAD_FAILURE;
1681         }
1682         ao2_global_obj_replace_unref(current_states, new_states);
1683         ao2_ref(new_states, -1);
1684
1685         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
1686         if (!(registrations = get_registrations())) {
1687                 unload_module();
1688                 return AST_MODULE_LOAD_FAILURE;
1689         }
1690         ao2_ref(registrations, -1);
1691
1692         ast_sorcery_observer_add(ast_sip_get_sorcery(), "auth", &observer_callbacks);
1693
1694         return AST_MODULE_LOAD_SUCCESS;
1695 }
1696
1697 static int reload_module(void)
1698 {
1699         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
1700         ao2_cleanup(get_registrations());
1701         return 0;
1702 }
1703
1704 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
1705                 .support_level = AST_MODULE_SUPPORT_CORE,
1706                 .load = load_module,
1707                 .reload = reload_module,
1708                 .unload = unload_module,
1709                 .load_pri = AST_MODPRI_APP_DEPEND,
1710                );