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