Asterisk - The Open Source Telephony Project GIT-master-f36a736
res_pjsip_outbound_registration.c
Go to the documentation of this file.
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 <use type="module">res_statsd</use>
23 <support_level>core</support_level>
24 ***/
25
26#include "asterisk.h"
27
28#include <pjsip.h>
29#include <pjsip_ua.h>
30
31#include "asterisk/res_pjsip.h"
33#include "asterisk/module.h"
35#include "asterisk/cli.h"
38#include "asterisk/threadpool.h"
39#include "asterisk/statsd.h"
41#include "asterisk/vector.h"
42#include "asterisk/pbx.h"
43
44/*** DOCUMENTATION
45 <configInfo name="res_pjsip_outbound_registration" language="en_US">
46 <synopsis>SIP resource for outbound registrations</synopsis>
47 <description><para>
48 <emphasis>Outbound Registration</emphasis>
49 </para>
50 <para>This module allows <literal>res_pjsip</literal> to register to other SIP servers.</para>
51 </description>
52 <configFile name="pjsip.conf">
53 <configObject name="registration">
54 <synopsis>The configuration for outbound registration</synopsis>
55 <description><para>
56 Registration is <emphasis>COMPLETELY</emphasis> separate from the rest of
57 <literal>pjsip.conf</literal>. A minimal configuration consists of
58 setting a <literal>server_uri</literal> and a <literal>client_uri</literal>.
59 </para></description>
60 <configOption name="auth_rejection_permanent" default="yes">
61 <synopsis>Determines whether failed authentication challenges are treated
62 as permanent failures.</synopsis>
63 <description><para>If this option is enabled and an authentication challenge fails,
64 registration will not be attempted again until the configuration is reloaded.</para></description>
65 </configOption>
66 <configOption name="client_uri">
67 <synopsis>Client SIP URI used when attemping outbound registration</synopsis>
68 <description><para>
69 This is the address-of-record for the outbound registration (i.e. the URI in
70 the To header of the REGISTER).</para>
71 <para>For registration with an ITSP, the client SIP URI may need to consist of
72 an account name or number and the provider's hostname for their registrar, e.g.
73 client_uri=1234567890@example.com. This may differ between providers.</para>
74 <para>For registration to generic registrars, the client SIP URI will depend
75 on networking specifics and configuration of the registrar.
76 </para></description>
77 </configOption>
78 <configOption name="contact_user" default="s">
79 <synopsis>Contact User to use in request. If this value is not set, this defaults to 's'</synopsis>
80 </configOption>
81 <configOption name="contact_header_params">
82 <synopsis>Header parameters to place in the Contact header</synopsis>
83 </configOption>
84 <configOption name="expiration" default="3600">
85 <synopsis>Expiration time for registrations in seconds</synopsis>
86 </configOption>
87 <configOption name="max_retries" default="10">
88 <synopsis>Maximum number of registration attempts.</synopsis>
89 <description><para>
90 This sets the maximum number of registration attempts that are made before
91 stopping any further attempts. If set to 0 then upon failure no further attempts
92 are made.
93 </para></description>
94 </configOption>
95 <configOption name="security_negotiation" default="no">
96 <synopsis>The kind of security agreement negotiation to use. Currently, only mediasec is supported.</synopsis>
97 <description>
98 <enumlist>
99 <enum name="no" />
100 <enum name="mediasec" />
101 </enumlist>
102 </description>
103 </configOption>
104 <configOption name="security_mechanisms">
105 <synopsis>List of security mechanisms supported.</synopsis>
106 <description><para>
107 This is a comma-delimited list of security mechanisms to use. Each security mechanism
108 must be in the form defined by RFC 3329 section 2.2.
109 </para></description>
110 </configOption>
111 <configOption name="outbound_auth" default="">
112 <synopsis>Authentication object(s) to be used for outbound registrations.</synopsis>
113 <description><para>
114 This is a comma-delimited list of <replaceable>auth</replaceable>
115 sections defined in <filename>pjsip.conf</filename> used to respond
116 to outbound authentication challenges.</para>
117 <note><para>
118 Using the same auth section for inbound and outbound
119 authentication is not recommended. There is a difference in
120 meaning for an empty realm setting between inbound and outbound
121 authentication uses. See the auth realm description for details.
122 </para></note>
123 </description>
124 </configOption>
125 <configOption name="outbound_proxy" default="">
126 <synopsis>Full SIP URI of the outbound proxy used to send registrations</synopsis>
127 </configOption>
128 <configOption name="max_random_initial_delay" default="10">
129 <synopsis>Maximum interval in seconds for which an initial registration may be randomly delayed</synopsis>
130 <description>
131 <para>By default, registrations are randomly delayed by a small amount to prevent
132 too many registrations from being made simultaneously.</para>
133 <para>Depending on your system usage, it may be desirable to set this to a smaller
134 or larger value to have fine grained control over the size of this random delay.</para>
135 </description>
136 </configOption>
137 <configOption name="retry_interval" default="60">
138 <synopsis>Interval in seconds between retries if outbound registration is unsuccessful</synopsis>
139 </configOption>
140 <configOption name="forbidden_retry_interval" default="0">
141 <synopsis>Interval used when receiving a 403 Forbidden response.</synopsis>
142 <description><para>
143 If a 403 Forbidden is received, chan_pjsip will wait
144 <replaceable>forbidden_retry_interval</replaceable> seconds before
145 attempting registration again. If 0 is specified, chan_pjsip will not
146 retry after receiving a 403 Forbidden response. Setting this to a non-zero
147 value goes against a "SHOULD NOT" in RFC3261, but can be used to work around
148 buggy registrars.
149 </para></description>
150 </configOption>
151 <configOption name="fatal_retry_interval" default="0">
152 <synopsis>Interval used when receiving a Fatal response.</synopsis>
153 <description><para>
154 If a fatal response is received, chan_pjsip will wait
155 <replaceable>fatal_retry_interval</replaceable> seconds before
156 attempting registration again. If 0 is specified, chan_pjsip will not
157 retry after receiving a fatal (non-temporary 4xx, 5xx, 6xx) response.
158 Setting this to a non-zero value may go against a "SHOULD NOT" in RFC3261,
159 but can be used to work around buggy registrars.</para>
160 <note><para>if also set the <replaceable>forbidden_retry_interval</replaceable>
161 takes precedence over this one when a 403 is received.
162 Also, if <replaceable>auth_rejection_permanent</replaceable> equals 'yes' then
163 a 401 and 407 become subject to this retry interval.</para></note>
164 </description>
165 </configOption>
166 <configOption name="server_uri">
167 <synopsis>SIP URI of the server to register against</synopsis>
168 <description><para>
169 This is the URI at which to find the registrar to send the outbound REGISTER. This URI
170 is used as the request URI of the outbound REGISTER request from Asterisk.</para>
171 <para>For registration with an ITSP, the setting may often be just the domain of
172 the registrar, e.g. sip:sip.example.com.
173 </para></description>
174 </configOption>
175 <configOption name="transport">
176 <synopsis>Transport used for outbound authentication</synopsis>
177 <description>
178 <note><para>A <replaceable>transport</replaceable> configured in
179 <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>
180 </description>
181 </configOption>
182 <configOption name="line">
183 <synopsis>Whether to add a 'line' parameter to the Contact for inbound call matching</synopsis>
184 <description><para>
185 When enabled this option will cause a 'line' parameter to be added to the Contact
186 header placed into the outgoing registration request. If the remote server sends a call
187 this line parameter will be used to establish a relationship to the outbound registration,
188 ultimately causing the configured endpoint to be used.
189 </para></description>
190 </configOption>
191 <configOption name="endpoint">
192 <synopsis>Endpoint to use for incoming related calls</synopsis>
193 <description><para>
194 When line support is enabled this configured endpoint name is used for incoming calls
195 that are related to the outbound registration.
196 </para></description>
197 </configOption>
198 <configOption name="type">
199 <synopsis>Must be of type 'registration'.</synopsis>
200 </configOption>
201 <configOption name="support_path">
202 <synopsis>Enables advertising SIP Path support for outbound REGISTER requests.</synopsis>
203 <description><para>
204 When this option is enabled, outbound REGISTER requests will advertise
205 support for Path headers so that intervening proxies can add to the Path
206 header as necessary.
207 </para></description>
208 </configOption>
209 <configOption name="support_outbound">
210 <synopsis>Enables advertising SIP Outbound support (RFC5626) for outbound REGISTER requests.</synopsis>
211 </configOption>
212 <configOption name="user_agent">
213 <synopsis>Overrides the User-Agent header that should be used for outbound REGISTER requests.</synopsis>
214 </configOption>
215 </configObject>
216 </configFile>
217 </configInfo>
218 <manager name="PJSIPUnregister" language="en_US">
219 <synopsis>
220 Unregister an outbound registration.
221 </synopsis>
222 <syntax>
223 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
224 <parameter name="Registration" required="true">
225 <para>The outbound registration to unregister or '*all' to unregister them all.</para>
226 </parameter>
227 </syntax>
228 <description>
229 <para>
230 Unregisters the specified (or all) outbound registration(s) and stops future registration attempts.
231 Call PJSIPRegister to start registration and schedule re-registrations according to configuration.
232 </para>
233 </description>
234 </manager>
235 <manager name="PJSIPRegister" language="en_US">
236 <synopsis>
237 Register an outbound registration.
238 </synopsis>
239 <syntax>
240 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
241 <parameter name="Registration" required="true">
242 <para>The outbound registration to register or '*all' to register them all.</para>
243 </parameter>
244 </syntax>
245 <description>
246 <para>
247 Unregisters the specified (or all) outbound registration(s) then starts registration and schedules re-registrations
248 according to configuration.
249 </para>
250 </description>
251 </manager>
252 <manager name="PJSIPShowRegistrationsOutbound" language="en_US">
253 <synopsis>
254 Lists PJSIP outbound registrations.
255 </synopsis>
256 <syntax />
257 <description>
258 <para>
259 In response <literal>OutboundRegistrationDetail</literal> events showing configuration and status
260 information are raised for each outbound registration object. <literal>AuthDetail</literal>
261 events are raised for each associated auth object as well. Once all events are completed an
262 <literal>OutboundRegistrationDetailComplete</literal> is issued.
263 </para>
264 </description>
265 </manager>
266 ***/
267
268/* forward declarations */
269static int set_outbound_initial_authentication_credentials(pjsip_regc *regc,
270 const struct ast_sip_auth_vector *auth_vector);
271
272/*! \brief Some thread local storage used to determine if the running thread invoked the callback */
274
275/*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
276#define REREGISTER_BUFFER_TIME 10
277
278/*! \brief Size of the buffer for creating a unique string for the line */
279#define LINE_PARAMETER_SIZE 8
280
281/*! \brief Various states that an outbound registration may be in */
283 /*! \brief Currently unregistered */
285 /*! \brief Registered, yay! */
287 /*! \brief Registration was rejected, but response was temporal */
289 /*! \brief Registration was rejected, permanently */
291 /*! \brief Registration is stopping. */
293 /*! \brief Registration has been stopped */
295};
296
297/*!
298 * \internal
299 * \brief Convert the internal registration state to an external status string.
300 * \since 13.5.0
301 *
302 * \param state Current outbound registration state.
303 *
304 * \return External registration status string.
305 */
307{
308 const char *str;
309
310 str = "Unregistered";
311 switch (state) {
315 break;
317 str = "Registered";
318 break;
321 str = "Rejected";
322 break;
323 }
324 return str;
325}
326
327/*! \brief Outbound registration information */
329 /*! \brief Sorcery object details */
331 /*! \brief Stringfields */
333 /*! \brief URI for the registrar */
335 /*! \brief URI for the AOR */
337 /*! \brief Optional user for contact header */
339 /*! \brief Optional header parameters for contact */
341 /*! \brief Explicit transport to use for registration */
343 /*! \brief Outbound proxy to use */
345 /*! \brief Endpoint to use for related incoming calls */
347 /*! \brief User-Agent to use when sending the REGISTER */
349 );
350 /*! \brief Requested expiration time */
351 unsigned int expiration;
352 /*! \brief Maximum random initial delay interval for initial registrations */
354 /*! \brief Interval at which retries should occur for temporal responses */
355 unsigned int retry_interval;
356 /*! \brief Interval at which retries should occur for permanent responses */
358 /*! \brief Interval at which retries should occur for all permanent responses */
360 /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
362 /*! \brief Maximum number of retries permitted */
363 unsigned int max_retries;
364 /*! \brief Whether to add a line parameter to the outbound Contact or not */
365 unsigned int line;
366 /*! \brief Type of security negotiation to use (RFC 3329). */
368 /*! \brief Client security mechanisms (RFC 3329). */
370 /*! \brief Configured authentication credentials */
372 /*! \brief Whether Path support is enabled */
373 unsigned int support_path;
374 /*! \brief Whether Outbound support is enabled */
375 unsigned int support_outbound;
376};
377
378/*! \brief Outbound registration client state information (persists for lifetime of regc) */
380 /*! \brief Current state of this registration */
382 /*!
383 * \brief Outbound registration client
384 * \note May only be accessed within the serializer thread
385 * because it might get destroyed and set to NULL for
386 * module unload.
387 */
388 pjsip_regc *client;
389 /*!
390 * \brief Last tdata sent
391 * We need the original tdata to resend a request on auth failure
392 * or timeout. On an auth failure, we use the original tdata
393 * to initialize the new tdata for the authorized response. On a timeout
394 * we need it to skip failed SRV entries if any.
395 */
396 pjsip_tx_data *last_tdata;
397 /*! \brief Timer entry for retrying on temporal responses */
398 pj_timer_entry timer;
399 /*! \brief Optional line parameter placed into Contact */
401 /*! \brief Current number of retries */
402 unsigned int retries;
403 /*! \brief Maximum number of retries permitted */
404 unsigned int max_retries;
405 /*! \brief Interval at which retries should occur for temporal responses */
406 unsigned int retry_interval;
407 /*! \brief Interval at which retries should occur for permanent responses */
409 /*! \brief Interval at which retries should occur for all permanent responses */
411 /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
413 /*! \brief Determines whether SIP Path support should be advertised */
414 unsigned int support_path;
415 /*! \brief Determines whether SIP Outbound support should be advertised */
416 unsigned int support_outbound;
417 /*! \brief Type of security negotiation to use (RFC 3329). */
419 /*! \brief Client security mechanisms (RFC 3329). */
421 /*! \brief Security mechanisms of the peer (RFC 3329). */
423 /*! CSeq number of last sent auth request. */
424 unsigned int auth_cseq;
425 /*! \brief Serializer for stuff and things */
427 /*! \brief Configured authentication credentials */
429 /*! \brief Registration should be destroyed after completion of transaction */
430 unsigned int destroy:1;
431 /*! \brief Non-zero if we have attempted sending a REGISTER with authentication */
432 unsigned int auth_attempted:1;
433 /*! \brief Status code of last response if we have tried to register before */
435 /*! \brief The name of the transport to be used for the registration */
437 /*! \brief The name of the registration sorcery object */
439 /*! \brief Expected time of registration lapse/expiration */
441 /*! \brief The value for the User-Agent header sent in requests */
443};
444
445/*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
447 /*! \brief Outbound registration configuration object */
449 /*! \brief Client state information */
451};
452
453/*! Time needs to be long enough for a transaction to timeout if nothing replies. */
454#define MAX_UNLOAD_TIMEOUT_TIME 35 /* Seconds */
455
456/*! Shutdown group to monitor sip_outbound_registration_client_state serializers. */
458
459/*! \brief Default number of state container buckets */
460#define DEFAULT_STATE_BUCKETS 53
461static AO2_GLOBAL_OBJ_STATIC(current_states);
462
463/*! subscription id for network change events */
465
466/*! \brief hashing function for state objects */
467static int registration_state_hash(const void *obj, const int flags)
468{
469 const struct sip_outbound_registration_state *object;
470 const char *key;
471
472 switch (flags & OBJ_SEARCH_MASK) {
473 case OBJ_SEARCH_KEY:
474 key = obj;
475 break;
477 object = obj;
479 break;
480 default:
481 ast_assert(0);
482 return 0;
483 }
484 return ast_str_hash(key);
485}
486
487/*! \brief comparator function for state objects */
488static int registration_state_cmp(void *obj, void *arg, int flags)
489{
490 const struct sip_outbound_registration_state *object_left = obj;
491 const struct sip_outbound_registration_state *object_right = arg;
492 const char *right_key = arg;
493 int cmp;
494
495 switch (flags & OBJ_SEARCH_MASK) {
497 right_key = ast_sorcery_object_get_id(object_right->registration);
498 /* Fall through */
499 case OBJ_SEARCH_KEY:
500 cmp = strcmp(ast_sorcery_object_get_id(object_left->registration), right_key);
501 break;
503 /* Not supported by container. */
504 ast_assert(0);
505 return 0;
506 default:
507 cmp = 0;
508 break;
509 }
510 if (cmp) {
511 return 0;
512 }
513 return CMP_MATCH;
514}
515
516static struct sip_outbound_registration_state *get_state(const char *id)
517{
519 struct ao2_container *states;
520
521 states = ao2_global_obj_ref(current_states);
522 if (states) {
523 state = ao2_find(states, id, OBJ_SEARCH_KEY);
524 ao2_ref(states, -1);
525 }
526 return state;
527}
528
530{
532 ast_sip_get_sorcery(), "registration",
534
535 return registrations;
536}
537
538/*! \brief Callback function for matching an outbound registration based on line */
539static int line_identify_relationship(void *obj, void *arg, int flags)
540{
542 pjsip_param *line = arg;
543
544 return !pj_strcmp2(&line->value, state->client_state->line) ? CMP_MATCH : 0;
545}
546
547static struct pjsip_param *get_uri_option_line(const void *uri)
548{
549 static const pj_str_t LINE_STR = { "line", 4 };
550
551 return ast_sip_pjsip_uri_get_other_param((pjsip_uri *)uri, &LINE_STR);
552}
553
554/*! \brief Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing registration */
555static struct ast_sip_endpoint *line_identify(pjsip_rx_data *rdata)
556{
557 pjsip_param *line;
558 RAII_VAR(struct ao2_container *, states, NULL, ao2_cleanup);
560
561 if (!(line = get_uri_option_line(rdata->msg_info.to->uri))
562 && !(line = get_uri_option_line(rdata->msg_info.msg->line.req.uri))) {
563 return NULL;
564 }
565
566 states = ao2_global_obj_ref(current_states);
567 if (!states) {
568 return NULL;
569 }
570
572 if (!state || ast_strlen_zero(state->registration->endpoint)) {
573 return NULL;
574 }
575
576 ast_debug(3, "Determined relationship to outbound registration '%s' based on line '%s', using configured endpoint '%s'\n",
577 ast_sorcery_object_get_id(state->registration), state->client_state->line, state->registration->endpoint);
578
579 return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", state->registration->endpoint);
580}
581
584};
585
586/*! \brief Helper function which cancels the timer on a client */
588{
589 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
590 &client_state->timer, client_state->timer.id)) {
591 /* The timer was successfully cancelled, drop the refcount of client_state */
592 ao2_ref(client_state, -1);
593 }
594}
595
596static pj_str_t PATH_NAME = { "path", 4 };
597static pj_str_t OUTBOUND_NAME = { "outbound", 8 };
598
599AST_VECTOR(pjsip_generic_string_hdr_vector, pjsip_generic_string_hdr *);
600
601/*!
602 * \internal
603 * \brief Callback function which finds a contact whose contact_status has security mechanisms.
604 *
605 * \param obj Pointer to the ast_sip_contact.
606 * \param arg Pointer-pointer to a contact_status that will be set to the contact_status found by this function.
607 * \param flags Flags used by the ao2_callback function.
608 *
609 * \note The refcount of the found contact_status must be decremented by the caller.
610 */
611static int contact_has_security_mechanisms(void *obj, void *arg, int flags)
612{
613 struct ast_sip_contact *contact = obj;
614 struct ast_sip_contact_status **ret = arg;
615 struct ast_sip_contact_status *contact_status = ast_sip_get_contact_status(contact);
616
617 if (!contact_status) {
618 return 0;
619 }
620 if (!AST_VECTOR_SIZE(&contact_status->security_mechanisms)) {
621 ao2_cleanup(contact_status);
622 return 0;
623 }
624 *ret = contact_status;
625 return CMP_MATCH | CMP_STOP;
626}
627
628static int contact_add_security_headers_to_status(void *obj, void *arg, int flags)
629{
630 struct ast_sip_contact *contact = obj;
631 struct pjsip_generic_string_hdr_vector *header_vector = arg;
632 struct ast_sip_contact_status *contact_status = ast_sip_get_contact_status(contact);
633
634 if (!contact_status) {
635 return 0;
636 }
637 if (AST_VECTOR_SIZE(&contact_status->security_mechanisms)) {
638 goto out;
639 }
640
641 ao2_lock(contact_status);
643 ao2_unlock(contact_status);
644
645out:
646 ao2_cleanup(contact_status);
647 return 0;
648}
649
650/*! \brief Adds security negotiation mechanisms of outbound registration client state as Security headers to tdata. */
652 pjsip_tx_data *tdata)
653{
654 int add_sec_client_header = 0;
655 struct sip_outbound_registration *reg = NULL;
656 struct ast_sip_endpoint *endpt = NULL;
657 struct ao2_container *contact_container;
658 struct ast_sip_contact_status *contact_status = NULL;
659 struct ast_sip_security_mechanism_vector *sec_mechs = NULL;
660 static const pj_str_t security_verify = { "Security-Verify", 15 };
661 static const pj_str_t security_client = { "Security-Client", 15 };
662
664 return;
665 }
666
667 /* Get contact status through registration -> endpoint name -> aor -> contact (if set) */
668 if ((reg = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", client_state->registration_name))
669 && !ast_strlen_zero(reg->endpoint) && (endpt = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", reg->endpoint))
670 && (contact_container = ast_sip_location_retrieve_contacts_from_aor_list(endpt->aors))) {
671 /* Retrieve all contacts associated with aors from this endpoint
672 * and find the first one that has security mechanisms.
673 */
674 ao2_callback(contact_container, OBJ_NODATA, contact_has_security_mechanisms, &contact_status);
675 if (contact_status) {
676 ao2_lock(contact_status);
677 sec_mechs = &contact_status->security_mechanisms;
678 }
679 ao2_cleanup(contact_container);
680 }
681 /* Use client_state->server_security_mechanisms if contact_status does not exist. */
682 if (!contact_status && AST_VECTOR_SIZE(&client_state->server_security_mechanisms)) {
683 sec_mechs = &client_state->server_security_mechanisms;
684 }
685 if (client_state->status == SIP_REGISTRATION_REJECTED_TEMPORARY || client_state->auth_attempted) {
686 if (sec_mechs != NULL && pjsip_msg_find_hdr_by_name(tdata->msg, &security_verify, NULL) == NULL) {
687 ast_sip_add_security_headers(sec_mechs, "Security-Verify", 0, tdata);
688 }
689 if (client_state->last_status_code == 494) {
690 ast_sip_remove_headers_by_name_and_value(tdata->msg, &security_client, NULL);
691 } else {
692 /* necessary if a retry occures */
693 add_sec_client_header = (pjsip_msg_find_hdr_by_name(tdata->msg, &security_client, NULL) == NULL) ? 1 : 0;
694 }
695 } else {
696 ast_sip_add_security_headers(&client_state->security_mechanisms, "Security-Client", 0, tdata);
697 }
698
699 if (add_sec_client_header) {
700 ast_sip_add_security_headers(&client_state->security_mechanisms, "Security-Client", 0, tdata);
701 }
702
703 /* Cleanup */
704 if (contact_status) {
705 ao2_unlock(contact_status);
706 ao2_cleanup(contact_status);
707 }
708 ao2_cleanup(endpt);
709 ao2_cleanup(reg);
710}
711
712/*! \brief Helper function which sends a message and cleans up, if needed, on failure */
714 pjsip_tx_data *tdata)
715{
716 pj_status_t status;
717 int *callback_invoked;
718 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
719
720 callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
721 if (!callback_invoked) {
722 pjsip_tx_data_dec_ref(tdata);
723 return PJ_ENOMEM;
724 }
725 *callback_invoked = 0;
726
727 /* Due to the message going out the callback may now be invoked, so bump the count */
728 ao2_ref(client_state, +1);
729 /*
730 * We also bump tdata in expectation of saving it to client_state->last_tdata.
731 * We have to do it BEFORE pjsip_regc_send because if it succeeds, it decrements
732 * the ref count on its own.
733 */
734 pjsip_tx_data_add_ref(tdata);
735
736 /* Add Security-Verify or Security-Client headers */
737 add_security_headers(client_state, tdata);
738
739 /*
740 * Replace the User-Agent header if a different one should be used
741 */
742 if (!ast_strlen_zero(client_state->user_agent)) {
743 static const pj_str_t user_agent_str = { "User-Agent", 10 };
744 pjsip_generic_string_hdr *default_user_agent_hdr;
745 pjsip_generic_string_hdr *user_agent_hdr;
746 pj_str_t user_agent_val;
747 default_user_agent_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &user_agent_str, NULL);
748 user_agent_val = pj_str(client_state->user_agent);
749 user_agent_hdr = pjsip_generic_string_hdr_create(tdata->pool, &user_agent_str, &user_agent_val);
750 if (!user_agent_hdr) {
751 ast_log(LOG_ERROR, "Could not add custom User-Agent to outbound registration %s, sending REGISTER request with non-custom header\n", client_state->registration_name);
752 } else {
753 if (default_user_agent_hdr) {
754 pj_list_erase(default_user_agent_hdr);
755 }
756 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)user_agent_hdr);
757 }
758 }
759
760 /*
761 * Set the transport in case transports were reloaded.
762 * When pjproject removes the extraneous error messages produced,
763 * we can check status and only set the transport and resend if there was an error
764 */
766 pjsip_regc_set_transport(client_state->client, &selector);
767 ast_sip_tpselector_unref(&selector);
768
769 status = pjsip_regc_send(client_state->client, tdata);
770
771 /*
772 * If the attempt to send the message failed and the callback was not invoked we need to
773 * drop the references we just added
774 */
775 if ((status != PJ_SUCCESS) && !(*callback_invoked)) {
776 pjsip_tx_data_dec_ref(tdata);
777 ao2_ref(client_state, -1);
778 return status;
779 }
780
781 /*
782 * Decref the old last_data before replacing it.
783 * BTW, it's quite possible that last_data == tdata
784 * if we're trying successive servers in an SRV set.
785 */
786 if (client_state->last_tdata) {
787 pjsip_tx_data_dec_ref(client_state->last_tdata);
788 }
789 client_state->last_tdata = tdata;
790
791 return status;
792}
793
794/*! \brief Helper function to add string to Supported header */
795static int add_to_supported_header(pjsip_tx_data *tdata, pj_str_t *name)
796{
797 pjsip_supported_hdr *hdr;
798 int i;
799
800 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
801 if (!hdr) {
802 /* insert a new Supported header */
803 hdr = pjsip_supported_hdr_create(tdata->pool);
804 if (!hdr) {
805 pjsip_tx_data_dec_ref(tdata);
806 return 0;
807 }
808
809 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
810 }
811
812 /* Don't add the value if it's already there */
813 for (i = 0; i < hdr->count; ++i) {
814 if (pj_stricmp(&hdr->values[i], name) == 0) {
815 return 1;
816 }
817 }
818
819 if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
820 return 0;
821 }
822
823 /* add on to the existing Supported header */
824 pj_strassign(&hdr->values[hdr->count++], name);
825
826 return 1;
827}
828
829/*! \brief Helper function to add configured supported headers */
830static int add_configured_supported_headers(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
831{
832 if (client_state->support_path) {
833 if (!add_to_supported_header(tdata, &PATH_NAME)) {
834 return 0;
835 }
836 }
837
838 if (client_state->support_outbound) {
840 return 0;
841 }
842 }
843
844 return 1;
845}
846
847/*! \brief Callback function for registering */
848static int handle_client_registration(void *data)
849{
850 RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
851 pjsip_tx_data *tdata;
852
853 if (set_outbound_initial_authentication_credentials(client_state->client, &client_state->outbound_auths)) {
854 ast_log(LOG_WARNING, "Failed to set initial authentication credentials\n");
855 }
856
857 if (client_state->status == SIP_REGISTRATION_STOPPED
858 || pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
859 return 0;
860 }
861
862 if (DEBUG_ATLEAST(1)) {
863 pjsip_regc_info info;
864
865 pjsip_regc_get_info(client_state->client, &info);
866 ast_log(LOG_DEBUG, "Outbound REGISTER attempt %u to '%.*s' with client '%.*s'\n",
867 client_state->retries + 1,
868 (int) info.server_uri.slen, info.server_uri.ptr,
869 (int) info.client_uri.slen, info.client_uri.ptr);
870 }
871
872 if (!add_configured_supported_headers(client_state, tdata)) {
873 ast_log(LOG_WARNING, "Failed to set supported headers\n");
874 return -1;
875 }
876
877 registration_client_send(client_state, tdata);
878
879 return 0;
880}
881
882/*! \brief Timer callback function, used just for registrations */
883static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
884{
885 struct sip_outbound_registration_client_state *client_state = entry->user_data;
886
887 entry->id = 0;
888
889 /*
890 * Transfer client_state reference to serializer task so the
891 * nominal path will not dec the client_state ref in this
892 * pjproject callback thread.
893 */
894 if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
895 ast_log(LOG_WARNING, "Scheduled outbound registration could not be executed.\n");
896 ao2_ref(client_state, -1);
897 }
898}
899
900/*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
901static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
902{
903 pj_time_val delay = { .sec = seconds, };
904 pjsip_regc_info info;
905
906 cancel_registration(client_state);
907
908 pjsip_regc_get_info(client_state->client, &info);
909 ast_debug(1, "Scheduling outbound registration to server '%.*s' from client '%.*s' in %d seconds\n",
910 (int) info.server_uri.slen, info.server_uri.ptr,
911 (int) info.client_uri.slen, info.client_uri.ptr,
912 seconds);
913
914 ao2_ref(client_state, +1);
915 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
916 ast_log(LOG_WARNING, "Failed to schedule registration to server '%.*s' from client '%.*s'\n",
917 (int) info.server_uri.slen, info.server_uri.ptr,
918 (int) info.client_uri.slen, info.client_uri.ptr);
919 ao2_ref(client_state, -1);
920 }
921 client_state->registration_expires = ((int) time(NULL)) + seconds;
922}
923
925{
926 const char *status_old;
927 const char *status_new;
928
929 if (client_state->status == status) {
930 /* Status state did not change at all. */
931 return;
932 }
933
934 status_old = sip_outbound_registration_status_str(client_state->status);
936 client_state->status = status;
937
938 if (!strcmp(status_old, status_new)) {
939 /*
940 * The internal status state may have changed but the status
941 * state we tell the world did not change at all.
942 */
943 return;
944 }
945
946 ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
947 status_old);
948 ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
949 status_new);
950}
951
952/*! \brief Callback function for unregistering (potentially) and destroying state */
954{
955 struct sip_outbound_registration_client_state *client_state = data;
956
957 cancel_registration(client_state);
958
959 if (client_state->client) {
960 pjsip_regc_info info;
961 pjsip_tx_data *tdata;
962
963 pjsip_regc_get_info(client_state->client, &info);
964
965 if (info.is_busy == PJ_TRUE) {
966 /* If a client transaction is in progress we defer until it is complete */
967 ast_debug(1,
968 "Registration transaction is busy with server '%.*s' from client '%.*s'.\n",
969 (int) info.server_uri.slen, info.server_uri.ptr,
970 (int) info.client_uri.slen, info.client_uri.ptr);
971 client_state->destroy = 1;
972 ao2_ref(client_state, -1);
973 return 0;
974 }
975
976 switch (client_state->status) {
978 break;
980 ast_debug(1,
981 "Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n",
982 (int) info.server_uri.slen, info.server_uri.ptr,
983 (int) info.client_uri.slen, info.client_uri.ptr);
984
986 client_state->destroy = 1;
987 if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS
988 && add_configured_supported_headers(client_state, tdata)
989 && registration_client_send(client_state, tdata) == PJ_SUCCESS) {
990 ao2_ref(client_state, -1);
991 return 0;
992 }
993 break;
998 break;
999 }
1000
1001 pjsip_regc_destroy(client_state->client);
1002 client_state->client = NULL;
1003 }
1004
1009 ao2_ref(client_state, -1);
1010
1011 return 0;
1012}
1013
1014/*! \brief Structure for registration response */
1016 /*! \brief Response code for the registration attempt */
1017 int code;
1018 /*! \brief Expiration time for registration */
1020 /*! \brief Retry-After value */
1022 /*! \brief Outbound registration client state */
1024 /*! \brief The response message */
1025 pjsip_rx_data *rdata;
1026 /*! \brief Request for which the response was received */
1027 pjsip_tx_data *old_request;
1028 /*! \brief Key for the reliable transport in use */
1030};
1031
1032/*! \brief Registration response structure destructor */
1033static void registration_response_destroy(void *obj)
1034{
1035 struct registration_response *response = obj;
1036
1037 if (response->rdata) {
1038 pjsip_rx_data_free_cloned(response->rdata);
1039 }
1040
1041 if (response->old_request) {
1042 pjsip_tx_data_dec_ref(response->old_request);
1043 }
1044
1045 ao2_cleanup(response->client_state);
1046}
1047
1048/*! \brief Helper function which determines if a response code is temporal or not */
1051{
1052 /* Shamelessly taken from pjsua */
1053 if (code == PJSIP_SC_REQUEST_TIMEOUT ||
1054 code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
1055 code == PJSIP_SC_BAD_GATEWAY ||
1056 code == PJSIP_SC_SERVICE_UNAVAILABLE ||
1057 code == PJSIP_SC_SERVER_TIMEOUT ||
1058 ((code == PJSIP_SC_UNAUTHORIZED ||
1059 code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
1061 PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
1062 return 1;
1063 } else {
1064 return 0;
1065 }
1066}
1067
1068static void schedule_retry(struct registration_response *response, unsigned int interval,
1069 const char *server_uri, const char *client_uri)
1070{
1072 schedule_registration(response->client_state, interval);
1073
1074 if (response->rdata) {
1075 ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
1076 "registration attempt to '%s', retrying in '%u'\n",
1077 response->code, server_uri, client_uri, interval);
1078 } else {
1079 ast_log(LOG_WARNING, "No response received from '%s' on "
1080 "registration attempt to '%s', retrying in '%u'\n",
1081 server_uri, client_uri, interval);
1082 }
1083}
1084
1085static int reregister_immediately_cb(void *obj)
1086{
1088
1089 if (state->client_state->status != SIP_REGISTRATION_REGISTERED) {
1090 ao2_ref(state, -1);
1091 return 0;
1092 }
1093
1094 if (DEBUG_ATLEAST(1)) {
1095 pjsip_regc_info info;
1096
1097 pjsip_regc_get_info(state->client_state->client, &info);
1099 "Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n",
1100 (int) info.server_uri.slen, info.server_uri.ptr,
1101 (int) info.client_uri.slen, info.client_uri.ptr);
1102 }
1103
1104 cancel_registration(state->client_state);
1105
1106 ao2_ref(state->client_state, +1);
1107 handle_client_registration(state->client_state);
1108
1109 ao2_ref(state, -1);
1110 return 0;
1111}
1112
1113/*!
1114 * \internal
1115 * \brief The reliable transport we registered using has shutdown.
1116 * \since 13.18.0
1117 *
1118 * \param obj What is needed to initiate a reregister attempt.
1119 *
1120 * \note Normally executed by the pjsip monitor thread.
1121 */
1123{
1124 const char *registration_name = obj;
1126
1127 state = get_state(registration_name);
1128 if (!state) {
1129 /* Registration no longer exists or shutting down. */
1130 return;
1131 }
1132 if (ast_sip_push_task(state->client_state->serializer, reregister_immediately_cb, state)) {
1133 ao2_ref(state, -1);
1134 }
1135}
1136
1137static int monitor_matcher(void *a, void *b)
1138{
1139 char *ma = a;
1140 char *mb = b;
1141
1142 return strcmp(ma, mb) == 0;
1143}
1144
1145static void registration_transport_monitor_setup(const char *transport_key, const char *registration_name)
1146{
1147 char *monitor;
1148 enum ast_transport_monitor_reg monitor_res;
1149
1150 monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL,
1152 if (!monitor) {
1153 return;
1154 }
1155 strcpy(monitor, registration_name);/* Safe */
1156
1157 /*
1158 * We'll ignore if the transport has already been shutdown before we
1159 * register the monitor. We might get into a message spamming infinite
1160 * loop of registration, shutdown, reregistration...
1161 */
1163 monitor, monitor_matcher))) {
1164 ast_log(LOG_NOTICE, "Failed to register transport monitor for regisration %s: %d\n", registration_name, monitor_res);
1165 }
1166 ao2_ref(monitor, -1);
1167}
1168
1170{
1171 static const pj_str_t associated_uri_str = { "P-Associated-URI", 16 };
1172 static const pj_str_t service_route_str = { "Service-Route", 13 };
1173 pjsip_hdr *header = NULL;
1174 pjsip_msg *msg = response->rdata->msg_info.msg;
1175 struct ast_sip_service_route_vector *service_routes = NULL;
1176
1177 /* If no transport is specified then we can't update any */
1179 return;
1180 }
1181
1182 ast_sip_transport_state_set_transport(response->client_state->transport_name, response->rdata->tp_info.transport);
1183
1184 while ((header = pjsip_msg_find_hdr_by_name(msg, &service_route_str, header ? header->next : NULL))) {
1185 char *service_route;
1186 size_t size;
1187
1188 /* The below code takes the approach that if we can't store all service routes then we
1189 * store none at all. This gives a predictable failure condition instead of storing a
1190 * partial list and having partial route headers.
1191 */
1192 size = pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1;
1193 service_route = ast_malloc(size);
1194 if (!service_route) {
1195 if (service_routes) {
1197 service_routes = NULL;
1198 }
1199 break;
1200 }
1201
1202 ast_copy_pj_str(service_route, &((pjsip_generic_string_hdr*)header)->hvalue, size);
1203
1204 if (!service_routes) {
1205 service_routes = ast_sip_service_route_vector_alloc();
1206 if (!service_routes) {
1207 ast_free(service_route);
1208 break;
1209 }
1210 }
1211
1212 if (AST_VECTOR_APPEND(service_routes, service_route)) {
1213 ast_free(service_route);
1215 service_routes = NULL;
1216 break;
1217 }
1218 }
1219
1220 /* If any service routes were handled then store them on the transport */
1221 if (service_routes) {
1223 }
1224
1225 /* If an associated URI is present in the response we need to use it on any outgoing
1226 * traffic on the transport.
1227 */
1228 header = pjsip_msg_find_hdr_by_name(msg, &associated_uri_str, NULL);
1229 if (header) {
1230 char value[pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1];
1231
1232 ast_copy_pj_str(value, &((pjsip_generic_string_hdr*)header)->hvalue, sizeof(value));
1234 }
1235}
1236
1237
1238/*! \brief Callback function for handling a response to a registration attempt */
1239static int handle_registration_response(void *data)
1240{
1241 struct registration_response *response = data;
1242 pjsip_regc_info info;
1243 char server_uri[PJSIP_MAX_URL_SIZE];
1244 char client_uri[PJSIP_MAX_URL_SIZE];
1245
1246 if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
1247 ao2_ref(response, -1);
1248 return 0;
1249 }
1250
1251 pjsip_regc_get_info(response->client_state->client, &info);
1252 ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
1253 ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
1254 response->client_state->last_status_code = response->code;
1255
1256 ast_debug(1, "Processing REGISTER response %d from server '%s' for client '%s'\n",
1257 response->code, server_uri, client_uri);
1258
1259 if (response->code == 408 || response->code == 503) {
1260 if ((ast_sip_failover_request(response->old_request))) {
1261 int res = registration_client_send(response->client_state, response->old_request);
1262 /* The tdata ref was stolen */
1263 response->old_request = NULL;
1264 if (res == PJ_SUCCESS) {
1265 ao2_ref(response, -1);
1266 return 0;
1267 }
1268 }
1269 } else if ((response->code == 401 || response->code == 407 || response->code == 494)
1270 && (!response->client_state->auth_attempted
1271 || response->rdata->msg_info.cseq->cseq != response->client_state->auth_cseq)) {
1272 int res;
1273 pjsip_cseq_hdr *cseq_hdr;
1274 pjsip_tx_data *tdata;
1275
1277 struct sip_outbound_registration *reg = NULL;
1278 struct ast_sip_endpoint *endpt = NULL;
1279 struct ao2_container *contact_container = NULL;
1280 pjsip_generic_string_hdr *header;
1281 struct pjsip_generic_string_hdr_vector header_vector;
1282 static const pj_str_t security_server = { "Security-Server", 15 };
1283
1284 if ((reg = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration",
1285 response->client_state->registration_name)) && reg->endpoint &&
1286 (endpt = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", reg->endpoint))) {
1287 /* Retrieve all contacts associated with aors from this endpoint (if set). */
1288 contact_container = ast_sip_location_retrieve_contacts_from_aor_list(endpt->aors);
1289 }
1290 /* Add server list of security mechanism to client_state and contact status if exists. */
1291 AST_VECTOR_INIT(&header_vector, 1);
1292 header = pjsip_msg_find_hdr_by_name(response->rdata->msg_info.msg, &security_server, NULL);
1293 for (; header;
1294 header = pjsip_msg_find_hdr_by_name(response->rdata->msg_info.msg, &security_server, header->next)) {
1295 AST_VECTOR_APPEND(&header_vector, header);
1297 }
1298 if (contact_container) {
1299 /* Add server security mechanisms to contact status of all associated contacts to be able to send correct
1300 * Security-Verify headers on subsequent non-REGISTER requests through this outbound registration.
1301 */
1302 ao2_callback(contact_container, OBJ_NODATA, contact_add_security_headers_to_status, &header_vector);
1303 ao2_cleanup(contact_container);
1304 }
1305 AST_VECTOR_FREE(&header_vector);
1306 ao2_cleanup(endpt);
1307 ao2_cleanup(reg);
1308 }
1309
1310 if (response->code == 494) {
1312 response->client_state->retries++;
1313 schedule_registration(response->client_state, 0);
1314 ao2_ref(response, -1);
1315 return 0;
1317 response->rdata, response->old_request, &tdata)) {
1318 response->client_state->auth_attempted = 1;
1319 ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
1320 server_uri, client_uri);
1321 pjsip_tx_data_add_ref(tdata);
1322
1323 res = registration_client_send(response->client_state, tdata);
1324
1325 /* Save the cseq that actually got sent. */
1326 cseq_hdr = (pjsip_cseq_hdr *) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ,
1327 NULL);
1328 response->client_state->auth_cseq = cseq_hdr->cseq;
1329 pjsip_tx_data_dec_ref(tdata);
1330 if (res == PJ_SUCCESS) {
1331 ao2_ref(response, -1);
1332 return 0;
1333 }
1334 } else {
1335 ast_log(LOG_WARNING, "Failed to create authenticated REGISTER request to server '%s' from client '%s'\n",
1336 server_uri, client_uri);
1337 }
1338 /* Otherwise, fall through so the failure is processed appropriately */
1339 }
1340
1341 response->client_state->auth_attempted = 0;
1342
1343 if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
1344 /* Check if this is in regards to registering or unregistering */
1345 if (response->expiration) {
1346 int next_registration_round;
1347
1348 /* If the registration went fine simply reschedule registration for the future */
1349 ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
1351 response->client_state->retries = 0;
1352 next_registration_round = response->expiration - REREGISTER_BUFFER_TIME;
1353 if (next_registration_round < 0) {
1354 /* Re-register immediately. */
1355 next_registration_round = 0;
1356 }
1357 schedule_registration(response->client_state, next_registration_round);
1358
1359 /* See if we should monitor for transport shutdown */
1360 if (PJSIP_TRANSPORT_IS_RELIABLE(response->rdata->tp_info.transport)) {
1362 response->client_state->registration_name);
1363 }
1364 } else {
1365 ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
1367 if (PJSIP_TRANSPORT_IS_RELIABLE(response->rdata->tp_info.transport)) {
1371 }
1372 }
1373
1375 } else if (response->client_state->destroy) {
1376 /* We need to deal with the pending destruction instead. */
1377 } else if (response->retry_after) {
1378 /* If we have been instructed to retry after a period of time, schedule it as such */
1379 schedule_retry(response, response->retry_after, server_uri, client_uri);
1380 } else if (response->client_state->retry_interval
1381 && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
1382 if (response->client_state->retries == response->client_state->max_retries) {
1383 /* If we received enough temporal responses to exceed our maximum give up permanently */
1385 ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
1386 server_uri, client_uri);
1387 } else {
1388 /* On the other hand if we can still try some more do so */
1389 response->client_state->retries++;
1390 schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
1391 }
1392 } else {
1393 if (response->code == 403
1395 && response->client_state->retries < response->client_state->max_retries) {
1396 /* A forbidden response retry interval is configured and there are retries remaining */
1398 response->client_state->retries++;
1400 ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1401 server_uri, client_uri, response->client_state->forbidden_retry_interval);
1402 } else if (response->client_state->fatal_retry_interval
1403 && response->client_state->retries < response->client_state->max_retries) {
1404 /* Some kind of fatal failure response received, so retry according to configured interval */
1406 response->client_state->retries++;
1408 ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1409 response->code, server_uri, client_uri, response->client_state->fatal_retry_interval);
1410 } else {
1411 /* Finally if there's no hope of registering give up */
1413 if (response->rdata) {
1414 ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
1415 response->code, server_uri, client_uri);
1416 } else {
1417 ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
1418 }
1419 }
1420 }
1421
1422 ast_system_publish_registry("PJSIP", client_uri, server_uri,
1424
1425 if (response->client_state->destroy) {
1426 /* We have a pending deferred destruction to complete now. */
1427 ao2_ref(response->client_state, +1);
1429 }
1430
1431 ao2_ref(response, -1);
1432 return 0;
1433}
1434
1435/*! \brief Callback function for outbound registration client */
1436static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
1437{
1438 struct sip_outbound_registration_client_state *client_state = param->token;
1439 struct registration_response *response;
1440 int *callback_invoked;
1441
1442 callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
1443
1444 ast_assert(callback_invoked != NULL);
1446
1447 *callback_invoked = 1;
1448
1449 response = ao2_alloc(sizeof(*response), registration_response_destroy);
1450 if (!response) {
1451 ao2_ref(client_state, -1);
1452 return;
1453 }
1454 response->code = param->code;
1455 response->expiration = param->expiration;
1456 /*
1457 * Transfer client_state reference to response so the
1458 * nominal path will not dec the client_state ref in this
1459 * pjproject callback thread.
1460 */
1461 response->client_state = client_state;
1462
1463 ast_debug(1, "Received REGISTER response %d(%.*s)\n",
1464 param->code, (int) param->reason.slen, param->reason.ptr);
1465
1466 if (param->rdata) {
1467 struct pjsip_retry_after_hdr *retry_after;
1468 pjsip_transaction *tsx;
1469
1470 retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER,
1471 NULL);
1472 response->retry_after = retry_after ? retry_after->ivalue : 0;
1473
1474 /*
1475 * If we got a response from the server, we have to use the tdata
1476 * from the transaction, not the tdata saved when we sent the
1477 * request. If we use the saved tdata, we won't process responses
1478 * like 423 Interval Too Brief correctly and we'll wind up sending
1479 * the bad Expires value again.
1480 */
1481 pjsip_tx_data_dec_ref(client_state->last_tdata);
1482
1483 tsx = pjsip_rdata_get_tsx(param->rdata);
1484 response->old_request = tsx->last_tx;
1485 pjsip_tx_data_add_ref(response->old_request);
1486 pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
1487 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(param->rdata->tp_info.transport,
1488 response->transport_key);
1489
1490 } else {
1491 /* old_request steals the reference */
1492 response->old_request = client_state->last_tdata;
1493 }
1494 client_state->last_tdata = NULL;
1495
1496 /*
1497 * Transfer response reference to serializer task so the
1498 * nominal path will not dec the response ref in this
1499 * pjproject callback thread.
1500 */
1501 if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
1502 ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
1503 ao2_cleanup(response);
1504 }
1505}
1506
1507/*! \brief Destructor function for registration state */
1509{
1511
1512 ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n",
1513 state->registration ? state->registration->server_uri : "",
1514 state->registration ? state->registration->client_uri : "");
1515 ao2_cleanup(state->registration);
1516
1517 if (!state->client_state) {
1518 /* Nothing to do */
1519 } else if (!state->client_state->serializer) {
1520 ao2_ref(state->client_state, -1);
1521 } else if (ast_sip_push_task(state->client_state->serializer,
1522 handle_client_state_destruction, state->client_state)) {
1523 ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
1524 ao2_ref(state->client_state, -1);
1525 }
1526}
1527
1528/*! \brief Destructor function for client registration state */
1530{
1531 struct sip_outbound_registration_client_state *client_state = obj;
1532
1533 ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0);
1534 ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
1536
1538 ast_free(client_state->transport_name);
1539 ast_free(client_state->registration_name);
1540 ast_free(client_state->user_agent);
1541 if (client_state->last_tdata) {
1542 pjsip_tx_data_dec_ref(client_state->last_tdata);
1543 }
1544}
1545
1546/*! \brief Allocator function for registration state */
1548{
1550 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1551
1553 if (!state) {
1554 return NULL;
1555 }
1556 state->client_state = ao2_alloc(sizeof(*state->client_state),
1558 if (!state->client_state) {
1560 return NULL;
1561 }
1562
1563 state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
1564 pj_timer_entry_init(&state->client_state->timer, 0, state->client_state,
1566 state->client_state->transport_name = ast_strdup(registration->transport);
1567 state->client_state->registration_name =
1569 state->client_state->user_agent = ast_strdup(registration->user_agent);
1570
1571 ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0);
1572 ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
1573 sip_outbound_registration_status_str(state->client_state->status));
1574
1575 if (!state->client_state->transport_name
1576 || !state->client_state->registration_name) {
1578 return NULL;
1579 }
1580
1581 /* Create name with seq number appended. */
1582 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outreg/%s",
1584
1585 state->client_state->serializer = ast_sip_create_serializer_group(tps_name,
1587 if (!state->client_state->serializer) {
1589 return NULL;
1590 }
1591
1592 state->registration = ao2_bump(registration);
1593 return state;
1594}
1595
1596/*! \brief Destructor function for registration information */
1598{
1599 struct sip_outbound_registration *registration = obj;
1600
1603
1604 ast_string_field_free_memory(registration);
1605}
1606
1607/*! \brief Allocator function for registration information */
1608static void *sip_outbound_registration_alloc(const char *name)
1609{
1610 struct sip_outbound_registration *registration;
1611
1612 registration = ast_sorcery_generic_alloc(sizeof(*registration),
1614 if (!registration || ast_string_field_init(registration, 256)) {
1615 ao2_cleanup(registration);
1616 return NULL;
1617 }
1618
1619 return registration;
1620}
1621
1622/*! \brief Helper function which populates a pj_str_t with a contact header */
1623static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user,
1624 const pj_str_t *target, pjsip_tpselector *selector, const char *line, const char *header_params)
1625{
1626 pj_str_t tmp, local_addr;
1627 pjsip_uri *uri;
1628 pjsip_sip_uri *sip_uri;
1629 pjsip_transport_type_e type;
1630 int local_port;
1631
1632 pj_strdup_with_null(pool, &tmp, target);
1633
1634 if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
1635 (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
1636 return -1;
1637 }
1638
1639 sip_uri = pjsip_uri_get_uri(uri);
1640
1641 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
1642 if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
1643 if (type == PJSIP_TRANSPORT_UNSPECIFIED
1644 || !(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE)) {
1645 type = PJSIP_TRANSPORT_TLS;
1646 }
1647 } else if (!sip_uri->transport_param.slen) {
1648 type = PJSIP_TRANSPORT_UDP;
1649 } else if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
1650 return -1;
1651 }
1652
1653 if (pj_strchr(&sip_uri->host, ':')) {
1654 type |= PJSIP_TRANSPORT_IPV6;
1655 }
1656
1657 if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
1658 pool, type, selector, &local_addr, &local_port) != PJ_SUCCESS) {
1659 return -1;
1660 }
1661
1662 if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
1663 type |= PJSIP_TRANSPORT_IPV6;
1664 }
1665
1666 contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
1667 contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
1668 "<%s:%s@%s%.*s%s:%d%s%s%s%s>%s%s",
1669 ((pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) && PJSIP_URI_SCHEME_IS_SIPS(uri)) ? "sips" : "sip",
1670 user,
1671 (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
1672 (int)local_addr.slen,
1673 local_addr.ptr,
1674 (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
1675 local_port,
1676 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
1677 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "",
1678 !ast_strlen_zero(line) ? ";line=" : "",
1679 S_OR(line, ""),
1680 !ast_strlen_zero(header_params) ? ";" : "",
1681 S_OR(header_params, ""));
1682
1683 return 0;
1684}
1685
1686/*!
1687 * \internal
1688 * \brief Check if a registration can be reused
1689 *
1690 * This checks if the existing outbound registration's configuration differs from a newly-applied
1691 * outbound registration to see if the applied one.
1692 *
1693 * \param existing The pre-existing outbound registration
1694 * \param applied The newly-created registration
1695 */
1697 struct sip_outbound_registration *applied)
1698{
1699 int rc = 1;
1701 struct ast_variable *ve = ast_sorcery_objectset_create(sorcery, existing);
1702 struct ast_variable *va = ast_sorcery_objectset_create(sorcery, applied);
1703 struct ast_variable *vc = NULL;
1704
1705 if (ast_sorcery_changeset_create(ve, va, &vc) || vc != NULL) {
1706 rc = 0;
1707 ast_debug(4, "Registration '%s' changed. Can't re-use.\n", ast_sorcery_object_get_id(existing));
1708 } else {
1709 ast_debug(4, "Registration '%s' didn't change. Can re-use\n", ast_sorcery_object_get_id(existing));
1710 }
1711
1715
1716 return rc;
1717}
1718
1719/*! \brief Get google oauth2 access token using refresh token */
1720static const char *fetch_google_access_token(const struct ast_sip_auth *auth)
1721{
1722 char *cmd = NULL;
1723 const char *token;
1724 const char *url = "https://www.googleapis.com/oauth2/v3/token";
1725 char buf[4096];
1726 int res;
1727 struct ast_json_error error;
1728 struct ast_json *json;
1729
1730 /* set timeout to be shorter than default 180s (also checks func_curl is available) */
1731 if (ast_func_write(NULL, "CURLOPT(conntimeout)", "10")) {
1732 ast_log(LOG_ERROR, "CURL is unavailable. This is required for Google OAuth 2.0 authentication. Please ensure it is loaded.\n");
1733 return NULL;
1734 }
1735
1736 res = ast_asprintf(&cmd,
1737 "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)",
1738 url, auth->oauth_clientid, auth->oauth_secret, auth->refresh_token);
1739 if (res < 0) {
1740 return NULL;
1741 }
1742
1743 ast_debug(2, "Performing Google OAuth 2.0 authentication using command: %s\n", cmd);
1744
1745 buf[0] = '\0';
1746 res = ast_func_read(NULL, cmd, buf, sizeof(buf));
1747 ast_free(cmd);
1748 if (res) {
1749 ast_log(LOG_ERROR, "Could not retrieve Google OAuth 2.0 authentication\n");
1750 return NULL;
1751 }
1752
1753 ast_debug(2, "Google OAuth 2.0 authentication returned: %s\n", buf);
1754
1755 json = ast_json_load_string(buf, &error);
1756 if (!json) {
1757 ast_log(LOG_ERROR, "Could not parse Google OAuth 2.0 authentication: %d(%d) %s: '%s'\n",
1758 error.line, error.column, error.text, buf);
1759 return NULL;
1760 }
1761
1762 token = ast_json_string_get(ast_json_object_get(json, "access_token"));
1763 if (!token) {
1764 ast_log(LOG_ERROR, "Could not find Google OAuth 2.0 access_token in: '%s'\n",
1765 buf);
1766 }
1767 token = ast_strdup(token);
1768 ast_json_unref(json);
1769 return token;
1770}
1771
1772/*!
1773 * \internal
1774 * \brief Set pjsip registration context with any authentication credentials that need to be
1775 * sent in the initial registration request
1776 *
1777 * \param regc The pjsip registration context
1778 * \param auth_vector The vector of configured authentication credentials
1779 */
1781 const struct ast_sip_auth_vector *auth_vector)
1782{
1783 size_t auth_size = AST_VECTOR_SIZE(auth_vector);
1784 struct ast_sip_auth *auths[auth_size];
1785 const char *access_token;
1786 pjsip_cred_info auth_creds[1];
1787 pjsip_auth_clt_pref prefs;
1788 int res = 0;
1789 int idx;
1790
1791 memset(auths, 0, sizeof(auths));
1792 if (ast_sip_retrieve_auths(auth_vector, auths)) {
1793 res = -1;
1794 goto cleanup;
1795 }
1796
1797 for (idx = 0; idx < auth_size; ++idx) {
1798 switch (auths[idx]->type) {
1800 pj_cstr(&auth_creds[0].username, auths[idx]->auth_user);
1801 pj_cstr(&auth_creds[0].scheme, "Bearer");
1802 pj_cstr(&auth_creds[0].realm, auths[idx]->realm);
1803 ast_debug(2, "Obtaining Google OAuth access token\n");
1804 access_token = fetch_google_access_token(auths[idx]);
1805 if (!access_token) {
1806 ast_log(LOG_WARNING, "Obtaining Google OAuth access token failed\n");
1807 access_token = auths[idx]->auth_pass;
1808 res = -1;
1809 }
1810 ast_debug(2, "Setting data to '%s'\n", access_token);
1811
1812 pj_cstr(&auth_creds[0].data, access_token);
1813 auth_creds[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
1814
1815 pjsip_regc_set_credentials(regc, 1, auth_creds);
1816
1817 /* for oauth, send auth without waiting for unauthorized response */
1818 prefs.initial_auth = PJ_TRUE;
1819 pj_cstr(&prefs.algorithm, "oauth");
1820 pjsip_regc_set_prefs(regc, &prefs);
1821
1822 if (access_token != auths[idx]->auth_pass) {
1823 ast_free((char *) access_token);
1824 }
1825 break;
1826 default:
1827 /* other cases handled after receiving auth rejection */
1828 break;
1829 }
1830 }
1831
1832cleanup:
1833 ast_sip_cleanup_auths(auths, auth_size);
1834 return res;
1835}
1836
1837/*! \brief Helper function that allocates a pjsip registration client and configures it */
1839{
1842 ao2_bump(state->registration), ao2_cleanup);
1843 pj_pool_t *pool;
1844 pj_str_t tmp;
1845 pjsip_uri *uri;
1846 pj_str_t server_uri, client_uri, contact_uri;
1847 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
1848
1849 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
1850 if (!pool) {
1851 ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
1853 return -1;
1854 }
1855
1856 pj_strdup2_with_null(pool, &tmp, registration->server_uri);
1857 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1858 if (!uri) {
1859 ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
1861 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1862 return -1;
1863 }
1864
1865 pj_strdup2_with_null(pool, &tmp, registration->client_uri);
1866 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1867 if (!uri) {
1868 ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
1870 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1871 return -1;
1872 }
1873
1874 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1875
1876 ast_assert(state->client_state->client == NULL);
1877 if (pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state,
1879 &state->client_state->client) != PJ_SUCCESS) {
1880 return -1;
1881 }
1882
1884 pjsip_regc_set_transport(state->client_state->client, &selector);
1885
1887 pjsip_route_hdr route_set, *route;
1888 static const pj_str_t ROUTE_HNAME = { "Route", 5 };
1889 pj_str_t tmp;
1890
1891 pj_list_init(&route_set);
1892
1893 pj_strdup2_with_null(pjsip_regc_get_pool(state->client_state->client), &tmp,
1895 route = pjsip_parse_hdr(pjsip_regc_get_pool(state->client_state->client),
1896 &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL);
1897 if (!route) {
1898 ast_sip_tpselector_unref(&selector);
1899 return -1;
1900 }
1901 pj_list_insert_nodes_before(&route_set, route);
1902
1903 pjsip_regc_set_route_set(state->client_state->client, &route_set);
1904 }
1905
1906 if (state->registration->line) {
1907 ast_generate_random_string(state->client_state->line, sizeof(state->client_state->line));
1908 }
1909
1911
1912 if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client),
1913 &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
1914 state->client_state->line, registration->contact_header_params)) {
1915 ast_sip_tpselector_unref(&selector);
1916 return -1;
1917 }
1918
1919 ast_sip_tpselector_unref(&selector);
1920
1921 pj_cstr(&client_uri, registration->client_uri);
1922 if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri,
1923 &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
1924 return -1;
1925 }
1926
1927 return 0;
1928}
1929
1930/*! \brief Helper function which performs a single registration */
1932{
1934 struct sip_outbound_registration *registration = ao2_bump(state->registration);
1935 size_t i;
1936 int max_delay;
1937
1938 /* Just in case the client state is being reused for this registration, free the auth information */
1939 ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
1940 ast_sip_security_mechanisms_vector_destroy(&state->client_state->security_mechanisms);
1941 ast_sip_security_mechanisms_vector_destroy(&state->client_state->server_security_mechanisms);
1942
1943 AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(&registration->outbound_auths));
1944 for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
1945 char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
1946
1947 if (name && AST_VECTOR_APPEND(&state->client_state->outbound_auths, name)) {
1948 ast_free(name);
1949 }
1950 }
1951 ast_sip_security_mechanisms_vector_copy(&state->client_state->security_mechanisms,
1952 &registration->security_mechanisms);
1953 state->client_state->retry_interval = registration->retry_interval;
1954 state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
1955 state->client_state->fatal_retry_interval = registration->fatal_retry_interval;
1956 state->client_state->max_retries = registration->max_retries;
1957 state->client_state->retries = 0;
1958 state->client_state->support_path = registration->support_path;
1959 state->client_state->support_outbound = registration->support_outbound;
1960 state->client_state->security_negotiation = registration->security_negotiation;
1961 state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
1962 max_delay = registration->max_random_initial_delay;
1963
1964 pjsip_regc_update_expires(state->client_state->client, registration->expiration);
1965
1966 /* n mod 0 is undefined, so don't let that happen */
1967 schedule_registration(state->client_state, (max_delay ? ast_random() % max_delay : 0) + 1);
1968
1969 ao2_ref(registration, -1);
1970 ao2_ref(state, -1);
1971 return 0;
1972}
1973
1974/*! \brief Apply function which finds or allocates a state structure */
1975static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
1976{
1977 RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup);
1980 struct sip_outbound_registration *applied = obj;
1981
1982 if (!states) {
1983 /* Global container has gone. Likely shutting down. */
1984 return -1;
1985 }
1987
1988 ast_debug(4, "Applying configuration to outbound registration '%s'\n", ast_sorcery_object_get_id(applied));
1989
1990 if (ast_strlen_zero(applied->server_uri)) {
1991 ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'\n",
1992 ast_sorcery_object_get_id(applied));
1993 return -1;
1994 } else if (ast_sip_validate_uri_length(applied->server_uri)) {
1995 ast_log(LOG_ERROR, "Server URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
1996 ast_sorcery_object_get_id(applied));
1997 return -1;
1998 } else if (ast_strlen_zero(applied->client_uri)) {
1999 ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
2000 ast_sorcery_object_get_id(applied));
2001 return -1;
2002 } else if (ast_sip_validate_uri_length(applied->client_uri)) {
2003 ast_log(LOG_ERROR, "Client URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
2004 ast_sorcery_object_get_id(applied));
2005 return -1;
2006 } else if (applied->line && ast_strlen_zero(applied->endpoint)) {
2007 ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
2008 ast_sorcery_object_get_id(applied));
2009 return -1;
2010 } else if (!ast_strlen_zero(applied->endpoint) && !applied->line) {
2011 ast_log(LOG_ERROR, "An endpoint has been specified on outbound registration '%s' without enabling line support\n",
2012 ast_sorcery_object_get_id(applied));
2013 return -1;
2014 }
2015
2016 if (state && can_reuse_registration(state->registration, applied)) {
2017 ast_debug(4,
2018 "No change between old configuration and new configuration on outbound registration '%s'. Using previous state\n",
2019 ast_sorcery_object_get_id(applied));
2020
2021 /*
2022 * This is OK to replace without relinking the state in the
2023 * current_states container since state->registration and
2024 * applied have the same key.
2025 */
2026 ao2_lock(states);
2027 ao2_replace(state->registration, applied);
2028 ao2_unlock(states);
2029 return 0;
2030 }
2031
2032 if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
2033 return -1;
2034 }
2035
2036 if (ast_sip_push_task_wait_serializer(new_state->client_state->serializer,
2038 return -1;
2039 }
2040
2041 if (ast_sip_push_task(new_state->client_state->serializer,
2043 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n",
2044 ast_sorcery_object_get_id(new_state->registration));
2045 ao2_ref(new_state, -1);
2046 return -1;
2047 }
2048
2049 ao2_lock(states);
2050 if (state) {
2051 ao2_unlink(states, state);
2052 }
2053 ao2_link(states, new_state);
2054 ao2_unlock(states);
2055
2056 return 0;
2057}
2058
2059static int security_mechanism_to_str(const void *obj, const intptr_t *args, char **buf)
2060{
2061 const struct sip_outbound_registration *registration = obj;
2062
2064}
2065
2066static const char *security_negotiation_map[] = {
2068 [AST_SIP_SECURITY_NEG_MEDIASEC] = "mediasec",
2069};
2070
2071static int security_negotiation_to_str(const void *obj, const intptr_t *args, char **buf)
2072{
2073 const struct sip_outbound_registration *registration = obj;
2076 }
2077 return 0;
2078}
2079
2080static int security_mechanisms_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2081{
2082 struct sip_outbound_registration *registration = obj;
2083
2084 return ast_sip_security_mechanism_vector_init(&registration->security_mechanisms, var->value);
2085}
2086
2087static int security_negotiation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2088{
2089 struct sip_outbound_registration *registration = obj;
2090
2091 return ast_sip_set_security_negotiation(&registration->security_negotiation, var->value);
2092}
2093
2094static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2095{
2096 struct sip_outbound_registration *registration = obj;
2097
2098 return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
2099}
2100
2101static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
2102{
2103 const struct sip_outbound_registration *registration = obj;
2104
2105 return ast_sip_auths_to_str(&registration->outbound_auths, buf);
2106}
2107
2108static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
2109{
2110 const struct sip_outbound_registration *registration = obj;
2111 int i;
2112 struct ast_variable *head = NULL;
2113
2114 for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
2115 ast_variable_list_append(&head, ast_variable_new("outbound_auth",
2116 AST_VECTOR_GET(&registration->outbound_auths, i), ""));
2117 }
2118
2119 if (head) {
2120 *fields = head;
2121 }
2122
2123 return 0;
2124}
2125
2126static int unregister_task(void *obj)
2127{
2129 struct pjsip_regc *client = state->client_state->client;
2130 pjsip_tx_data *tdata;
2131 pjsip_regc_info info;
2132
2133 pjsip_regc_get_info(client, &info);
2134 ast_debug(1, "Unregistering contacts with server '%s' from client '%s'\n",
2135 state->registration->server_uri, state->registration->client_uri);
2136
2137 cancel_registration(state->client_state);
2138
2139 if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS
2140 && add_configured_supported_headers(state->client_state, tdata)) {
2141 registration_client_send(state->client_state, tdata);
2142 }
2143
2144 ao2_ref(state, -1);
2145 return 0;
2146}
2147
2149{
2150 ao2_ref(state, +1);
2151 if (ast_sip_push_task(state->client_state->serializer, unregister_task, state)) {
2152 ao2_ref(state, -1);
2153 return -1;
2154 }
2155
2156 return 0;
2157}
2158
2160{
2161 ao2_ref(state, +1);
2162 if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) {
2163 ao2_ref(state, -1);
2164 return -1;
2165 }
2166
2167 return 0;
2168}
2169
2170static void unregister_all(void)
2171{
2172 struct ao2_container *states;
2173
2174 states = ao2_global_obj_ref(current_states);
2175 if (!states) {
2176 return;
2177 }
2178
2179 /* Clean out all the states and let sorcery handle recreating the registrations */
2181 ao2_ref(states, -1);
2182}
2183
2184static void reregister_all(void)
2185{
2188}
2189
2190static char *cli_complete_registration(const char *line, const char *word,
2191 int pos, int state)
2192{
2193 char *result = NULL;
2194 int wordlen;
2195 int which = 0;
2196 struct sip_outbound_registration *registration;
2198 struct ao2_iterator i;
2199
2200 if (pos != 3) {
2201 return NULL;
2202 }
2203
2204 wordlen = strlen(word);
2205 if (wordlen == 0 && ++which > state) {
2206 return ast_strdup("*all");
2207 }
2208
2211 if (!registrations) {
2212 return NULL;
2213 }
2214
2216 while ((registration = ao2_iterator_next(&i))) {
2217 const char *name = ast_sorcery_object_get_id(registration);
2218
2219 if (!strncasecmp(word, name, wordlen) && ++which > state) {
2221 }
2222
2223 ao2_ref(registration, -1);
2224 if (result) {
2225 break;
2226 }
2227 }
2229
2231 return result;
2232}
2233
2234static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2235{
2237 const char *registration_name;
2238
2239 switch (cmd) {
2240 case CLI_INIT:
2241 e->command = "pjsip send unregister";
2242 e->usage =
2243 "Usage: pjsip send unregister <registration> | *all\n"
2244 " Unregisters the specified (or all) outbound registration(s) "
2245 "and stops future registration attempts.\n";
2246 return NULL;
2247 case CLI_GENERATE:
2248 return cli_complete_registration(a->line, a->word, a->pos, a->n);
2249 }
2250
2251 if (a->argc != 4) {
2252 return CLI_SHOWUSAGE;
2253 }
2254
2255 registration_name = a->argv[3];
2256
2257 if (strcmp(registration_name, "*all") == 0) {
2259 ast_cli(a->fd, "Unregister all queued\n");
2260 return CLI_SUCCESS;
2261 }
2262
2263 state = get_state(registration_name);
2264 if (!state) {
2265 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
2266 return CLI_FAILURE;
2267 }
2268
2269 if (queue_unregister(state)) {
2270 ast_cli(a->fd, "Failed to queue unregistration\n");
2271 }
2272
2273 ao2_ref(state, -1);
2274 return CLI_SUCCESS;
2275}
2276
2277static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2278{
2280 const char *registration_name;
2281
2282 switch (cmd) {
2283 case CLI_INIT:
2284 e->command = "pjsip send register";
2285 e->usage =
2286 "Usage: pjsip send register <registration> | *all \n"
2287 " Unregisters the specified (or all) outbound "
2288 "registration(s) then starts registration(s) and schedules re-registrations.\n";
2289 return NULL;
2290 case CLI_GENERATE:
2291 return cli_complete_registration(a->line, a->word, a->pos, a->n);
2292 }
2293
2294 if (a->argc != 4) {
2295 return CLI_SHOWUSAGE;
2296 }
2297
2298 registration_name = a->argv[3];
2299
2300 if (strcmp(registration_name, "*all") == 0) {
2302 ast_cli(a->fd, "Re-register all queued\n");
2303 return CLI_SUCCESS;
2304 }
2305
2306 state = get_state(registration_name);
2307 if (!state) {
2308 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
2309 return CLI_FAILURE;
2310 }
2311
2312 /* We need to serialize the unregister and register so they need
2313 * to be queued as separate tasks.
2314 */
2315 if (queue_unregister(state)) {
2316 ast_cli(a->fd, "Failed to queue unregistration\n");
2317 } else if (queue_register(state)) {
2318 ast_cli(a->fd, "Failed to queue registration\n");
2319 }
2320
2321 ao2_ref(state, -1);
2322 return CLI_SUCCESS;
2323}
2324
2325static int ami_unregister(struct mansession *s, const struct message *m)
2326{
2327 const char *registration_name = astman_get_header(m, "Registration");
2329
2330 if (ast_strlen_zero(registration_name)) {
2331 astman_send_error(s, m, "Registration parameter missing.");
2332 return 0;
2333 }
2334
2335 if (strcmp(registration_name, "*all") == 0) {
2337 astman_send_ack(s, m, "Unregistrations queued.");
2338 return 0;
2339 }
2340
2341 state = get_state(registration_name);
2342 if (!state) {
2343 astman_send_error(s, m, "Unable to retrieve registration entry\n");
2344 return 0;
2345 }
2346
2347 if (queue_unregister(state)) {
2348 astman_send_ack(s, m, "Failed to queue unregistration");
2349 } else {
2350 astman_send_ack(s, m, "Unregistration sent");
2351 }
2352
2353 ao2_ref(state, -1);
2354 return 0;
2355}
2356
2357static int ami_register(struct mansession *s, const struct message *m)
2358{
2359 const char *registration_name = astman_get_header(m, "Registration");
2361
2362 if (ast_strlen_zero(registration_name)) {
2363 astman_send_error(s, m, "Registration parameter missing.");
2364 return 0;
2365 }
2366
2367 if (strcmp(registration_name, "*all") == 0) {
2369 astman_send_ack(s, m, "Reregistrations queued.");
2370 return 0;
2371 }
2372
2373 state = get_state(registration_name);
2374 if (!state) {
2375 astman_send_error(s, m, "Unable to retrieve registration entry\n");
2376 return 0;
2377 }
2378
2379 /* We need to serialize the unregister and register so they need
2380 * to be queued as separate tasks.
2381 */
2382 if (queue_unregister(state)) {
2383 astman_send_ack(s, m, "Failed to queue unregistration");
2384 } else if (queue_register(state)) {
2385 astman_send_ack(s, m, "Failed to queue unregistration");
2386 } else {
2387 astman_send_ack(s, m, "Reregistration sent");
2388 }
2389
2390 ao2_ref(state, -1);
2391 return 0;
2392}
2393
2399};
2400
2402{
2403 struct sip_ami_outbound *ami = obj;
2404 struct ast_str *buf;
2406
2407 buf = ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami);
2408 if (!buf) {
2409 return -1;
2410 }
2411
2413
2415 pjsip_regc_info info;
2416
2417 if (state->client_state->status == SIP_REGISTRATION_REGISTERED) {
2418 ++ami->registered;
2419 } else {
2420 ++ami->not_registered;
2421 }
2422
2423 ast_str_append(&buf, 0, "Status: %s\r\n",
2424 sip_outbound_registration_status_str(state->client_state->status));
2425
2426 pjsip_regc_get_info(state->client_state->client, &info);
2427 ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg);
2428 ao2_ref(state, -1);
2429 }
2430
2431 astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
2432 ast_free(buf);
2433
2435}
2436
2437static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
2438{
2439 struct sip_ami_outbound *ami = arg;
2440
2441 ami->registration = obj;
2443}
2444
2446 const struct message *m)
2447{
2448 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2449 struct sip_ami_outbound ami_outbound = { .ami = &ami };
2450 struct ao2_container *regs;
2451
2452 regs = get_registrations();
2453 if (!regs) {
2454 astman_send_error(s, m, "Unable to retrieve "
2455 "outbound registrations\n");
2456 return -1;
2457 }
2458
2459 astman_send_listack(s, m, "Following are Events for each Outbound registration",
2460 "start");
2461
2463
2464 astman_send_list_complete_start(s, m, "OutboundRegistrationDetailComplete",
2465 ami_outbound.registered + ami_outbound.not_registered);
2466 astman_append(s,
2467 "Registered: %d\r\n"
2468 "NotRegistered: %d\r\n",
2469 ami_outbound.registered,
2470 ami_outbound.not_registered);
2472
2473 ao2_ref(regs, -1);
2474 return 0;
2475}
2476
2477static struct ao2_container *cli_get_container(const char *regex)
2478{
2480 struct ao2_container *s_container;
2481
2483 if (!container) {
2484 return NULL;
2485 }
2486
2489 if (!s_container) {
2490 return NULL;
2491 }
2492
2493 if (ao2_container_dup(s_container, container, 0)) {
2494 ao2_ref(s_container, -1);
2495 return NULL;
2496 }
2497
2498 return s_container;
2499}
2500
2501static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
2502{
2504
2505 return 0;
2506}
2507
2508static void *cli_retrieve_by_id(const char *id)
2509{
2510 struct ao2_container *states;
2511 void *obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
2512
2513 if (!obj) {
2514 /* if the object no longer exists then remove its state */
2515 states = ao2_global_obj_ref(current_states);
2516 if (states) {
2518 ao2_ref(states, -1);
2519 }
2520 }
2521
2522 return obj;
2523}
2524
2525static int cli_print_header(void *obj, void *arg, int flags)
2526{
2527 struct ast_sip_cli_context *context = arg;
2528
2529 ast_assert(context->output_buffer != NULL);
2530
2531 ast_str_append(&context->output_buffer, 0,
2532 " <Registration/ServerURI..............................> <Auth....................> <Status.......>\n");
2533
2534 return 0;
2535}
2536
2537static int cli_print_body(void *obj, void *arg, int flags)
2538{
2539 struct sip_outbound_registration *registration = obj;
2540 struct ast_sip_cli_context *context = arg;
2541 const char *id = ast_sorcery_object_get_id(registration);
2543 int expsecs;
2544#define REGISTRATION_URI_FIELD_LEN 53
2545
2546 ast_assert(context->output_buffer != NULL);
2547 expsecs = state ? state->client_state->registration_expires - ((int) time(NULL)) : 0;
2548
2549 ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-26s %-16s %s%d%s\n",
2550 id,
2551 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2552 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2556 : "n/a",
2557 (state ? sip_outbound_registration_status_str(state->client_state->status) : "Unregistered"),
2558 state ? " (exp. " : "", abs(expsecs), state ? (expsecs < 0 ? "s ago)" : "s)") : "");
2560
2561 if (context->show_details
2562 || (context->show_details_only_level_0 && context->indent_level == 0)) {
2563 ast_str_append(&context->output_buffer, 0, "\n");
2565 }
2566
2567 return 0;
2568}
2569
2570/*
2571 * A function pointer to callback needs to be within the
2572 * module in order to avoid problems with an undefined
2573 * symbol when the module is loaded.
2574 */
2575static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2576{
2577 return ast_sip_cli_traverse_objects(e, cmd, a);
2578}
2579
2581 AST_CLI_DEFINE(cli_unregister, "Unregisters outbound registration target"),
2582 AST_CLI_DEFINE(cli_register, "Registers an outbound registration target"),
2583 AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
2584 .command = "pjsip list registrations",
2585 .usage = "Usage: pjsip list registrations [ like <pattern> ]\n"
2586 " List the configured PJSIP Registrations\n"
2587 " Optional regular expression pattern is used to filter the list.\n"),
2588 AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
2589 .command = "pjsip show registrations",
2590 .usage = "Usage: pjsip show registrations [ like <pattern> ]\n"
2591 " Show the configured PJSIP Registrations\n"
2592 " Optional regular expression pattern is used to filter the list.\n"),
2593 AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
2594 .command = "pjsip show registration",
2595 .usage = "Usage: pjsip show registration <id>\n"
2596 " Show the configured PJSIP Registration\n"),
2597};
2598
2600
2601static void auth_observer(const char *type)
2602{
2603 struct sip_outbound_registration *registration;
2605 struct ao2_container *regs;
2606 const char *registration_id;
2607 struct ao2_iterator i;
2608
2609 ast_debug(4, "Auths updated. Checking for any outbound registrations that are in permanent rejected state so they can be retried\n");
2610
2611 regs = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
2613 if (!regs || ao2_container_count(regs) == 0) {
2614 ao2_cleanup(regs);
2615 return;
2616 }
2617
2618 i = ao2_iterator_init(regs, 0);
2619 for (; (registration = ao2_iterator_next(&i)); ao2_ref(registration, -1)) {
2620 registration_id = ast_sorcery_object_get_id(registration);
2621 state = get_state(registration_id);
2622 if (state && state->client_state->status == SIP_REGISTRATION_REJECTED_PERMANENT) {
2623 ast_debug(4, "Trying outbound registration '%s' again\n", registration_id);
2624
2625 if (ast_sip_push_task(state->client_state->serializer,
2627 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", registration_id);
2628 ao2_ref(state, -1);
2629 }
2630 }
2632 }
2634 ao2_cleanup(regs);
2635}
2636
2639};
2640
2641static int check_state(void *obj, void *arg, int flags)
2642{
2644 struct sip_outbound_registration *registration;
2645
2646 registration = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration",
2647 ast_sorcery_object_get_id(state->registration));
2648 if (!registration) {
2649 /* This is a dead registration */
2650 return CMP_MATCH;
2651 }
2652
2653 ao2_ref(registration, -1);
2654 return 0;
2655}
2656
2657/*!
2658 * \internal
2659 * \brief Observer to purge dead registration states.
2660 *
2661 * \param name Module name owning the sorcery instance.
2662 * \param sorcery Instance being observed.
2663 * \param object_type Name of object being observed.
2664 * \param reloaded Non-zero if the object is being reloaded.
2665 */
2666static void registration_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
2667{
2668 struct ao2_container *states;
2669
2670 if (strcmp(object_type, "registration")) {
2671 /* Not interested */
2672 return;
2673 }
2674
2675 states = ao2_global_obj_ref(current_states);
2676 if (!states) {
2677 /* Global container has gone. Likely shutting down. */
2678 return;
2679 }
2680
2681 /*
2682 * Refresh the current configured registrations. We don't need to hold
2683 * onto the objects, as the apply handler will cause their states to
2684 * be created appropriately.
2685 */
2687
2688 /* Now to purge dead registrations. */
2690 ao2_ref(states, -1);
2691}
2692
2695};
2696
2697static void registration_deleted_observer(const void *obj)
2698{
2699 const struct sip_outbound_registration *registration = obj;
2700 struct ao2_container *states;
2701
2702 states = ao2_global_obj_ref(current_states);
2703 if (!states) {
2704 /* Global container has gone. Likely shutting down. */
2705 return;
2706 }
2707
2709
2710 ao2_ref(states, -1);
2711}
2712
2715};
2716
2718{
2719 /* This callback is only concerned with network change messages from the system topic. */
2721 return;
2722 }
2723 ast_debug(3, "Received network change event\n");
2724
2726}
2727
2728static int unload_module(void)
2729{
2730 int remaining;
2731
2733
2734 ast_manager_unregister("PJSIPShowRegistrationsOutbound");
2735 ast_manager_unregister("PJSIPUnregister");
2736 ast_manager_unregister("PJSIPRegister");
2737
2741
2743
2746
2748
2749 ao2_global_obj_release(current_states);
2750
2752
2753 /* Wait for registration serializers to get destroyed. */
2754 ast_debug(2, "Waiting for registration transactions to complete for unload.\n");
2756 if (remaining) {
2757 /*
2758 * NOTE: We probably have a sip_outbound_registration_client_state
2759 * ref leak if the remaining count cannot reach zero after a few
2760 * minutes of trying to unload.
2761 */
2762 ast_log(LOG_WARNING, "Unload incomplete. Could not stop %d outbound registrations. Try again later.\n",
2763 remaining);
2764 return -1;
2765 }
2766
2767 ast_debug(2, "Successful shutdown.\n");
2768
2771
2772 return 0;
2773}
2774
2775static int load_module(void)
2776{
2777 struct ao2_container *new_states;
2778
2780 if (!shutdown_group) {
2782 }
2783
2784 /* Create outbound registration states container. */
2787 if (!new_states) {
2788 ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
2789 unload_module();
2791 }
2793 ao2_ref(new_states, -1);
2794
2795 /*
2796 * Register sorcery object descriptions.
2797 */
2798 ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_registration");
2799 ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
2800
2802 unload_module();
2804 }
2805
2806 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
2808 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
2809 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
2810 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_header_params", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_header_params));
2811 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
2812 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
2813 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
2814 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_random_initial_delay", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_random_initial_delay));
2815 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
2816 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));
2817 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "fatal_retry_interval", "0", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, fatal_retry_interval));
2819 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));
2821 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
2822 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_outbound", "no", OPT_YESNO_T, 1, FLDSET(struct sip_outbound_registration, support_outbound));
2825 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));
2826 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));
2827 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, user_agent));
2828
2829 /*
2830 * Register sorcery observers.
2831 */
2836 || ast_sorcery_observer_add(ast_sip_get_sorcery(), "registration",
2838 ast_log(LOG_ERROR, "Unable to register observers.\n");
2839 unload_module();
2841 }
2842
2843 /* Register how this module identifies endpoints. */
2845
2846 /* Register CLI commands. */
2848 if (!cli_formatter) {
2849 ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
2850 unload_module();
2852 }
2853 cli_formatter->name = "registration";
2862
2863 /* Register AMI actions. */
2867
2868 /* Clear any previous statsd gauges in case we weren't shutdown cleanly */
2869 ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GAUGE, 0);
2870 ast_statsd_log("PJSIP.registrations.state.Registered", AST_STATSD_GAUGE, 0);
2871 ast_statsd_log("PJSIP.registrations.state.Unregistered", AST_STATSD_GAUGE, 0);
2872 ast_statsd_log("PJSIP.registrations.state.Rejected", AST_STATSD_GAUGE, 0);
2873
2874 /* Load configuration objects */
2876
2881
2883}
2884
2885static int reload_module(void)
2886{
2888 return 0;
2889}
2890
2891AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
2892 .support_level = AST_MODULE_SUPPORT_CORE,
2893 .load = load_module,
2895 .unload = unload_module,
2896 .load_pri = AST_MODPRI_APP_DEPEND,
2897 .requires = "res_pjsip",
2898 .optional_modules = "res_statsd",
jack_status_t status
Definition: app_jack.c:146
const char * str
Definition: app_jack.c:147
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
int() ao2_callback_fn(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1226
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
static int tmp()
Definition: bt_open.c:389
enum cc_state state
Definition: ccss.c:393
static PGresult * result
Definition: cel_pgsql.c:84
static struct registrations registrations
static int max_retries
Definition: chan_iax2.c:332
static const char type[]
Definition: chan_ooh323.c:109
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
short word
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_YESNO_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define abs(x)
Definition: f2c.h:195
static const char name[]
Definition: format_mp3.c:68
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:2011
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1969
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:2047
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2001
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1630
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2055
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1890
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7608
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
struct ast_taskprocessor * ast_sip_create_serializer_group(const char *name, struct ast_serializer_shutdown_group *shutdown_group)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2089
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:2165
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:2179
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_DEBUG
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
Definition: json.c:567
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
#define EVENT_FLAG_REPORTING
Definition: manager.h:84
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_APP_DEPEND
Definition: module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
def info(msg)
Core PBX routines and definitions.
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
static char url[512]
static int reload(void)
struct stasis_forward * sub
Definition: res_corosync.c:240
struct ao2_container * container
Definition: res_fax.c:501
struct pjsip_param * ast_sip_pjsip_uri_get_other_param(pjsip_uri *uri, const pj_str_t *param_str)
Find an 'other' SIP/SIPS URI parameter by name.
Definition: res_pjsip.c:3511
void ast_sip_header_to_security_mechanism(const pjsip_generic_string_hdr *hdr, struct ast_sip_security_mechanism_vector *security_mechanisms)
Append to security mechanism vector from SIP header.
int ast_sip_set_security_negotiation(enum ast_sip_security_negotiation *security_negotiation, const char *val)
Set the security negotiation based on a given string.
void ast_sip_security_mechanisms_vector_copy(struct ast_sip_security_mechanism_vector *dst, const struct ast_sip_security_mechanism_vector *src)
Duplicate a security mechanism.
int ast_sip_transport_state_set_transport(const char *transport_name, pjsip_transport *transport)
Sets the PJSIP transport on a child transport.
void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
Clean up retrieved auth structures from memory.
int ast_sip_format_auths_ami(const struct ast_sip_auth_vector *auths, struct ast_sip_ami *ami)
Format auth details for AMI.
Definition: config_auth.c:195
int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, pjsip_tx_data *tdata, pjsip_tx_data **new_request)
Create a response to an authentication challenge.
Definition: res_pjsip.c:214
int ast_sip_auths_to_str(const struct ast_sip_auth_vector *auths, char **buf)
Converts an auths array to a string of comma separated values.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Register a SIP endpoint identifier.
Definition: res_pjsip.c:310
#define AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(_transport, _dest)
Fill a buffer with a pjsip transport's remote ip address and port.
Definition: res_pjsip.h:90
int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
Retrieve relevant SIP auth structures from sorcery.
void ast_sip_service_route_vector_destroy(struct ast_sip_service_route_vector *service_routes)
Destroy a vector of service routes.
void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Unregister a SIP endpoint identifier.
Definition: res_pjsip.c:315
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
void ast_sip_security_mechanisms_vector_destroy(struct ast_sip_security_mechanism_vector *security_mechanisms)
Free contents of a security mechanism vector.
void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a transport shutdown monitor from all reliable transports.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches)
Register a reliable transport shutdown monitor callback replacing any duplicate.
int ast_sip_security_mechanisms_to_str(const struct ast_sip_security_mechanism_vector *security_mechanisms, int add_qvalue, char **buf)
Writes the security mechanisms of an endpoint into a buffer as a string and returns the buffer.
#define IP6ADDR_COLON_PORT_BUFLEN
Definition: res_pjsip.h:82
void ast_sip_tpselector_unref(pjsip_tpselector *selector)
Unreference a pjsip_tpselector.
Definition: res_pjsip.c:923
struct ast_sip_service_route_vector * ast_sip_service_route_vector_alloc(void)
Allocate a vector of service routes.
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
@ AST_SIP_AUTH_TYPE_GOOGLE_OAUTH
Definition: res_pjsip.h:569
ast_transport_monitor_reg
Definition: res_pjsip.h:3934
struct ao2_container * ast_sip_location_retrieve_contacts_from_aor_list(const char *aor_list)
Retrieve all contacts from a list of AORs.
Definition: location.c:335
void ast_sip_remove_headers_by_name_and_value(pjsip_msg *msg, const pj_str_t *hdr_name, const char *value)
Removes all headers of a specific name and value from a pjsip_msg.
void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *vector)
Free contents of an auth vector.
ast_sip_security_negotiation
The kind of security negotiation.
Definition: res_pjsip.h:350
@ AST_SIP_SECURITY_NEG_MEDIASEC
Definition: res_pjsip.h:354
@ AST_SIP_SECURITY_NEG_NONE
Definition: res_pjsip.h:352
int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip_tpselector *selector)
Sets pjsip_tpselector from ast_sip_transport.
Definition: res_pjsip.c:893
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
struct ast_sip_contact_status * ast_sip_get_contact_status(const struct ast_sip_contact *contact)
Retrieve the current status for a contact.
int ast_sip_security_mechanism_vector_init(struct ast_sip_security_mechanism_vector *security_mechanism, const char *value)
Initialize security mechanism vector from string of security mechanisms.
int ast_sip_auth_vector_init(struct ast_sip_auth_vector *vector, const char *auth_names)
Initialize an auth vector with the configured values.
void ast_sip_transport_monitor_unregister_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
int ast_sip_add_security_headers(struct ast_sip_security_mechanism_vector *security_mechanisms, const char *header_name, int add_qval, pjsip_tx_data *tdata)
Add security headers to transmission data.
int ast_sip_transport_state_set_preferred_identity(const char *transport_name, const char *identity)
Sets the P-Preferred-Identity on a child transport.
int ast_sip_failover_request(pjsip_tx_data *tdata)
Set a request to use the next value in the list of resolved addresses.
Definition: res_pjsip.c:1816
int ast_sip_transport_state_set_service_routes(const char *transport_name, struct ast_sip_service_route_vector *service_routes)
Sets the service routes on a child transport.
int ast_sip_unregister_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Unregisters a CLI formatter.
Definition: pjsip_cli.c:326
int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
Prints a sorcery object's ast_variable list.
Definition: pjsip_cli.c:36
char * ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pjsip_cli.c:109
int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Registers a CLI formatter.
Definition: pjsip_cli.c:310
static struct ao2_container * new_states
Used on [re]loads to hold new state data.
static int ami_show_outbound_registrations(struct mansession *s, const struct message *m)
static const struct ast_sorcery_instance_observer observer_callbacks_registrations
static int sip_outbound_registration_regc_alloc(void *data)
Helper function that allocates a pjsip registration client and configures it.
static void save_response_fields_to_transport(struct registration_response *response)
static void * sip_outbound_registration_alloc(const char *name)
Allocator function for registration information.
#define REREGISTER_BUFFER_TIME
Amount of buffer time (in seconds) before expiration that we re-register at.
static void unregister_all(void)
#define LINE_PARAMETER_SIZE
Size of the buffer for creating a unique string for the line.
static int queue_unregister(struct sip_outbound_registration_state *state)
static void registration_deleted_observer(const void *obj)
static int cli_print_header(void *obj, void *arg, int flags)
static struct ast_serializer_shutdown_group * shutdown_group
static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
static char * cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define REGISTRATION_URI_FIELD_LEN
static int registration_state_cmp(void *obj, void *arg, int flags)
comparator function for state objects
static int handle_registration_response(void *data)
Callback function for handling a response to a registration attempt.
static struct pjsip_param * get_uri_option_line(const void *uri)
static void add_security_headers(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
Adds security negotiation mechanisms of outbound registration client state as Security headers to tda...
static int handle_client_registration(void *data)
Callback function for registering.
#define DEFAULT_STATE_BUCKETS
Default number of state container buckets.
static AO2_GLOBAL_OBJ_STATIC(current_states)
static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
Timer callback function, used just for registrations.
static const struct ast_sorcery_observer registration_observer
static int queue_register(struct sip_outbound_registration_state *state)
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, const char *line, const char *header_params)
Helper function which populates a pj_str_t with a contact header.
static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
#define MAX_UNLOAD_TIMEOUT_TIME
static void registration_transport_monitor_setup(const char *transport_key, const char *registration_name)
static int ami_register(struct mansession *s, const struct message *m)
static pj_str_t PATH_NAME
static int contact_has_security_mechanisms(void *obj, void *arg, int flags)
static int ami_unregister(struct mansession *s, const struct message *m)
static void registration_transport_shutdown_cb(void *obj)
static void sip_outbound_registration_state_destroy(void *obj)
Destructor function for registration state.
static const char * fetch_google_access_token(const struct ast_sip_auth *auth)
Get google oauth2 access token using refresh token.
static int contact_add_security_headers_to_status(void *obj, void *arg, int flags)
static int security_negotiation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static struct sip_outbound_registration_state * get_state(const char *id)
static int security_mechanisms_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static void registration_response_destroy(void *obj)
Registration response structure destructor.
static struct ast_sip_endpoint * line_identify(pjsip_rx_data *rdata)
Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing regist...
static void sip_outbound_registration_client_state_destroy(void *obj)
Destructor function for client registration state.
static int reload_module(void)
static int reregister_immediately_cb(void *obj)
static int security_mechanism_to_str(const void *obj, const intptr_t *args, char **buf)
static int add_to_supported_header(pjsip_tx_data *tdata, pj_str_t *name)
Helper function to add string to Supported header.
static struct sip_outbound_registration_state * sip_outbound_registration_state_alloc(struct sip_outbound_registration *registration)
Allocator function for registration state.
static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
static int sip_outbound_registration_is_temporal(unsigned int code, struct sip_outbound_registration_client_state *client_state)
Helper function which determines if a response code is temporal or not.
static int handle_client_state_destruction(void *data)
Callback function for unregistering (potentially) and destroying state.
static void auth_observer(const char *type)
static const char * sip_outbound_registration_status_str(enum sip_outbound_registration_status state)
static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
Apply function which finds or allocates a state structure.
static void update_client_state_status(struct sip_outbound_registration_client_state *client_state, enum sip_outbound_registration_status status)
static void * cli_retrieve_by_id(const char *id)
static const struct ast_sorcery_observer observer_callbacks_auth
static pj_status_t registration_client_send(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
Helper function which sends a message and cleans up, if needed, on failure.
static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
static void reregister_all(void)
static char * cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_sip_endpoint_identifier line_identifier
static int unregister_task(void *obj)
static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
static struct ast_threadstorage register_callback_invoked
static struct ao2_container * cli_get_container(const char *regex)
static char * cli_complete_registration(const char *line, const char *word, int pos, int state)
static void sip_outbound_registration_destroy(void *obj)
Destructor function for registration information.
static const char * security_negotiation_map[]
static pj_str_t OUTBOUND_NAME
static struct stasis_subscription * network_change_sub
static struct ao2_container * get_registrations(void)
static int load_module(void)
static int cli_print_body(void *obj, void *arg, int flags)
static void schedule_retry(struct registration_response *response, unsigned int interval, const char *server_uri, const char *client_uri)
static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
Helper function which sets up the timer to re-register in a specific amount of time.
sip_outbound_registration_status
Various states that an outbound registration may be in.
@ SIP_REGISTRATION_REGISTERED
Registered, yay!
@ SIP_REGISTRATION_REJECTED_PERMANENT
Registration was rejected, permanently.
@ SIP_REGISTRATION_STOPPED
Registration has been stopped.
@ SIP_REGISTRATION_STOPPING
Registration is stopping.
@ SIP_REGISTRATION_UNREGISTERED
Currently unregistered.
@ SIP_REGISTRATION_REJECTED_TEMPORARY
Registration was rejected, but response was temporal.
static int security_negotiation_to_str(const void *obj, const intptr_t *args, char **buf)
static char * my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int unload_module(void)
static int line_identify_relationship(void *obj, void *arg, int flags)
Callback function for matching an outbound registration based on line.
static int set_outbound_initial_authentication_credentials(pjsip_regc *regc, const struct ast_sip_auth_vector *auth_vector)
static struct ast_cli_entry cli_outbound_registration[]
static struct ast_sip_cli_formatter_entry * cli_formatter
static int check_state(void *obj, void *arg, int flags)
static int sip_outbound_registration_perform(void *data)
Helper function which performs a single registration.
static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
Callback function for outbound registration client.
static int registration_state_hash(const void *obj, const int flags)
hashing function for state objects
static int monitor_matcher(void *a, void *b)
static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
Helper function which cancels the timer on a client.
static void registration_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
static int ami_outbound_registration_task(void *obj)
static int add_configured_supported_headers(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
Helper function to add configured supported headers.
static struct ast_sorcery * sorcery
int ast_sip_validate_uri_length(const char *uri)
Definition: location.c:528
#define NULL
Definition: resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition: sorcery.c:2423
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1137
void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Remove an observer from a sorcery instance.
Definition: sorcery.c:537
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition: sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition: sorcery.h:123
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
struct ao2_container * ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
Retrieve multiple objects using a regular expression on their id.
Definition: sorcery.c:1954
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition: sorcery.c:2391
void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to load persistent objects.
Definition: sorcery.c:1393
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
Definition: sorcery.h:1005
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
int ast_sorcery_object_unregister(struct ast_sorcery *sorcery, const char *type)
Unregister an object type.
Definition: sorcery.c:1061
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2464
#define ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:455
int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
Create a changeset given two object sets.
Definition: sorcery.c:1663
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition: sorcery.c:2440
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
Definition: sorcery.c:1442
int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Add an observer to a sorcery instance.
Definition: sorcery.c:520
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1897
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1024
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1078
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1135
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
void ast_system_publish_registry(const char *channeltype, const char *username, const char *domain, const char *status, const char *cause)
Publish a channel driver outgoing registration message.
struct stasis_topic * ast_system_topic(void)
A Stasis Message Bus API topic which publishes messages regarding system changes.
struct stasis_message_type * ast_network_change_type(void)
A stasis_message_type for network changes.
void ast_statsd_log_string_va(const char *metric_name, const char *metric_type, const char *value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition: res_statsd.c:186
#define AST_STATSD_GAUGE
Support for publishing to a statsd server.
Definition: statsd.h:32
void ast_statsd_log_string(const char *metric_name, const char *metric_type, const char *value, double sample_rate)
Send a stat to the configured statsd server.
Definition: res_statsd.c:117
void ast_statsd_log(const char *metric_name, const char *metric_type, intmax_t value)
Send a stat to the configured statsd server.
Definition: res_statsd.c:232
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
Definition: strings.c:226
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
JSON parsing error information.
Definition: json.h:887
Abstract JSON element (object, array, string, int, ...).
AMI variable container.
Definition: res_pjsip.h:3046
struct mansession * s
Definition: res_pjsip.h:3048
const struct message * m
Definition: res_pjsip.h:3050
const ast_string_field oauth_clientid
Definition: res_pjsip.h:594
const ast_string_field oauth_secret
Definition: res_pjsip.h:594
const ast_string_field realm
Definition: res_pjsip.h:594
const ast_string_field auth_user
Definition: res_pjsip.h:594
const ast_string_field refresh_token
Definition: res_pjsip.h:594
const ast_string_field auth_pass
Definition: res_pjsip.h:594
CLI Formatter Context passed to all formatters.
Definition: res_pjsip_cli.h:34
CLI Formatter Registry Entry.
Definition: res_pjsip_cli.h:52
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Definition: res_pjsip_cli.h:66
ao2_callback_fn * print_header
Definition: res_pjsip_cli.h:60
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
const char * name
Definition: res_pjsip_cli.h:58
ao2_callback_fn * print_body
Definition: res_pjsip_cli.h:62
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
A contact's status.
Definition: res_pjsip.h:448
struct ast_sip_security_mechanism_vector security_mechanisms
Definition: res_pjsip.h:463
Contact associated with an address of record.
Definition: res_pjsip.h:389
An entity responsible for identifying the source of a SIP message.
Definition: res_pjsip.h:1289
struct ast_sip_endpoint *(* identify_endpoint)(pjsip_rx_data *rdata)
Callback used to identify the source of a message. See ast_sip_identify_endpoint for more details.
Definition: res_pjsip.h:1294
An entity with which Asterisk communicates.
Definition: res_pjsip.h:958
const ast_string_field aors
Definition: res_pjsip.h:987
Interface for the sorcery instance observer.
Definition: sorcery.h:237
void(* object_type_loaded)(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
Callback after any object_type is loaded/reloaded.
Definition: sorcery.h:260
Interface for a sorcery object type observer.
Definition: sorcery.h:332
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
Definition: sorcery.h:343
void(* deleted)(const void *object)
Callback for when an object is deleted.
Definition: sorcery.h:340
Full structure for sorcery.
Definition: sorcery.c:230
Support for dynamic strings.
Definition: strings.h:623
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
Structure for variables, used for configurations and for channel variables.
Definition: search.h:40
struct header * next
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:326
Structure for registration response.
struct sip_outbound_registration_client_state * client_state
Outbound registration client state.
char transport_key[IP6ADDR_COLON_PORT_BUFLEN]
Key for the reliable transport in use.
pjsip_rx_data * rdata
The response message.
int code
Response code for the registration attempt.
int expiration
Expiration time for registration.
pjsip_tx_data * old_request
Request for which the response was received.
struct sip_outbound_registration * registration
Outbound registration client state information (persists for lifetime of regc)
struct ast_sip_auth_vector outbound_auths
Configured authentication credentials.
unsigned int auth_rejection_permanent
Treat authentication challenges that we cannot handle as permanent failures.
char * user_agent
The value for the User-Agent header sent in requests.
unsigned int support_outbound
Determines whether SIP Outbound support should be advertised.
unsigned int auth_attempted
Non-zero if we have attempted sending a REGISTER with authentication.
enum ast_sip_security_negotiation security_negotiation
Type of security negotiation to use (RFC 3329).
char line[LINE_PARAMETER_SIZE]
Optional line parameter placed into Contact.
unsigned int support_path
Determines whether SIP Path support should be advertised.
char * transport_name
The name of the transport to be used for the registration.
int last_status_code
Status code of last response if we have tried to register before.
unsigned int registration_expires
Expected time of registration lapse/expiration.
unsigned int retry_interval
Interval at which retries should occur for temporal responses.
unsigned int destroy
Registration should be destroyed after completion of transaction.
struct ast_sip_security_mechanism_vector server_security_mechanisms
Security mechanisms of the peer (RFC 3329).
unsigned int forbidden_retry_interval
Interval at which retries should occur for permanent responses.
struct ast_taskprocessor * serializer
Serializer for stuff and things.
unsigned int max_retries
Maximum number of retries permitted.
unsigned int fatal_retry_interval
Interval at which retries should occur for all permanent responses.
char * registration_name
The name of the registration sorcery object.
pj_timer_entry timer
Timer entry for retrying on temporal responses.
enum sip_outbound_registration_status status
Current state of this registration.
unsigned int retries
Current number of retries.
pjsip_tx_data * last_tdata
Last tdata sent We need the original tdata to resend a request on auth failure or timeout....
pjsip_regc * client
Outbound registration client.
struct ast_sip_security_mechanism_vector security_mechanisms
Client security mechanisms (RFC 3329).
Outbound registration state information (persists for lifetime that registration should exist)
struct sip_outbound_registration_client_state * client_state
Client state information.
struct sip_outbound_registration * registration
Outbound registration configuration object.
Outbound registration information.
struct ast_sip_auth_vector outbound_auths
Configured authentication credentials.
SORCERY_OBJECT(details)
Sorcery object details.
unsigned int auth_rejection_permanent
Treat authentication challenges that we cannot handle as permanent failures.
unsigned int expiration
Requested expiration time.
unsigned int support_outbound
Whether Outbound support is enabled.
enum ast_sip_security_negotiation security_negotiation
Type of security negotiation to use (RFC 3329).
unsigned int support_path
Whether Path support is enabled.
unsigned int max_random_initial_delay
Maximum random initial delay interval for initial registrations.
unsigned int retry_interval
Interval at which retries should occur for temporal responses.
unsigned int forbidden_retry_interval
Interval at which retries should occur for permanent responses.
unsigned int max_retries
Maximum number of retries permitted.
unsigned int fatal_retry_interval
Interval at which retries should occur for all permanent responses.
unsigned int line
Whether to add a line parameter to the outbound Contact or not.
struct ast_sip_security_mechanism_vector security_mechanisms
Client security mechanisms (RFC 3329).
structure to hold users read from users.conf
int value
Definition: syslog.c:37
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:61
const char * args
static char server_uri[512]
static struct test_val b
static struct test_val a
int ast_serializer_shutdown_group_join(struct ast_serializer_shutdown_group *shutdown_group, int timeout)
Wait for the serializers in the group to shutdown with timeout.
Definition: threadpool.c:1241
struct ast_serializer_shutdown_group * ast_serializer_shutdown_group_alloc(void)
Create a serializer group shutdown control object.
Definition: threadpool.c:1229
Definitions to aid in the use of thread local storage.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:86
FILE * out
Definition: utils/frame.c:33
int error(const char *format,...)
Definition: utils/frame.c:999
char * usage
Definition: utils/frame.c:37
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
long int ast_random(void)
Definition: utils.c:2312
#define ARRAY_IN_BOUNDS(v, a)
Checks to see if value is within the bounds of the given array.
Definition: utils.h:687
#define ARRAY_LEN(a)
Definition: utils.h:666
Vector container support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680