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