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