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