Add missing module dependencies to various res_sip* modules
[asterisk/asterisk.git] / res / res_sip_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_sip</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_sip.h"
31 #include "asterisk/module.h"
32 #include "asterisk/taskprocessor.h"
33
34 /*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
35 #define REREGISTER_BUFFER_TIME 10
36
37 /*! \brief Various states that an outbound registration may be in */
38 enum sip_outbound_registration_status {
39         /*! \brief Currently unregistered */
40         SIP_REGISTRATION_UNREGISTERED = 0,
41         /*! \brief Registered, yay! */
42         SIP_REGISTRATION_REGISTERED,
43         /*! \brief Registration was rejected, but response was temporal */
44         SIP_REGISTRATION_REJECTED_TEMPORARY,
45         /*! \brief Registration was rejected, permanently */
46         SIP_REGISTRATION_REJECTED_PERMANENT,
47         /*! \brief Registration has been stopped */
48         SIP_REGISTRATION_STOPPED,
49 };
50
51 /*! \brief Outbound registration client state information (persists for lifetime of regc) */
52 struct sip_outbound_registration_client_state {
53         /*! \brief Current status of this registration */
54         enum sip_outbound_registration_status status;
55         /*! \brief Outbound registration client */
56         pjsip_regc *client;
57         /*! \brief Timer entry for retrying on temporal responses */
58         pj_timer_entry timer;
59         /*! \brief Current number of retries */
60         unsigned int retries;
61         /*! \brief Maximum number of retries permitted */
62         unsigned int max_retries;
63         /*! \brief Interval at which retries should occur for temporal responses */
64         unsigned int retry_interval;
65         /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
66         unsigned int auth_rejection_permanent;
67         /*! \brief Serializer for stuff and things */
68         struct ast_taskprocessor *serializer;
69         /*! \brief Configured authentication credentials */
70         const char **sip_outbound_auths;
71         /*! \brief Number of configured auths */
72         size_t num_outbound_auths;
73         /*! \brief Registration should be destroyed after completion of transaction */
74         unsigned int destroy:1;
75 };
76
77 /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
78 struct sip_outbound_registration_state {
79         /*! \brief Client state information */
80         struct sip_outbound_registration_client_state *client_state;
81 };
82
83 /*! \brief Outbound registration information */
84 struct sip_outbound_registration {
85         /*! \brief Sorcery object details */
86         SORCERY_OBJECT(details);
87         /*! \brief Stringfields */
88         AST_DECLARE_STRING_FIELDS(
89                 /*! \brief URI for the registrar */
90                 AST_STRING_FIELD(server_uri);
91                 /*! \brief URI for the AOR */
92                 AST_STRING_FIELD(client_uri);
93                 /*! \brief Optional user for contact header */
94                 AST_STRING_FIELD(contact_user);
95                 /*! \brief Explicit transport to use for registration */
96                 AST_STRING_FIELD(transport);
97                 /*! \brief Outbound proxy to use */
98                 AST_STRING_FIELD(outbound_proxy);
99         );
100         /*! \brief Requested expiration time */
101         unsigned int expiration;
102         /*! \brief Interval at which retries should occur for temporal responses */
103         unsigned int retry_interval;
104         /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
105         unsigned int auth_rejection_permanent;
106         /*! \brief Maximum number of retries permitted */
107         unsigned int max_retries;
108         /*! \brief Outbound registration state */
109         struct sip_outbound_registration_state *state;
110         /*! \brief Configured authentication credentials */
111         const char **sip_outbound_auths;
112         /*! \brief Number of configured auths */
113         size_t num_outbound_auths;
114 };
115
116 static void destroy_auths(const char **auths, size_t num_auths)
117 {
118         int i;
119         for (i = 0; i < num_auths; ++i) {
120                 ast_free((char *) auths[i]);
121         }
122         ast_free(auths);
123 }
124
125 /*! \brief Helper function which cancels the timer on a client */
126 static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
127 {
128         if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &client_state->timer)) {
129                 /* The timer was successfully cancelled, drop the refcount of client_state */
130                 ao2_ref(client_state, -1);
131         }
132 }
133
134 /*! \brief Callback function for registering */
135 static int handle_client_registration(void *data)
136 {
137         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
138         pjsip_tx_data *tdata;
139
140         cancel_registration(client_state);
141
142         if ((client_state->status == SIP_REGISTRATION_STOPPED) ||
143                 (pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS)) {
144                 return 0;
145         }
146
147         /* Due to the registration the callback may now get called, so bump the ref count */
148         ao2_ref(client_state, +1);
149         if (pjsip_regc_send(client_state->client, tdata) != PJ_SUCCESS) {
150                 ao2_ref(client_state, -1);
151                 pjsip_tx_data_dec_ref(tdata);
152         }
153
154         return 0;
155 }
156
157 /*! \brief Timer callback function, used just for registrations */
158 static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
159 {
160         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, entry->user_data, ao2_cleanup);
161
162         ao2_ref(client_state, +1);
163         if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
164                 ast_log(LOG_WARNING, "Failed to pass outbound registration to threadpool\n");
165                 ao2_ref(client_state, -1);
166         }
167
168         entry->id = 0;
169 }
170
171 /*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
172 static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
173 {
174         pj_time_val delay = { .sec = seconds, };
175
176         cancel_registration(client_state);
177
178         ao2_ref(client_state, +1);
179         if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
180                 ast_log(LOG_WARNING, "Failed to pass timed registration to scheduler\n");
181                 ao2_ref(client_state, -1);
182         }
183 }
184
185 /*! \brief Callback function for unregistering (potentially) and destroying state */
186 static int handle_client_state_destruction(void *data)
187 {
188         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
189         pjsip_regc_info info;
190
191         cancel_registration(client_state);
192
193         pjsip_regc_get_info(client_state->client, &info);
194
195         if (info.is_busy == PJ_TRUE) {
196                 /* If a client transaction is in progress we defer until it is complete */
197                 client_state->destroy = 1;
198                 return 0;
199         }
200
201         if (client_state->status != SIP_REGISTRATION_UNREGISTERED && client_state->status != SIP_REGISTRATION_REJECTED_PERMANENT) {
202                 pjsip_tx_data *tdata;
203
204                 if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS) {
205                         pjsip_regc_send(client_state->client, tdata);
206                 }
207         }
208
209         pjsip_regc_destroy(client_state->client);
210
211         client_state->status = SIP_REGISTRATION_STOPPED;
212         destroy_auths(client_state->sip_outbound_auths, client_state->num_outbound_auths);
213
214         return 0;
215 }
216
217 /*! \brief Structure for registration response */
218 struct registration_response {
219         /*! \brief Response code for the registration attempt */
220         int code;
221         /*! \brief Expiration time for registration */
222         int expiration;
223         /*! \brief Retry-After value */
224         int retry_after;
225         /*! \brief Outbound registration client state */
226         struct sip_outbound_registration_client_state *client_state;
227         /*! \brief The response message */
228         pjsip_rx_data *rdata;
229         /*! \brief The response transaction */
230         pjsip_transaction *tsx;
231 };
232
233 /*! \brief Registration response structure destructor */
234 static void registration_response_destroy(void *obj)
235 {
236         struct registration_response *response = obj;
237
238         pjsip_rx_data_free_cloned(response->rdata);
239         ao2_cleanup(response->client_state);
240 }
241
242 /* \brief Helper funtion which determines if a response code is temporal or not */
243 static int sip_outbound_registration_is_temporal(unsigned int code,
244                 struct sip_outbound_registration_client_state *client_state)
245 {
246         /* Shamelessly taken from pjsua */
247         if (code == PJSIP_SC_REQUEST_TIMEOUT ||
248                 code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
249                 code == PJSIP_SC_BAD_GATEWAY ||
250                 code == PJSIP_SC_SERVICE_UNAVAILABLE ||
251                 code == PJSIP_SC_SERVER_TIMEOUT ||
252                 ((code == PJSIP_SC_UNAUTHORIZED ||
253                   code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
254                  !client_state->auth_rejection_permanent) ||
255                 PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
256                 return 1;
257         } else {
258                 return 0;
259         }
260 }
261
262 /*! \brief Callback function for handling a response to a registration attempt */
263 static int handle_registration_response(void *data)
264 {
265         RAII_VAR(struct registration_response *, response, data, ao2_cleanup);
266         pjsip_regc_info info;
267         char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
268
269         if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
270                 return 0;
271         }
272
273         pjsip_regc_get_info(response->client_state->client, &info);
274         ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
275         ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
276
277         if (response->code == 401 || response->code == 407) {
278                 pjsip_tx_data *tdata;
279                 if (!ast_sip_create_request_with_auth(response->client_state->sip_outbound_auths, response->client_state->num_outbound_auths,
280                                 response->rdata, response->tsx, &tdata)) {
281                         pjsip_regc_send(response->client_state->client, tdata);
282                         return 0;
283                 }
284                 /* Otherwise, fall through so the failure is processed appropriately */
285         }
286
287         if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
288                 /* If the registration went fine simply reschedule registration for the future */
289                 response->client_state->status = SIP_REGISTRATION_REGISTERED;
290                 response->client_state->retries = 0;
291                 schedule_registration(response->client_state, response->expiration - REREGISTER_BUFFER_TIME);
292         } else if (response->retry_after) {
293                 /* If we have been instructed to retry after a period of time, schedule it as such */
294                 response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
295                 schedule_registration(response->client_state, response->retry_after);
296                 ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on registration attempt to '%s', instructed to retry in '%d'\n",
297                         response->code, server_uri, client_uri, response->retry_after);
298         } else if (response->client_state->retry_interval && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
299                 if (response->client_state->retries == response->client_state->max_retries) {
300                         /* If we received enough temporal responses to exceed our maximum give up permanently */
301                         response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
302                         ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
303                                 server_uri, client_uri);
304                 } else {
305                         /* On the other hand if we can still try some more do so */
306                         response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
307                         response->client_state->retries++;
308                         schedule_registration(response->client_state, response->client_state->retry_interval);
309                         ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on registration attempt to '%s', retrying in '%d' seconds\n",
310                                 response->code, server_uri, client_uri, response->client_state->retry_interval);
311                 }
312         } else {
313                 /* Finally if there's no hope of registering give up */
314                 response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
315                 ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
316                         response->code, server_uri, client_uri);
317         }
318
319         /* If deferred destruction is in use see if we need to destroy now */
320         if (response->client_state->destroy) {
321                 handle_client_state_destruction(response->client_state);
322         }
323
324         return 0;
325 }
326
327 /*! \brief Callback function for outbound registration client */
328 static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
329 {
330         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, param->token, ao2_cleanup);
331         struct registration_response *response = ao2_alloc(sizeof(*response), registration_response_destroy);
332         struct pjsip_retry_after_hdr *retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER, NULL);
333
334         response->code = param->code;
335         response->expiration = param->expiration;
336         response->retry_after = retry_after ? retry_after->ivalue : 0;
337         response->client_state = client_state;
338         response->tsx = pjsip_rdata_get_tsx(param->rdata);
339         pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
340         ao2_ref(response->client_state, +1);
341
342         if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
343                 ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
344                 ao2_cleanup(response);
345         }
346 }
347
348 /*! \brief Destructor function for registration state */
349 static void sip_outbound_registration_state_destroy(void *obj)
350 {
351         struct sip_outbound_registration_state *state = obj;
352
353         if (!state->client_state) {
354                 return;
355         }
356
357         if (state->client_state->serializer && ast_sip_push_task(state->client_state->serializer, handle_client_state_destruction, state->client_state)) {
358                 ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
359                 ao2_ref(state->client_state, -1);
360         }
361 }
362
363 /*! \brief Destructor function for client registration state */
364 static void sip_outbound_registration_client_state_destroy(void *obj)
365 {
366         struct sip_outbound_registration_client_state *client_state = obj;
367
368         ast_taskprocessor_unreference(client_state->serializer);
369 }
370
371 /*! \brief Allocator function for registration state */
372 static struct sip_outbound_registration_state *sip_outbound_registration_state_alloc(void)
373 {
374         struct sip_outbound_registration_state *state = ao2_alloc(sizeof(*state), sip_outbound_registration_state_destroy);
375
376         if (!state || !(state->client_state = ao2_alloc(sizeof(*state->client_state), sip_outbound_registration_client_state_destroy))) {
377                 ao2_cleanup(state);
378                 return NULL;
379         }
380
381         if ((pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state, sip_outbound_registration_response_cb, &state->client_state->client) != PJ_SUCCESS) ||
382                 !(state->client_state->serializer = ast_sip_create_serializer())) {
383                 /* This is on purpose, normal operation will have it be deallocated within the serializer */
384                 pjsip_regc_destroy(state->client_state->client);
385                 ao2_cleanup(state->client_state);
386                 ao2_cleanup(state);
387                 return NULL;
388         }
389
390         state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
391         state->client_state->timer.user_data = state->client_state;
392         state->client_state->timer.cb = sip_outbound_registration_timer_cb;
393
394         return state;
395 }
396
397 /*! \brief Destructor function for registration information */
398 static void sip_outbound_registration_destroy(void *obj)
399 {
400         struct sip_outbound_registration *registration = obj;
401
402         ao2_cleanup(registration->state);
403         destroy_auths(registration->sip_outbound_auths, registration->num_outbound_auths);
404
405         ast_string_field_free_memory(registration);
406 }
407
408 /*! \brief Allocator function for registration information */
409 static void *sip_outbound_registration_alloc(const char *name)
410 {
411         struct sip_outbound_registration *registration = ao2_alloc(sizeof(*registration), sip_outbound_registration_destroy);
412
413         if (!registration || ast_string_field_init(registration, 256)) {
414                 ao2_cleanup(registration);
415                 return NULL;
416         }
417
418         return registration;
419 }
420
421 /*! \brief Helper function which populates a pj_str_t with a contact header */
422 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)
423 {
424         pj_str_t tmp, local_addr;
425         pjsip_uri *uri;
426         pjsip_sip_uri *sip_uri;
427         pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
428         int local_port;
429
430         pj_strdup_with_null(pool, &tmp, target);
431
432         if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
433             (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
434                 return -1;
435         }
436
437         sip_uri = pjsip_uri_get_uri(uri);
438
439         if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
440                 type = PJSIP_TRANSPORT_TLS;
441         } else if (!sip_uri->transport_param.slen) {
442                 type = PJSIP_TRANSPORT_UDP;
443         } else {
444                 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
445         }
446
447         if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
448                 return -1;
449         }
450
451         if (pj_strchr(&sip_uri->host, ':')) {
452                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
453         }
454
455         if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
456                                                               &local_addr, &local_port) != PJ_SUCCESS) {
457                 return -1;
458         }
459
460         if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
461                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
462         }
463
464         contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
465         contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
466                                       "<%s:%s@%s%.*s%s:%d%s%s>",
467                                       (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
468                                       user,
469                                       (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
470                                       (int)local_addr.slen,
471                                       local_addr.ptr,
472                                       (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
473                                       local_port,
474                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
475                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
476
477         return 0;
478 }
479
480 /*!
481  * \internal
482  * \brief Check if a registration can be reused
483  *
484  * This checks if the existing outbound registration's configuration differs from a newly-applied
485  * outbound registration to see if the applied one.
486  *
487  * \param existing The pre-existing outbound registration
488  * \param applied The newly-created registration
489  */
490 static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
491 {
492         int i;
493
494         if (strcmp(existing->server_uri, applied->server_uri) || strcmp(existing->client_uri, applied->client_uri) ||
495                 strcmp(existing->transport, applied->transport) || strcmp(existing->contact_user, applied->contact_user) ||
496                 strcmp(existing->outbound_proxy, applied->outbound_proxy) || existing->num_outbound_auths != applied->num_outbound_auths ||
497                 existing->auth_rejection_permanent != applied->auth_rejection_permanent) {
498                 return 0;
499         }
500
501         for (i = 0; i < existing->num_outbound_auths; ++i) {
502                 if (strcmp(existing->sip_outbound_auths[i], applied->sip_outbound_auths[i])) {
503                         return 0;
504                 }
505         }
506
507         return 1;
508 }
509
510 /*! \brief Apply function which finds or allocates a state structure */
511 static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
512 {
513         RAII_VAR(struct sip_outbound_registration *, existing, ast_sorcery_retrieve_by_id(sorcery, "registration", ast_sorcery_object_get_id(obj)), ao2_cleanup);
514         struct sip_outbound_registration *applied = obj;
515         pj_str_t server_uri, client_uri, contact_uri;
516         pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
517
518         if (!existing) {
519                 /* If no existing registration exists we can just start fresh easily */
520                 applied->state = sip_outbound_registration_state_alloc();
521         } else {
522                 /* If there is an existing registration things are more complicated, we can immediately reuse this state if most stuff remains unchanged */
523                 if (can_reuse_registration(existing, applied)) {
524                         applied->state = existing->state;
525                         ao2_ref(applied->state, +1);
526                         return 0;
527                 }
528                 applied->state = sip_outbound_registration_state_alloc();
529         }
530
531         if (!applied->state) {
532                 return -1;
533         }
534
535         if (!ast_strlen_zero(applied->transport)) {
536                 RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", applied->transport), ao2_cleanup);
537
538                 if (!transport || !transport->state) {
539                         return -1;
540                 }
541
542                 if (transport->type == AST_SIP_TRANSPORT_UDP) {
543                         selector.type = PJSIP_TPSELECTOR_TRANSPORT;
544                         selector.u.transport = transport->state->transport;
545                 } else if (transport->type == AST_SIP_TRANSPORT_TCP || transport->type == AST_SIP_TRANSPORT_TLS) {
546                         selector.type = PJSIP_TPSELECTOR_LISTENER;
547                         selector.u.listener = transport->state->factory;
548                 } else {
549                         return -1;
550                 }
551         }
552
553         pjsip_regc_set_transport(applied->state->client_state->client, &selector);
554
555         if (!ast_strlen_zero(applied->outbound_proxy)) {
556                 pjsip_route_hdr route_set, *route;
557                 static const pj_str_t ROUTE_HNAME = { "Route", 5 };
558                 pj_str_t tmp;
559
560                 pj_list_init(&route_set);
561
562                 pj_strdup2_with_null(pjsip_regc_get_pool(applied->state->client_state->client), &tmp, applied->outbound_proxy);
563                 if (!(route = pjsip_parse_hdr(pjsip_regc_get_pool(applied->state->client_state->client), &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
564                         return -1;
565                 }
566                 pj_list_push_back(&route_set, route);
567
568                 pjsip_regc_set_route_set(applied->state->client_state->client, &route_set);
569         }
570
571         pj_cstr(&server_uri, applied->server_uri);
572
573         if (sip_dialog_create_contact(pjsip_regc_get_pool(applied->state->client_state->client), &contact_uri, S_OR(applied->contact_user, "s"), &server_uri, &selector)) {
574                 return -1;
575         }
576
577         pj_cstr(&client_uri, applied->client_uri);
578
579         if (pjsip_regc_init(applied->state->client_state->client, &server_uri, &client_uri, &client_uri, 1, &contact_uri, applied->expiration) != PJ_SUCCESS) {
580                 return -1;
581         }
582
583         return 0;
584 }
585
586 /*! \brief Helper function which performs a single registration */
587 static int sip_outbound_registration_perform(void *obj, void *arg, int flags)
588 {
589         struct sip_outbound_registration *registration = obj;
590         size_t i;
591
592         /* Just in case the client state is being reused for this registration, free the auth information */
593         destroy_auths(registration->state->client_state->sip_outbound_auths,
594                         registration->state->client_state->num_outbound_auths);
595         registration->state->client_state->num_outbound_auths = 0;
596
597         registration->state->client_state->sip_outbound_auths = ast_calloc(registration->num_outbound_auths, sizeof(char *));
598         for (i = 0; i < registration->num_outbound_auths; ++i) {
599                 registration->state->client_state->sip_outbound_auths[i] = ast_strdup(registration->sip_outbound_auths[i]);
600         }
601         registration->state->client_state->num_outbound_auths = registration->num_outbound_auths;
602         registration->state->client_state->retry_interval = registration->retry_interval;
603         registration->state->client_state->max_retries = registration->max_retries;
604         registration->state->client_state->retries = 0;
605
606         pjsip_regc_update_expires(registration->state->client_state->client, registration->expiration);
607
608         schedule_registration(registration->state->client_state, (ast_random() % 10) + 1);
609
610         return 0;
611 }
612
613 /*! \brief Helper function which performs all registrations */
614 static void sip_outbound_registration_perform_all(void)
615 {
616         RAII_VAR(struct ao2_container *, registrations, ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL), ao2_cleanup);
617
618         if (!registrations) {
619                 return;
620         }
621
622         ao2_callback(registrations, OBJ_NODATA, sip_outbound_registration_perform, NULL);
623 }
624
625 #define AUTH_INCREMENT 4
626
627 static const char **auth_alloc(const char *value, size_t *num_auths)
628 {
629         char *auths = ast_strdupa(value);
630         char *val;
631         int num_alloced = 0;
632         const char **alloced_auths = NULL;
633
634         while ((val = strsep(&auths, ","))) {
635                 if (*num_auths >= num_alloced) {
636                         size_t size;
637                         num_alloced += AUTH_INCREMENT;
638                         size = num_alloced * sizeof(char *);
639                         alloced_auths = ast_realloc(alloced_auths, size);
640                         if (!alloced_auths) {
641                                 goto failure;
642                         }
643                 }
644                 alloced_auths[*num_auths] = ast_strdup(val);
645                 if (!alloced_auths[*num_auths]) {
646                         goto failure;
647                 }
648                 ++(*num_auths);
649         }
650         return alloced_auths;
651
652 failure:
653         destroy_auths(alloced_auths, *num_auths);
654         return NULL;
655 }
656
657 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
658 {
659         struct sip_outbound_registration *registration = obj;
660
661         registration->sip_outbound_auths = auth_alloc(var->value, &registration->num_outbound_auths);
662         if (!registration->sip_outbound_auths) {
663                 return -1;
664         }
665         return 0;
666 }
667
668 static int load_module(void)
669 {
670         ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "res_sip.conf,criteria=type=registration");
671
672         if (ast_sorcery_object_register(ast_sip_get_sorcery(), "registration", sip_outbound_registration_alloc, NULL, sip_outbound_registration_apply)) {
673                 return AST_MODULE_LOAD_DECLINE;
674         }
675
676         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
677         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, server_uri));
678         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
679         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
680         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
681         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
682         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
683         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
684         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
685         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));
686         ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, NULL, 0, 0);
687         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
688         sip_outbound_registration_perform_all();
689
690         return AST_MODULE_LOAD_SUCCESS;
691 }
692
693 static int reload_module(void)
694 {
695         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
696         sip_outbound_registration_perform_all();
697         return 0;
698 }
699
700 static int unload_module(void)
701 {
702         return 0;
703 }
704
705 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP Outbound Registration Support",
706                 .load = load_module,
707                 .reload = reload_module,
708                 .unload = unload_module,
709                 .load_pri = AST_MODPRI_APP_DEPEND,
710                );