AMI: Remove no longer used parameter from astman_send_listack().
[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         ao2_ref(client_state, -1);
466
467         if ((client_state->status == SIP_REGISTRATION_STOPPED) ||
468                 (pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS)) {
469                 return 0;
470         }
471
472         pjsip_regc_get_info(client_state->client, &info);
473         ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
474         ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
475         ast_debug(3, "REGISTER attempt %u to '%s' with client '%s'\n",
476                   client_state->retries + 1, server_uri, client_uri);
477
478         if (client_state->support_path) {
479                 pjsip_supported_hdr *hdr;
480
481                 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
482                 if (!hdr) {
483                         /* insert a new Supported header */
484                         hdr = pjsip_supported_hdr_create(tdata->pool);
485                         if (!hdr) {
486                                 return -1;
487                         }
488
489                         pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
490                 }
491
492                 /* add on to the existing Supported header */
493                 pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
494         }
495
496         /* Due to the registration the callback may now get called, so bump the ref count */
497         ao2_ref(client_state, +1);
498         if (pjsip_regc_send(client_state->client, tdata) != PJ_SUCCESS) {
499                 ao2_ref(client_state, -1);
500         }
501
502         return 0;
503 }
504
505 /*! \brief Timer callback function, used just for registrations */
506 static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
507 {
508         struct sip_outbound_registration_client_state *client_state = entry->user_data;
509
510         ao2_ref(client_state, +1);
511         if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
512                 ast_log(LOG_WARNING, "Failed to pass outbound registration to threadpool\n");
513                 ao2_ref(client_state, -1);
514         }
515
516         entry->id = 0;
517 }
518
519 /*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
520 static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
521 {
522         pj_time_val delay = { .sec = seconds, };
523
524         cancel_registration(client_state);
525
526         ao2_ref(client_state, +1);
527         if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
528                 ast_log(LOG_WARNING, "Failed to pass timed registration to scheduler\n");
529                 ao2_ref(client_state, -1);
530         }
531 }
532
533 /*! \brief Callback function for unregistering (potentially) and destroying state */
534 static int handle_client_state_destruction(void *data)
535 {
536         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
537
538         cancel_registration(client_state);
539
540         if (client_state->client) {
541                 pjsip_regc_info info;
542
543                 pjsip_regc_get_info(client_state->client, &info);
544
545                 if (info.is_busy == PJ_TRUE) {
546                         /* If a client transaction is in progress we defer until it is complete */
547                         client_state->destroy = 1;
548                         return 0;
549                 }
550
551                 if (client_state->status != SIP_REGISTRATION_UNREGISTERED && client_state->status != SIP_REGISTRATION_REJECTED_PERMANENT) {
552                         pjsip_tx_data *tdata;
553
554                         if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS) {
555                                 pjsip_regc_send(client_state->client, tdata);
556                         }
557                 }
558
559                 pjsip_regc_destroy(client_state->client);
560         }
561
562         client_state->status = SIP_REGISTRATION_STOPPED;
563         ast_sip_auth_vector_destroy(&client_state->outbound_auths);
564
565         return 0;
566 }
567
568 /*! \brief Structure for registration response */
569 struct registration_response {
570         /*! \brief Response code for the registration attempt */
571         int code;
572         /*! \brief Expiration time for registration */
573         int expiration;
574         /*! \brief Retry-After value */
575         int retry_after;
576         /*! \brief Outbound registration client state */
577         struct sip_outbound_registration_client_state *client_state;
578         /*! \brief The response message */
579         pjsip_rx_data *rdata;
580         /*! \brief The response transaction */
581         pjsip_transaction *tsx;
582 };
583
584 /*! \brief Registration response structure destructor */
585 static void registration_response_destroy(void *obj)
586 {
587         struct registration_response *response = obj;
588
589         if (response->rdata) {
590                 pjsip_rx_data_free_cloned(response->rdata);
591         }
592
593         ao2_cleanup(response->client_state);
594 }
595
596 /* \brief Helper funtion which determines if a response code is temporal or not */
597 static int sip_outbound_registration_is_temporal(unsigned int code,
598                 struct sip_outbound_registration_client_state *client_state)
599 {
600         /* Shamelessly taken from pjsua */
601         if (code == PJSIP_SC_REQUEST_TIMEOUT ||
602                 code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
603                 code == PJSIP_SC_BAD_GATEWAY ||
604                 code == PJSIP_SC_SERVICE_UNAVAILABLE ||
605                 code == PJSIP_SC_SERVER_TIMEOUT ||
606                 ((code == PJSIP_SC_UNAUTHORIZED ||
607                   code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
608                  !client_state->auth_rejection_permanent) ||
609                 PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
610                 return 1;
611         } else {
612                 return 0;
613         }
614 }
615
616 static void schedule_retry(struct registration_response *response, unsigned int interval,
617                            const char *server_uri, const char *client_uri)
618 {
619         response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
620         schedule_registration(response->client_state, interval);
621
622         if (response->rdata) {
623                 ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
624                         "registration attempt to '%s', retrying in '%u'\n",
625                         response->code, server_uri, client_uri, interval);
626         } else {
627                 ast_log(LOG_WARNING, "No response received from '%s' on "
628                         "registration attempt to '%s', retrying in '%u'\n",
629                         server_uri, client_uri, interval);
630         }
631 }
632
633 /*! \brief Callback function for handling a response to a registration attempt */
634 static int handle_registration_response(void *data)
635 {
636         RAII_VAR(struct registration_response *, response, data, ao2_cleanup);
637         pjsip_regc_info info;
638         char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
639
640         if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
641                 return 0;
642         }
643
644         pjsip_regc_get_info(response->client_state->client, &info);
645         ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
646         ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
647
648         if (!response->client_state->auth_attempted &&
649                         (response->code == 401 || response->code == 407)) {
650                 pjsip_tx_data *tdata;
651                 if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
652                                 response->rdata, response->tsx, &tdata)) {
653                         ao2_ref(response->client_state, +1);
654                         response->client_state->auth_attempted = 1;
655                         if (pjsip_regc_send(response->client_state->client, tdata) != PJ_SUCCESS) {
656                                 response->client_state->auth_attempted = 0;
657                                 ao2_cleanup(response->client_state);
658                         }
659                         return 0;
660                 }
661                 /* Otherwise, fall through so the failure is processed appropriately */
662         }
663
664         response->client_state->auth_attempted = 0;
665
666         if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
667                 /* Check if this is in regards to registering or unregistering */
668                 if (response->expiration) {
669                         /* If the registration went fine simply reschedule registration for the future */
670                         ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
671                         response->client_state->status = SIP_REGISTRATION_REGISTERED;
672                         response->client_state->retries = 0;
673                         schedule_registration(response->client_state, response->expiration - REREGISTER_BUFFER_TIME);
674                 } else {
675                         ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
676                         response->client_state->status = SIP_REGISTRATION_UNREGISTERED;
677                 }
678         } else if (response->retry_after) {
679                 /* If we have been instructed to retry after a period of time, schedule it as such */
680                 schedule_retry(response, response->retry_after, server_uri, client_uri);
681         } else if (response->client_state->retry_interval && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
682                 if (response->client_state->retries == response->client_state->max_retries) {
683                         /* If we received enough temporal responses to exceed our maximum give up permanently */
684                         response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
685                         ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
686                                 server_uri, client_uri);
687                 } else {
688                         /* On the other hand if we can still try some more do so */
689                         response->client_state->retries++;
690                         schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
691                 }
692         } else {
693                 if (response->code == 403
694                         && response->client_state->forbidden_retry_interval
695                         && response->client_state->retries < response->client_state->max_retries) {
696                         /* A forbidden response retry interval is configured and there are retries remaining */
697                         response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
698                         response->client_state->retries++;
699                         schedule_registration(response->client_state, response->client_state->forbidden_retry_interval);
700                         ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
701                                 server_uri, client_uri, response->client_state->forbidden_retry_interval);
702                 } else {
703                         /* Finally if there's no hope of registering give up */
704                         response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
705                         if (response->rdata) {
706                                 ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
707                                         response->code, server_uri, client_uri);
708                         } else {
709                                 ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
710                         }
711                 }
712         }
713
714         ast_system_publish_registry("PJSIP", client_uri, server_uri, sip_outbound_registration_status_str[response->client_state->status], NULL);
715
716         /* If deferred destruction is in use see if we need to destroy now */
717         if (response->client_state->destroy) {
718                 handle_client_state_destruction(response->client_state);
719         }
720
721         return 0;
722 }
723
724 /*! \brief Callback function for outbound registration client */
725 static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
726 {
727         RAII_VAR(struct sip_outbound_registration_client_state *, client_state, param->token, ao2_cleanup);
728         struct registration_response *response = ao2_alloc(sizeof(*response), registration_response_destroy);
729
730         response->code = param->code;
731         response->expiration = param->expiration;
732         response->client_state = client_state;
733         ao2_ref(response->client_state, +1);
734
735         if (param->rdata) {
736                 struct pjsip_retry_after_hdr *retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER, NULL);
737
738                 response->retry_after = retry_after ? retry_after->ivalue : 0;
739                 response->tsx = pjsip_rdata_get_tsx(param->rdata);
740                 pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
741         }
742
743         if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
744                 ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
745                 ao2_cleanup(response);
746         }
747 }
748
749 /*! \brief Destructor function for registration state */
750 static void sip_outbound_registration_state_destroy(void *obj)
751 {
752         struct sip_outbound_registration_state *state = obj;
753
754         ao2_cleanup(state->registration);
755
756         if (!state->client_state) {
757                 return;
758         }
759
760         if (state->client_state->serializer && ast_sip_push_task(state->client_state->serializer, handle_client_state_destruction, state->client_state)) {
761                 ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
762                 ao2_ref(state->client_state, -1);
763         }
764 }
765
766 /*! \brief Destructor function for client registration state */
767 static void sip_outbound_registration_client_state_destroy(void *obj)
768 {
769         struct sip_outbound_registration_client_state *client_state = obj;
770
771         ast_taskprocessor_unreference(client_state->serializer);
772 }
773
774 /*! \brief Allocator function for registration state */
775 static struct sip_outbound_registration_state *sip_outbound_registration_state_alloc(struct sip_outbound_registration *registration)
776 {
777         struct sip_outbound_registration_state *state = ao2_alloc(sizeof(*state), sip_outbound_registration_state_destroy);
778
779         if (!state || !(state->client_state = ao2_alloc(sizeof(*state->client_state), sip_outbound_registration_client_state_destroy))) {
780                 ao2_cleanup(state);
781                 return NULL;
782         }
783
784         if (!(state->client_state->serializer = ast_sip_create_serializer())) {
785                 ao2_cleanup(state->client_state);
786                 ao2_cleanup(state);
787                 return NULL;
788         }
789
790         state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
791         state->client_state->timer.user_data = state->client_state;
792         state->client_state->timer.cb = sip_outbound_registration_timer_cb;
793
794         state->registration = ao2_bump(registration);
795         return state;
796 }
797
798 /*! \brief Destructor function for registration information */
799 static void sip_outbound_registration_destroy(void *obj)
800 {
801         struct sip_outbound_registration *registration = obj;
802
803         ast_sip_auth_vector_destroy(&registration->outbound_auths);
804
805         ast_string_field_free_memory(registration);
806 }
807
808 /*! \brief Allocator function for registration information */
809 static void *sip_outbound_registration_alloc(const char *name)
810 {
811         struct sip_outbound_registration *registration = ast_sorcery_generic_alloc(sizeof(*registration), sip_outbound_registration_destroy);
812         if (!registration || ast_string_field_init(registration, 256)) {
813                 ao2_cleanup(registration);
814                 return NULL;
815         }
816
817         return registration;
818 }
819
820 /*! \brief Helper function which populates a pj_str_t with a contact header */
821 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,
822         const char *line)
823 {
824         pj_str_t tmp, local_addr;
825         pjsip_uri *uri;
826         pjsip_sip_uri *sip_uri;
827         pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
828         int local_port;
829
830         pj_strdup_with_null(pool, &tmp, target);
831
832         if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
833             (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
834                 return -1;
835         }
836
837         sip_uri = pjsip_uri_get_uri(uri);
838
839         if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
840                 type = PJSIP_TRANSPORT_TLS;
841         } else if (!sip_uri->transport_param.slen) {
842                 type = PJSIP_TRANSPORT_UDP;
843         } else {
844                 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
845         }
846
847         if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
848                 return -1;
849         }
850
851         if (pj_strchr(&sip_uri->host, ':')) {
852                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
853         }
854
855         if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
856                                                               &local_addr, &local_port) != PJ_SUCCESS) {
857                 return -1;
858         }
859
860         if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
861                 type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
862         }
863
864         contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
865         contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
866                                       "<%s:%s@%s%.*s%s:%d%s%s%s%s>",
867                                       (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
868                                       user,
869                                       (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
870                                       (int)local_addr.slen,
871                                       local_addr.ptr,
872                                       (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
873                                       local_port,
874                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
875                                       (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "",
876                                       !ast_strlen_zero(line) ? ";line=" : "",
877                                       S_OR(line, ""));
878
879         return 0;
880 }
881
882 /*!
883  * \internal
884  * \brief Check if a registration can be reused
885  *
886  * This checks if the existing outbound registration's configuration differs from a newly-applied
887  * outbound registration to see if the applied one.
888  *
889  * \param existing The pre-existing outbound registration
890  * \param applied The newly-created registration
891  */
892 static int can_reuse_registration(struct sip_outbound_registration *existing,
893         struct sip_outbound_registration *applied)
894 {
895         int rc = 1;
896         struct ast_sorcery *sorcery = ast_sip_get_sorcery();
897         struct ast_variable *ve = ast_sorcery_objectset_create(sorcery, existing);
898         struct ast_variable *va = ast_sorcery_objectset_create(sorcery, applied);
899         struct ast_variable *vc = NULL;
900
901         if (ast_sorcery_changeset_create(ve, va, &vc) || vc != NULL) {
902                 rc = 0;
903                 ast_debug(4, "Registration '%s' changed.  Can't re-use.\n", ast_sorcery_object_get_id(existing));
904         } else {
905                 ast_debug(4, "Registration '%s' didn't change.  Can re-use\n", ast_sorcery_object_get_id(existing));
906         }
907
908         ast_variables_destroy(ve);
909         ast_variables_destroy(va);
910         ast_variables_destroy(vc);
911
912         return rc;
913 }
914
915 /*! \brief Helper function that allocates a pjsip registration client and configures it */
916 static int sip_outbound_registration_regc_alloc(void *data)
917 {
918         struct sip_outbound_registration_state *state = data;
919         RAII_VAR(struct sip_outbound_registration *, registration,
920                  ao2_bump(state->registration), ao2_cleanup);
921         pj_pool_t *pool;
922         pj_str_t tmp;
923         pjsip_uri *uri;
924         pj_str_t server_uri, client_uri, contact_uri;
925         pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
926
927         pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
928         if (!pool) {
929                 ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
930                         ast_sorcery_object_get_id(registration));
931                 return -1;
932         }
933
934         pj_strdup2_with_null(pool, &tmp, registration->server_uri);
935         uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
936         if (!uri) {
937                 ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
938                         registration->server_uri, ast_sorcery_object_get_id(registration));
939                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
940                 return -1;
941         }
942
943         pj_strdup2_with_null(pool, &tmp, registration->client_uri);
944         uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
945         if (!uri) {
946                 ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
947                         registration->client_uri, ast_sorcery_object_get_id(registration));
948                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
949                 return -1;
950         }
951
952         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
953
954         if (!ast_strlen_zero(registration->transport)) {
955                 RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", registration->transport), ao2_cleanup);
956
957                 if (!transport || !transport->state) {
958                         ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' "
959                                 " for outbound registration", registration->transport);
960                         return -1;
961                 }
962
963                 if (transport->state->transport) {
964                         selector.type = PJSIP_TPSELECTOR_TRANSPORT;
965                         selector.u.transport = transport->state->transport;
966                 } else if (transport->state->factory) {
967                         selector.type = PJSIP_TPSELECTOR_LISTENER;
968                         selector.u.listener = transport->state->factory;
969                 } else {
970                         return -1;
971                 }
972         }
973
974         if (!state->client_state->client &&
975                 pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state, sip_outbound_registration_response_cb,
976                 &state->client_state->client) != PJ_SUCCESS) {
977                 return -1;
978         }
979
980         pjsip_regc_set_transport(state->client_state->client, &selector);
981
982         if (!ast_strlen_zero(registration->outbound_proxy)) {
983                 pjsip_route_hdr route_set, *route;
984                 static const pj_str_t ROUTE_HNAME = { "Route", 5 };
985                 pj_str_t tmp;
986
987                 pj_list_init(&route_set);
988
989                 pj_strdup2_with_null(pjsip_regc_get_pool(state->client_state->client), &tmp, registration->outbound_proxy);
990                 if (!(route = pjsip_parse_hdr(pjsip_regc_get_pool(state->client_state->client), &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
991                         return -1;
992                 }
993                 pj_list_insert_nodes_before(&route_set, route);
994
995                 pjsip_regc_set_route_set(state->client_state->client, &route_set);
996         }
997
998         if (state->registration->line) {
999                 ast_generate_random_string(state->client_state->line, sizeof(state->client_state->line));
1000         }
1001
1002         pj_cstr(&server_uri, registration->server_uri);
1003
1004
1005         if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client), &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
1006                 state->client_state->line)) {
1007                 return -1;
1008         }
1009
1010         pj_cstr(&client_uri, registration->client_uri);
1011         if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri, &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
1012                 return -1;
1013         }
1014
1015         return 0;
1016 }
1017
1018 /*! \brief Helper function which performs a single registration */
1019 static int sip_outbound_registration_perform(void *data)
1020 {
1021         RAII_VAR(struct sip_outbound_registration_state *, state, data, ao2_cleanup);
1022         RAII_VAR(struct sip_outbound_registration *, registration, ao2_bump(state->registration), ao2_cleanup);
1023         size_t i;
1024
1025         /* Just in case the client state is being reused for this registration, free the auth information */
1026         ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
1027
1028         AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(&registration->outbound_auths));
1029         for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
1030                 const char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
1031                 AST_VECTOR_APPEND(&state->client_state->outbound_auths, name);
1032         }
1033         state->client_state->retry_interval = registration->retry_interval;
1034         state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
1035         state->client_state->max_retries = registration->max_retries;
1036         state->client_state->retries = 0;
1037         state->client_state->support_path = registration->support_path;
1038         state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
1039
1040         pjsip_regc_update_expires(state->client_state->client, registration->expiration);
1041
1042         schedule_registration(state->client_state, (ast_random() % 10) + 1);
1043
1044         return 0;
1045 }
1046
1047 /*! \brief Apply function which finds or allocates a state structure */
1048 static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
1049 {
1050         RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup);
1051         RAII_VAR(struct sip_outbound_registration_state *, state,
1052                  ao2_find(states, ast_sorcery_object_get_id(obj), OBJ_SEARCH_KEY), ao2_cleanup);
1053         RAII_VAR(struct sip_outbound_registration_state *, new_state, NULL, ao2_cleanup);
1054         struct sip_outbound_registration *applied = obj;
1055
1056         ast_debug(4, "Applying configuration to outbound registration '%s'\n", ast_sorcery_object_get_id(applied));
1057
1058         if (ast_strlen_zero(applied->server_uri)) {
1059                 ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'",
1060                         ast_sorcery_object_get_id(applied));
1061                 return -1;
1062         } else if (ast_strlen_zero(applied->client_uri)) {
1063                 ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
1064                         ast_sorcery_object_get_id(applied));
1065                 return -1;
1066         } else if (applied->line && ast_strlen_zero(applied->endpoint)) {
1067                 ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
1068                         ast_sorcery_object_get_id(applied));
1069                 return -1;
1070         } else if (!ast_strlen_zero(applied->endpoint) && !applied->line) {
1071                 ast_log(LOG_ERROR, "An endpoint has been specified on outbound registration '%s' without enabling line support\n",
1072                         ast_sorcery_object_get_id(applied));
1073                 return -1;
1074         }
1075
1076         if (state && can_reuse_registration(state->registration, applied)) {
1077                 ast_debug(4,
1078                         "No change between old configuration and new configuration on outbound registration '%s'. Using previous state\n",
1079                         ast_sorcery_object_get_id(applied));
1080                 ao2_replace(state->registration, applied);
1081                 return 0;
1082         }
1083
1084         if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
1085                 return -1;
1086         }
1087
1088         if (ast_sip_push_task_synchronous(NULL, sip_outbound_registration_regc_alloc, new_state)) {
1089                 return -1;
1090         }
1091
1092         if (ast_sip_push_task(new_state->client_state->serializer,
1093                               sip_outbound_registration_perform, ao2_bump(new_state))) {
1094                 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n",
1095                         ast_sorcery_object_get_id(new_state->registration));
1096                 ao2_ref(new_state, -1);
1097                 return -1;
1098         }
1099
1100         ao2_lock(states);
1101
1102         if (state) {
1103                 ao2_unlink(states, state);
1104         }
1105
1106         ao2_link(states, new_state);
1107         ao2_unlock(states);
1108
1109         return 0;
1110 }
1111
1112 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1113 {
1114         struct sip_outbound_registration *registration = obj;
1115
1116         return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
1117 }
1118
1119 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
1120 {
1121         const struct sip_outbound_registration *registration = obj;
1122
1123         return ast_sip_auths_to_str(&registration->outbound_auths, buf);
1124 }
1125
1126 static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
1127 {
1128         const struct sip_outbound_registration *registration = obj;
1129         int i;
1130         struct ast_variable *head = NULL;
1131
1132         for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
1133                 ast_variable_list_append(&head, ast_variable_new("outbound_auth",
1134                         AST_VECTOR_GET(&registration->outbound_auths, i), ""));
1135         }
1136
1137         if (head) {
1138                 *fields = head;
1139         }
1140
1141         return 0;
1142 }
1143
1144 static int unregister_task(void *obj)
1145 {
1146         RAII_VAR(struct sip_outbound_registration_state*, state, obj, ao2_cleanup);
1147         struct pjsip_regc *client = state->client_state->client;
1148         pjsip_tx_data *tdata;
1149
1150         cancel_registration(state->client_state);
1151
1152         if (pjsip_regc_unregister(client, &tdata) != PJ_SUCCESS) {
1153                 return 0;
1154         }
1155
1156         ao2_ref(state->client_state, +1);
1157         if (pjsip_regc_send(client, tdata) != PJ_SUCCESS) {
1158                 ao2_cleanup(state->client_state);
1159         }
1160
1161         return 0;
1162 }
1163
1164 static int queue_unregister(struct sip_outbound_registration_state *state)
1165 {
1166         ao2_ref(state, +1);
1167         if (ast_sip_push_task(state->client_state->serializer, unregister_task, state)) {
1168                 ao2_ref(state, -1);
1169                 return -1;
1170         }
1171
1172         return 0;
1173 }
1174
1175 static int queue_register(struct sip_outbound_registration_state *state)
1176 {
1177         ao2_ref(state, +1);
1178         if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) {
1179                 ao2_ref(state, -1);
1180                 return -1;
1181         }
1182
1183         return 0;
1184 }
1185
1186 static char *cli_complete_registration(const char *line, const char *word,
1187                                        int pos, int state)
1188 {
1189         char *result = NULL;
1190         int wordlen;
1191         int which = 0;
1192         struct sip_outbound_registration *registration;
1193         RAII_VAR(struct ao2_container *, registrations, NULL, ao2_cleanup);
1194         struct ao2_iterator i;
1195
1196         if (pos != 3) {
1197                 return NULL;
1198         }
1199
1200         wordlen = strlen(word);
1201         registrations = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
1202                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1203         if (!registrations) {
1204                 return NULL;
1205         }
1206
1207         i = ao2_iterator_init(registrations, 0);
1208         while ((registration = ao2_iterator_next(&i))) {
1209                 const char *name = ast_sorcery_object_get_id(registration);
1210                 if (!strncasecmp(word, name, wordlen) && ++which > state) {
1211                         result = ast_strdup(name);
1212                 }
1213
1214                 ao2_cleanup(registration);
1215                 if (result) {
1216                         break;
1217                 }
1218         }
1219         ao2_iterator_destroy(&i);
1220         return result;
1221 }
1222
1223 static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1224 {
1225         RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
1226         const char *registration_name;
1227
1228         switch (cmd) {
1229         case CLI_INIT:
1230                 e->command = "pjsip send unregister";
1231                 e->usage =
1232                         "Usage: pjsip send unregister <registration>\n"
1233                         "       Unregisters the specified outbound registration and stops future registration attempts.\n";
1234                 return NULL;
1235         case CLI_GENERATE:
1236                 return cli_complete_registration(a->line, a->word, a->pos, a->n);
1237         }
1238
1239         if (a->argc != 4) {
1240                 return CLI_SHOWUSAGE;
1241         }
1242
1243         registration_name = a->argv[3];
1244
1245         state = get_state(registration_name);
1246         if (!state) {
1247                 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
1248                 return CLI_FAILURE;
1249         }
1250
1251         if (queue_unregister(state)) {
1252                 ast_cli(a->fd, "Failed to queue unregistration");
1253                 return 0;
1254         }
1255
1256         return CLI_SUCCESS;
1257 }
1258
1259 static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1260 {
1261         RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
1262         const char *registration_name;
1263
1264         switch (cmd) {
1265         case CLI_INIT:
1266                 e->command = "pjsip send register";
1267                 e->usage =
1268                         "Usage: pjsip send register <registration>\n"
1269                         "       Unregisters the specified outbound "
1270                         "registration then re-registers and re-schedules it.\n";
1271                 return NULL;
1272         case CLI_GENERATE:
1273                 return cli_complete_registration(a->line, a->word, a->pos, a->n);
1274         }
1275
1276         if (a->argc != 4) {
1277                 return CLI_SHOWUSAGE;
1278         }
1279
1280         registration_name = a->argv[3];
1281
1282         state = get_state(registration_name);
1283         if (!state) {
1284                 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
1285                 return CLI_FAILURE;
1286         }
1287
1288         /* We need to serialize the unregister and register so they need
1289          * to be queued as separate tasks.
1290          */
1291         if (queue_unregister(state)) {
1292                 ast_cli(a->fd, "Failed to queue unregistration");
1293                 return 0;
1294         }
1295         if (queue_register(state)) {
1296                 ast_cli(a->fd, "Failed to queue registration");
1297                 return 0;
1298         }
1299
1300         return CLI_SUCCESS;
1301 }
1302
1303 static int ami_unregister(struct mansession *s, const struct message *m)
1304 {
1305         const char *registration_name = astman_get_header(m, "Registration");
1306         RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
1307
1308         if (ast_strlen_zero(registration_name)) {
1309                 astman_send_error(s, m, "Registration parameter missing.");
1310                 return 0;
1311         }
1312
1313         state = get_state(registration_name);
1314         if (!state) {
1315                 astman_send_error(s, m, "Unable to retrieve registration entry\n");
1316                 return 0;
1317         }
1318
1319         if (queue_unregister(state)) {
1320                 astman_send_ack(s, m, "Failed to queue unregistration");
1321                 return 0;
1322         }
1323
1324         astman_send_ack(s, m, "Unregistration sent");
1325         return 0;
1326 }
1327
1328 static int ami_register(struct mansession *s, const struct message *m)
1329 {
1330         const char *registration_name = astman_get_header(m, "Registration");
1331         RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
1332
1333         if (ast_strlen_zero(registration_name)) {
1334                 astman_send_error(s, m, "Registration parameter missing.");
1335                 return 0;
1336         }
1337
1338         state = get_state(registration_name);
1339         if (!state) {
1340                 astman_send_error(s, m, "Unable to retrieve registration entry\n");
1341                 return 0;
1342         }
1343
1344         /* We need to serialize the unregister and register so they need
1345          * to be queued as separate tasks.
1346          */
1347         if (queue_unregister(state)) {
1348                 astman_send_ack(s, m, "Failed to queue unregistration");
1349                 return 0;
1350         }
1351         if (queue_register(state)) {
1352                 astman_send_ack(s, m, "Failed to queue unregistration");
1353                 return 0;
1354         }
1355
1356         astman_send_ack(s, m, "Reregistration sent");
1357         return 0;
1358 }
1359
1360 struct sip_ami_outbound {
1361         struct ast_sip_ami *ami;
1362         int registered;
1363         int not_registered;
1364         struct sip_outbound_registration *registration;
1365 };
1366
1367 static int ami_outbound_registration_task(void *obj)
1368 {
1369         struct sip_ami_outbound *ami = obj;
1370         RAII_VAR(struct ast_str *, buf, NULL, ast_free);
1371         struct sip_outbound_registration_state *state;
1372
1373         buf = ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami);
1374         if (!buf) {
1375                 return -1;
1376         }
1377
1378         ast_sip_sorcery_object_to_ami(ami->registration, &buf);
1379
1380         if ((state = get_state(ast_sorcery_object_get_id(ami->registration)))) {
1381                 pjsip_regc_info info;
1382
1383                 if (state->client_state->status == SIP_REGISTRATION_REGISTERED) {
1384                         ++ami->registered;
1385                 } else {
1386                         ++ami->not_registered;
1387                 }
1388
1389                 ast_str_append(&buf, 0, "Status: %s\r\n",
1390                         sip_outbound_registration_status_str[state->client_state->status]);
1391
1392                 pjsip_regc_get_info(state->client_state->client, &info);
1393                 ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg);
1394                 ao2_ref(state, -1);
1395         }
1396
1397         astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
1398         return ast_sip_format_auths_ami(&ami->registration->outbound_auths, ami->ami);
1399 }
1400
1401 static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
1402 {
1403         struct sip_ami_outbound *ami = arg;
1404
1405         ami->registration = obj;
1406         return ast_sip_push_task_synchronous(
1407                 NULL, ami_outbound_registration_task, ami);
1408 }
1409
1410 static int ami_show_outbound_registrations(struct mansession *s,
1411                                            const struct message *m)
1412 {
1413         struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
1414         struct sip_ami_outbound ami_outbound = { .ami = &ami };
1415         RAII_VAR(struct ao2_container *, regs, get_registrations(), ao2_cleanup);
1416
1417         if (!regs) {
1418                 astman_send_error(s, m, "Unable to retreive "
1419                                   "outbound registrations\n");
1420                 return -1;
1421         }
1422
1423         astman_send_listack(s, m, "Following are Events for each Outbound registration");
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         ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s  %-16s  %-16s\n",
1506                 id,
1507                 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
1508                 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
1509                 registration->server_uri,
1510                 AST_VECTOR_SIZE(&registration->outbound_auths)
1511                         ? AST_VECTOR_GET(&registration->outbound_auths, 0)
1512                         : "n/a",
1513                 sip_outbound_registration_status_str[state->client_state->status]);
1514         ao2_ref(state, -1);
1515
1516         if (context->show_details
1517                 || (context->show_details_only_level_0 && context->indent_level == 0)) {
1518                 ast_str_append(&context->output_buffer, 0, "\n");
1519                 ast_sip_cli_print_sorcery_objectset(registration, context, 0);
1520         }
1521
1522         return 0;
1523 }
1524
1525 /*
1526  * A function pointer to callback needs to be within the
1527  * module in order to avoid problems with an undefined
1528  * symbol when the module is loaded.
1529  */
1530 static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1531 {
1532         return ast_sip_cli_traverse_objects(e, cmd, a);
1533 }
1534
1535 static struct ast_cli_entry cli_outbound_registration[] = {
1536         AST_CLI_DEFINE(cli_unregister, "Unregisters outbound registration target"),
1537         AST_CLI_DEFINE(cli_register, "Registers an outbound registration target"),
1538         AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
1539                 .command = "pjsip list registrations",
1540                 .usage = "Usage: pjsip list registrations\n"
1541                                  "       List the configured PJSIP Registrations\n"),
1542         AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
1543                 .command = "pjsip show registrations",
1544                 .usage = "Usage: pjsip show registrations\n"
1545                                  "       Show the configured PJSIP Registrations\n"),
1546         AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
1547                 .command = "pjsip show registration",
1548                 .usage = "Usage: pjsip show registration <id>\n"
1549                                  "       Show the configured PJSIP Registration\n"),
1550 };
1551
1552 static struct ast_sip_cli_formatter_entry *cli_formatter;
1553
1554 static void auth_observer(const char *type)
1555 {
1556         struct sip_outbound_registration *registration;
1557         struct sip_outbound_registration_state *state;
1558         struct ao2_container *regs;
1559         const char *registration_id;
1560         struct ao2_iterator i;
1561
1562         ast_debug(4, "Auths updated. Checking for any outbound registrations that are in permanent rejected state so they can be retried\n");
1563
1564         regs = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
1565                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1566         if (!regs || ao2_container_count(regs) == 0) {
1567                 ao2_cleanup(regs);
1568                 return;
1569         }
1570
1571         i = ao2_iterator_init(regs, 0);
1572         for (; (registration = ao2_iterator_next(&i)); ao2_ref(registration, -1)) {
1573                 registration_id = ast_sorcery_object_get_id(registration);
1574                 state = get_state(registration_id);
1575                 if (state && state->client_state->status == SIP_REGISTRATION_REJECTED_PERMANENT) {
1576                         ast_debug(4, "Trying outbound registration '%s' again\n", registration_id);
1577
1578                         if (ast_sip_push_task(state->client_state->serializer,
1579                                               sip_outbound_registration_perform, ao2_bump(state))) {
1580                                 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", registration_id);
1581                                 ao2_ref(state, -1);
1582                         }
1583                 }
1584                 ao2_cleanup(state);
1585         }
1586         ao2_iterator_destroy(&i);
1587         ao2_cleanup(regs);
1588 }
1589
1590 const struct ast_sorcery_observer observer_callbacks = {
1591         .loaded = auth_observer,
1592 };
1593
1594 static int unload_module(void)
1595 {
1596         ast_sip_unregister_endpoint_identifier(&line_identifier);
1597         ast_sorcery_observer_remove(ast_sip_get_sorcery(), "auth", &observer_callbacks);
1598         ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1599         ast_sip_unregister_cli_formatter(cli_formatter);
1600         ast_manager_unregister("PJSIPShowRegistrationsOutbound");
1601         ast_manager_unregister("PJSIPUnregister");
1602         ast_manager_unregister("PJSIPRegister");
1603
1604         ao2_global_obj_release(current_states);
1605
1606         return 0;
1607 }
1608
1609 static int load_module(void)
1610 {
1611         struct ao2_container *registrations, *new_states;
1612         CHECK_PJSIP_MODULE_LOADED();
1613
1614         ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_registration");
1615         ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
1616
1617         if (ast_sorcery_object_register(ast_sip_get_sorcery(), "registration", sip_outbound_registration_alloc, NULL, sip_outbound_registration_apply)) {
1618                 return AST_MODULE_LOAD_DECLINE;
1619         }
1620
1621         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
1622         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, server_uri));
1623         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
1624         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
1625         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
1626         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
1627         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
1628         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
1629         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));
1630         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
1631         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));
1632         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);
1633         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
1634         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));
1635         ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));
1636         ast_sip_register_endpoint_identifier(&line_identifier);
1637
1638         ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
1639         ast_manager_register_xml("PJSIPRegister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_register);
1640         ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations);
1641
1642         cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1643         if (!cli_formatter) {
1644                 ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
1645                 unload_module();
1646                 return -1;
1647         }
1648         cli_formatter->name = "registration";
1649         cli_formatter->print_header = cli_print_header;
1650         cli_formatter->print_body = cli_print_body;
1651         cli_formatter->get_container = cli_get_container;
1652         cli_formatter->iterate = cli_iterator;
1653         cli_formatter->get_id = ast_sorcery_object_get_id;
1654         cli_formatter->retrieve_by_id = cli_retrieve_by_id;
1655
1656         ast_sip_register_cli_formatter(cli_formatter);
1657         ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
1658
1659         if (!(new_states = ao2_container_alloc(
1660                       DEFAULT_STATE_BUCKETS, registration_state_hash, registration_state_cmp))) {
1661                 ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
1662                 unload_module();
1663                 return AST_MODULE_LOAD_FAILURE;
1664         }
1665         ao2_global_obj_replace_unref(current_states, new_states);
1666         ao2_ref(new_states, -1);
1667
1668         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
1669         if (!(registrations = get_registrations())) {
1670                 unload_module();
1671                 return AST_MODULE_LOAD_FAILURE;
1672         }
1673         ao2_ref(registrations, -1);
1674
1675         ast_sorcery_observer_add(ast_sip_get_sorcery(), "auth", &observer_callbacks);
1676
1677         return AST_MODULE_LOAD_SUCCESS;
1678 }
1679
1680 static int reload_module(void)
1681 {
1682         ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
1683         ao2_cleanup(get_registrations());
1684         return 0;
1685 }
1686
1687 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
1688                 .support_level = AST_MODULE_SUPPORT_CORE,
1689                 .load = load_module,
1690                 .reload = reload_module,
1691                 .unload = unload_module,
1692                 .load_pri = AST_MODPRI_APP_DEPEND,
1693                );