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