Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
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/taskpool.h"
40#include "asterisk/statsd.h"
42#include "asterisk/vector.h"
43#include "asterisk/pbx.h"
44
45/*** DOCUMENTATION
46 <configInfo name="res_pjsip_outbound_registration" language="en_US">
47 <synopsis>SIP resource for outbound registrations</synopsis>
48 <description><para>
49 <emphasis>Outbound Registration</emphasis>
50 </para>
51 <para>This module allows <literal>res_pjsip</literal> to register to other SIP servers.</para>
52 </description>
53 <configFile name="pjsip.conf">
54 <configObject name="registration">
55 <since>
56 <version>12.0.0</version>
57 </since>
58 <synopsis>The configuration for outbound registration</synopsis>
59 <description><para>
60 Registration is <emphasis>COMPLETELY</emphasis> separate from the rest of
61 <literal>pjsip.conf</literal>. A minimal configuration consists of
62 setting a <literal>server_uri</literal> and a <literal>client_uri</literal>.
63 </para></description>
64 <configOption name="auth_rejection_permanent" default="yes">
65 <since>
66 <version>12.0.0</version>
67 </since>
68 <synopsis>Determines whether failed authentication challenges are treated
69 as permanent failures.</synopsis>
70 <description><para>If this option is enabled and an authentication challenge fails,
71 registration will not be attempted again until the configuration is reloaded.</para></description>
72 </configOption>
73 <configOption name="client_uri">
74 <since>
75 <version>12.0.0</version>
76 </since>
77 <synopsis>Client SIP URI used when attemping outbound registration</synopsis>
78 <description><para>
79 This is the address-of-record for the outbound registration (i.e. the URI in
80 the To header of the REGISTER).</para>
81 <para>For registration with an ITSP, the client SIP URI may need to consist of
82 an account name or number and the provider's hostname for their registrar, e.g.
83 client_uri=1234567890@example.com. This may differ between providers.</para>
84 <para>For registration to generic registrars, the client SIP URI will depend
85 on networking specifics and configuration of the registrar.
86 </para></description>
87 </configOption>
88 <configOption name="contact_user" default="s">
89 <since>
90 <version>12.0.0</version>
91 </since>
92 <synopsis>Contact User to use in request. If this value is not set, this defaults to 's'</synopsis>
93 </configOption>
94 <configOption name="contact_header_params">
95 <since>
96 <version>17.0.0</version>
97 </since>
98 <synopsis>Header parameters to place in the Contact header</synopsis>
99 </configOption>
100 <configOption name="expiration" default="3600">
101 <since>
102 <version>12.0.0</version>
103 </since>
104 <synopsis>Expiration time for registrations in seconds</synopsis>
105 </configOption>
106 <configOption name="max_retries" default="10">
107 <since>
108 <version>12.0.0</version>
109 </since>
110 <synopsis>Maximum number of registration attempts.</synopsis>
111 <description><para>
112 This sets the maximum number of registration attempts that are made before
113 stopping any further attempts. If set to 0 then upon failure no further attempts
114 are made.
115 </para></description>
116 </configOption>
117 <configOption name="security_negotiation" default="no">
118 <since>
119 <version>21.0.0</version>
120 </since>
121 <synopsis>The kind of security agreement negotiation to use. Currently, only mediasec is supported.</synopsis>
122 <description>
123 <enumlist>
124 <enum name="no" />
125 <enum name="mediasec" />
126 </enumlist>
127 </description>
128 </configOption>
129 <configOption name="security_mechanisms">
130 <since>
131 <version>21.0.0</version>
132 </since>
133 <synopsis>List of security mechanisms supported.</synopsis>
134 <description><para>
135 This is a comma-delimited list of security mechanisms to use. Each security mechanism
136 must be in the form defined by RFC 3329 section 2.2.
137 </para></description>
138 </configOption>
139 <configOption name="outbound_auth" default="">
140 <since>
141 <version>12.2.0</version>
142 </since>
143 <synopsis>Authentication object(s) to be used for outbound registrations.</synopsis>
144 <description><para>
145 This is a comma-delimited list of <replaceable>auth</replaceable>
146 sections defined in <filename>pjsip.conf</filename> used to respond
147 to outbound authentication challenges.</para>
148 <note><para>
149 Using the same auth section for inbound and outbound
150 authentication is not recommended. There is a difference in
151 meaning for an empty realm setting between inbound and outbound
152 authentication uses. See the auth realm description for details.
153 </para></note>
154 </description>
155 </configOption>
156 <configOption name="outbound_proxy" default="">
157 <since>
158 <version>12.0.0</version>
159 </since>
160 <synopsis>Full SIP URI of the outbound proxy used to send registrations</synopsis>
161 </configOption>
162 <configOption name="max_random_initial_delay" default="10">
163 <since>
164 <version>16.27.0</version>
165 <version>18.13.0</version>
166 <version>19.5.0</version>
167 </since>
168 <synopsis>Maximum interval in seconds for which an initial registration may be randomly delayed</synopsis>
169 <description>
170 <para>By default, registrations are randomly delayed by a small amount to prevent
171 too many registrations from being made simultaneously.</para>
172 <para>Depending on your system usage, it may be desirable to set this to a smaller
173 or larger value to have fine grained control over the size of this random delay.</para>
174 </description>
175 </configOption>
176 <configOption name="retry_interval" default="60">
177 <since>
178 <version>12.0.0</version>
179 </since>
180 <synopsis>Interval in seconds between retries if outbound registration is unsuccessful</synopsis>
181 </configOption>
182 <configOption name="forbidden_retry_interval" default="0">
183 <since>
184 <version>11.7.0</version>
185 </since>
186 <synopsis>Interval used when receiving a 403 Forbidden response.</synopsis>
187 <description><para>
188 If a 403 Forbidden is received, chan_pjsip will wait
189 <replaceable>forbidden_retry_interval</replaceable> seconds before
190 attempting registration again. If 0 is specified, chan_pjsip will not
191 retry after receiving a 403 Forbidden response. Setting this to a non-zero
192 value goes against a "SHOULD NOT" in RFC3261, but can be used to work around
193 buggy registrars.
194 </para></description>
195 </configOption>
196 <configOption name="fatal_retry_interval" default="0">
197 <since>
198 <version>13.7.0</version>
199 </since>
200 <synopsis>Interval used when receiving a Fatal response.</synopsis>
201 <description><para>
202 If a fatal response is received, chan_pjsip will wait
203 <replaceable>fatal_retry_interval</replaceable> seconds before
204 attempting registration again. If 0 is specified, chan_pjsip will not
205 retry after receiving a fatal (non-temporary 4xx, 5xx, 6xx) response.
206 Setting this to a non-zero value may go against a "SHOULD NOT" in RFC3261,
207 but can be used to work around buggy registrars.</para>
208 <note><para>if also set the <replaceable>forbidden_retry_interval</replaceable>
209 takes precedence over this one when a 403 is received.
210 Also, if <replaceable>auth_rejection_permanent</replaceable> equals 'yes' then
211 a 401 and 407 become subject to this retry interval.</para></note>
212 </description>
213 </configOption>
214 <configOption name="server_uri">
215 <since>
216 <version>12.0.0</version>
217 </since>
218 <synopsis>SIP URI of the server to register against</synopsis>
219 <description><para>
220 This is the URI at which to find the registrar to send the outbound REGISTER. This URI
221 is used as the request URI of the outbound REGISTER request from Asterisk.</para>
222 <para>For registration with an ITSP, the setting may often be just the domain of
223 the registrar, e.g. sip:sip.example.com.
224 </para></description>
225 </configOption>
226 <configOption name="transport">
227 <since>
228 <version>12.0.0</version>
229 </since>
230 <synopsis>Transport used for outbound authentication</synopsis>
231 <description>
232 <note><para>A <replaceable>transport</replaceable> configured in
233 <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>
234 </description>
235 </configOption>
236 <configOption name="line">
237 <since>
238 <version>13.4.0</version>
239 </since>
240 <synopsis>Whether to add a 'line' parameter to the Contact for inbound call matching</synopsis>
241 <description><para>
242 When enabled this option will cause a 'line' parameter to be added to the Contact
243 header placed into the outgoing registration request. If the remote server sends a call
244 this line parameter will be used to establish a relationship to the outbound registration,
245 ultimately causing the configured endpoint to be used.
246 </para></description>
247 </configOption>
248 <configOption name="endpoint">
249 <since>
250 <version>13.4.0</version>
251 </since>
252 <synopsis>Endpoint to use for incoming related calls</synopsis>
253 <description><para>
254 When line support is enabled this configured endpoint name is used for incoming calls
255 that are related to the outbound registration.
256 </para></description>
257 </configOption>
258 <configOption name="type">
259 <since>
260 <version>12.0.0</version>
261 </since>
262 <synopsis>Must be of type 'registration'.</synopsis>
263 </configOption>
264 <configOption name="support_path">
265 <since>
266 <version>12.1.0</version>
267 </since>
268 <synopsis>Enables advertising SIP Path support for outbound REGISTER requests.</synopsis>
269 <description><para>
270 When this option is enabled, outbound REGISTER requests will advertise
271 support for Path headers so that intervening proxies can add to the Path
272 header as necessary.
273 </para></description>
274 </configOption>
275 <configOption name="support_outbound">
276 <since>
277 <version>17.0.0</version>
278 </since>
279 <synopsis>Enables advertising SIP Outbound support (RFC5626) for outbound REGISTER requests.</synopsis>
280 </configOption>
281 <configOption name="user_agent">
282 <since>
283 <version>21.2.0</version>
284 </since>
285 <synopsis>Overrides the User-Agent header that should be used for outbound REGISTER requests.</synopsis>
286 </configOption>
287 </configObject>
288 </configFile>
289 </configInfo>
290 <manager name="PJSIPUnregister" language="en_US">
291 <since>
292 <version>12.0.0</version>
293 </since>
294 <synopsis>
295 Unregister an outbound registration.
296 </synopsis>
297 <syntax>
298 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
299 <parameter name="Registration" required="true">
300 <para>The outbound registration to unregister or '*all' to unregister them all.</para>
301 </parameter>
302 </syntax>
303 <description>
304 <para>
305 Unregisters the specified (or all) outbound registration(s) and stops future registration attempts.
306 Call PJSIPRegister to start registration and schedule re-registrations according to configuration.
307 </para>
308 </description>
309 </manager>
310 <manager name="PJSIPRegister" language="en_US">
311 <since>
312 <version>13.2.0</version>
313 </since>
314 <synopsis>
315 Register an outbound registration.
316 </synopsis>
317 <syntax>
318 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
319 <parameter name="Registration" required="true">
320 <para>The outbound registration to register or '*all' to register them all.</para>
321 </parameter>
322 </syntax>
323 <description>
324 <para>
325 Unregisters the specified (or all) outbound registration(s) then starts registration and schedules re-registrations
326 according to configuration.
327 </para>
328 </description>
329 </manager>
330 <manager name="PJSIPShowRegistrationsOutbound" language="en_US">
331 <since>
332 <version>12.0.0</version>
333 </since>
334 <synopsis>
335 Lists PJSIP outbound registrations.
336 </synopsis>
337 <syntax />
338 <description>
339 <para>
340 In response <literal>OutboundRegistrationDetail</literal> events showing configuration and status
341 information are raised for each outbound registration object. <literal>AuthDetail</literal>
342 events are raised for each associated auth object as well. Once all events are completed an
343 <literal>OutboundRegistrationDetailComplete</literal> is issued.
344 </para>
345 </description>
346 </manager>
347 <managerEvent language="en_US" name="OutboundRegistrationDetail">
348 <managerEventInstance class="EVENT_FLAG_COMMAND">
349 <since>
350 <version>12.0.0</version>
351 </since>
352 <synopsis>
353 Provides configuration details and status information about an
354 outbound registration.
355 </synopsis>
356 <syntax>
357 <parameter name="ObjectType">
358 <para>The object's type. This will always be 'registration'.</para>
359 </parameter>
360 <parameter name="ObjectName">
361 <para>The name of this object.</para>
362 </parameter>
363 <parameter name="MaxRetries">
364 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='max_retries']/synopsis/node())"/></para>
365 </parameter>
366 <parameter name="ClientUri">
367 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='client_uri']/synopsis/node())"/></para>
368 </parameter>
369 <parameter name="SecurityNegotiation">
370 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='security_negotiation']/synopsis/node())"/></para>
371 </parameter>
372 <parameter name="AuthRejectionPermanent">
373 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='auth_rejection_permanent']/synopsis/node())"/></para>
374 </parameter>
375 <parameter name="ServerUri">
376 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='server_uri']/synopsis/node())"/></para>
377 </parameter>
378 <parameter name="MaxRandomInitialDelay">
379 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='max_random_initial_delay']/synopsis/node())"/></para>
380 </parameter>
381 <parameter name="SupportPath">
382 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='support_path']/synopsis/node())"/></para>
383 </parameter>
384 <parameter name="RetryInterval">
385 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='retry_interval']/synopsis/node())"/></para>
386 </parameter>
387 <parameter name="ContactHeaderParams">
388 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='contact_header_params']/synopsis/node())"/></para>
389 </parameter>
390 <parameter name="Expiration">
391 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='expiration']/synopsis/node())"/></para>
392 </parameter>
393 <parameter name="Transport">
394 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='transport']/synopsis/node())"/></para>
395 </parameter>
396 <parameter name="Line">
397 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='line']/synopsis/node())"/></para>
398 </parameter>
399 <parameter name="ContactUser">
400 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='contact_user']/synopsis/node())"/></para>
401 </parameter>
402 <parameter name="Endpoint">
403 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='endpoint']/synopsis/node())"/></para>
404 </parameter>
405 <parameter name="UserAgent">
406 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='user_agent']/synopsis/node())"/></para>
407 </parameter>
408 <parameter name="ForbiddenRetryInterval">
409 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='forbidden_retry_interval']/synopsis/node())"/></para>
410 </parameter>
411 <parameter name="OutboundAuth">
412 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='outbound_auth']/synopsis/node())"/></para>
413 </parameter>
414 <parameter name="OutboundProxy">
415 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='outbound_proxy']/synopsis/node())"/></para>
416 </parameter>
417 <parameter name="FatalRetryInterval">
418 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='fatal_retry_interval']/synopsis/node())"/></para>
419 </parameter>
420 <parameter name="SupportOutbound">
421 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_outbound_registration']/configFile[@name='pjsip.conf']/configObject[@name='registration']/configOption[@name='support_outbound']/synopsis/node())"/></para>
422 </parameter>
423 <parameter name="Status">
424 <para>The current status of this registration. Will be one of:</para>
425 <enumlist>
426 <enum name="Registered"/>
427 <enum name="Unregistered"/>
428 <enum name="Rejected"/>
429 </enumlist>
430 </parameter>
431 <parameter name="NextReg">
432 <para>The number of seconds until the next registration.</para>
433 </parameter>
434 </syntax>
435 </managerEventInstance>
436 </managerEvent>
437 ***/
438
439/* forward declarations */
440static int set_outbound_initial_authentication_credentials(pjsip_regc *regc,
441 const struct ast_sip_auth_vector *auth_vector);
442
443/*! \brief Some thread local storage used to determine if the running thread invoked the callback */
444AST_THREADSTORAGE(register_callback_invoked);
445
446/*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
447#define REREGISTER_BUFFER_TIME 10
448
449/*! \brief Size of the buffer for creating a unique string for the line */
450#define LINE_PARAMETER_SIZE 8
451
452/*! \brief Various states that an outbound registration may be in */
454 /*! \brief Currently unregistered */
456 /*! \brief Registered, yay! */
458 /*! \brief Registration was rejected, but response was temporal */
460 /*! \brief Registration was rejected, permanently */
462 /*! \brief Registration is stopping. */
464 /*! \brief Registration has been stopped */
466};
467
468/*!
469 * \internal
470 * \brief Convert the internal registration state to an external status string.
471 * \since 13.5.0
472 *
473 * \param state Current outbound registration state.
474 *
475 * \return External registration status string.
476 */
478{
479 const char *str;
480
481 str = "Unregistered";
482 switch (state) {
486 break;
488 str = "Registered";
489 break;
492 str = "Rejected";
493 break;
494 }
495 return str;
496}
497
498/*! \brief Outbound registration information */
500 /*! \brief Sorcery object details */
502 /*! \brief Stringfields */
504 /*! \brief URI for the registrar */
506 /*! \brief URI for the AOR */
508 /*! \brief Optional user for contact header */
510 /*! \brief Optional header parameters for contact */
512 /*! \brief Explicit transport to use for registration */
514 /*! \brief Outbound proxy to use */
516 /*! \brief Endpoint to use for related incoming calls */
518 /*! \brief User-Agent to use when sending the REGISTER */
520 );
521 /*! \brief Requested expiration time */
522 unsigned int expiration;
523 /*! \brief Maximum random initial delay interval for initial registrations */
525 /*! \brief Interval at which retries should occur for temporal responses */
526 unsigned int retry_interval;
527 /*! \brief Interval at which retries should occur for permanent responses */
529 /*! \brief Interval at which retries should occur for all permanent responses */
531 /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
533 /*! \brief Maximum number of retries permitted */
534 unsigned int max_retries;
535 /*! \brief Whether to add a line parameter to the outbound Contact or not */
536 unsigned int line;
537 /*! \brief Type of security negotiation to use (RFC 3329). */
539 /*! \brief Client security mechanisms (RFC 3329). */
541 /*! \brief Configured authentication credentials */
543 /*! \brief Whether Path support is enabled */
544 unsigned int support_path;
545 /*! \brief Whether Outbound support is enabled */
546 unsigned int support_outbound;
547};
548
549/*! \brief Outbound registration client state information (persists for lifetime of regc) */
551 /*! \brief Current state of this registration */
553 /*!
554 * \brief Outbound registration client
555 * \note May only be accessed within the serializer thread
556 * because it might get destroyed and set to NULL for
557 * module unload.
558 */
559 pjsip_regc *client;
560 /*!
561 * \brief Last tdata sent
562 * We need the original tdata to resend a request on auth failure
563 * or timeout. On an auth failure, we use the original tdata
564 * to initialize the new tdata for the authorized response. On a timeout
565 * we need it to skip failed SRV entries if any.
566 */
567 pjsip_tx_data *last_tdata;
568 /*! \brief Timer entry for retrying on temporal responses */
569 pj_timer_entry timer;
570 /*! \brief Optional line parameter placed into Contact */
572 /*! \brief Current number of retries */
573 unsigned int retries;
574 /*! \brief Maximum number of retries permitted */
575 unsigned int max_retries;
576 /*! \brief Interval at which retries should occur for temporal responses */
577 unsigned int retry_interval;
578 /*! \brief Interval at which retries should occur for permanent responses */
580 /*! \brief Interval at which retries should occur for all permanent responses */
582 /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
584 /*! \brief Determines whether SIP Path support should be advertised */
585 unsigned int support_path;
586 /*! \brief Determines whether SIP Outbound support should be advertised */
587 unsigned int support_outbound;
588 /*! \brief Type of security negotiation to use (RFC 3329). */
590 /*! \brief Client security mechanisms (RFC 3329). */
592 /*! \brief Security mechanisms of the peer (RFC 3329). */
594 /*! CSeq number of last sent auth request. */
595 unsigned int auth_cseq;
596 /*! \brief Serializer for stuff and things */
598 /*! \brief Configured authentication credentials */
600 /*! \brief Registration should be destroyed after completion of transaction */
601 unsigned int destroy:1;
602 /*! \brief Non-zero if we have attempted sending a REGISTER with authentication */
603 unsigned int auth_attempted:1;
604 /*! \brief Status code of last response if we have tried to register before */
606 /*! \brief The name of the transport to be used for the registration */
608 /*! \brief The name of the registration sorcery object */
610 /*! \brief Expected time of registration lapse/expiration */
612 /*! \brief The value for the User-Agent header sent in requests */
614};
615
616/*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
618 /*! \brief Outbound registration configuration object */
620 /*! \brief Client state information */
622};
623
624/*! Time needs to be long enough for a transaction to timeout if nothing replies. */
625#define MAX_UNLOAD_TIMEOUT_TIME 35 /* Seconds */
626
627/*! Shutdown group to monitor sip_outbound_registration_client_state serializers. */
629
630/*! \brief Default number of state container buckets */
631#define DEFAULT_STATE_BUCKETS 53
632static AO2_GLOBAL_OBJ_STATIC(current_states);
633
634/*! subscription id for network change events */
636
637/*! \brief hashing function for state objects */
638static int registration_state_hash(const void *obj, const int flags)
639{
640 const struct sip_outbound_registration_state *object;
641 const char *key;
642
643 switch (flags & OBJ_SEARCH_MASK) {
644 case OBJ_SEARCH_KEY:
645 key = obj;
646 break;
648 object = obj;
650 break;
651 default:
652 ast_assert(0);
653 return 0;
654 }
655 return ast_str_hash(key);
656}
657
658/*! \brief comparator function for state objects */
659static int registration_state_cmp(void *obj, void *arg, int flags)
660{
661 const struct sip_outbound_registration_state *object_left = obj;
662 const struct sip_outbound_registration_state *object_right = arg;
663 const char *right_key = arg;
664 int cmp;
665
666 switch (flags & OBJ_SEARCH_MASK) {
668 right_key = ast_sorcery_object_get_id(object_right->registration);
669 /* Fall through */
670 case OBJ_SEARCH_KEY:
671 cmp = strcmp(ast_sorcery_object_get_id(object_left->registration), right_key);
672 break;
674 /* Not supported by container. */
675 ast_assert(0);
676 return 0;
677 default:
678 cmp = 0;
679 break;
680 }
681 if (cmp) {
682 return 0;
683 }
684 return CMP_MATCH;
685}
686
687static struct sip_outbound_registration_state *get_state(const char *id)
688{
690 struct ao2_container *states;
691
692 states = ao2_global_obj_ref(current_states);
693 if (states) {
694 state = ao2_find(states, id, OBJ_SEARCH_KEY);
695 ao2_ref(states, -1);
696 }
697 return state;
698}
699
708
709/*! \brief Callback function for matching an outbound registration based on line */
710static int line_identify_relationship(void *obj, void *arg, int flags)
711{
713 pjsip_param *line = arg;
714
715 return !pj_strcmp2(&line->value, state->client_state->line) ? CMP_MATCH : 0;
716}
717
718static struct pjsip_param *get_uri_option_line(const void *uri)
719{
720 static const pj_str_t LINE_STR = { "line", 4 };
721
722 return ast_sip_pjsip_uri_get_other_param((pjsip_uri *)uri, &LINE_STR);
723}
724
725/*! \brief Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing registration */
726static struct ast_sip_endpoint *line_identify(pjsip_rx_data *rdata)
727{
728 pjsip_param *line;
729 RAII_VAR(struct ao2_container *, states, NULL, ao2_cleanup);
731
732 if (!(line = get_uri_option_line(rdata->msg_info.to->uri))
733 && !(line = get_uri_option_line(rdata->msg_info.msg->line.req.uri))) {
734 return NULL;
735 }
736
737 states = ao2_global_obj_ref(current_states);
738 if (!states) {
739 return NULL;
740 }
741
743 if (!state || ast_strlen_zero(state->registration->endpoint)) {
744 return NULL;
745 }
746
747 ast_debug(3, "Determined relationship to outbound registration '%s' based on line '%s', using configured endpoint '%s'\n",
748 ast_sorcery_object_get_id(state->registration), state->client_state->line, state->registration->endpoint);
749
750 return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", state->registration->endpoint);
751}
752
756
757/*! \brief Helper function which cancels the timer on a client */
759{
760 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
761 &client_state->timer, client_state->timer.id)) {
762 /* The timer was successfully cancelled, drop the refcount of client_state */
763 ao2_ref(client_state, -1);
764 }
765}
766
767static pj_str_t PATH_NAME = { "path", 4 };
768static pj_str_t OUTBOUND_NAME = { "outbound", 8 };
769
770AST_VECTOR(pjsip_generic_string_hdr_vector, pjsip_generic_string_hdr *);
771
772/*!
773 * \internal
774 * \brief Callback function which finds a contact whose contact_status has security mechanisms.
775 *
776 * \param obj Pointer to the ast_sip_contact.
777 * \param arg Pointer-pointer to a contact_status that will be set to the contact_status found by this function.
778 * \param flags Flags used by the ao2_callback function.
779 *
780 * \note The refcount of the found contact_status must be decremented by the caller.
781 */
782static int contact_has_security_mechanisms(void *obj, void *arg, int flags)
783{
784 struct ast_sip_contact *contact = obj;
785 struct ast_sip_contact_status **ret = arg;
786 struct ast_sip_contact_status *contact_status = ast_sip_get_contact_status(contact);
787
788 if (!contact_status) {
789 return 0;
790 }
791 if (!AST_VECTOR_SIZE(&contact_status->security_mechanisms)) {
792 ao2_cleanup(contact_status);
793 return 0;
794 }
795 *ret = contact_status;
796 return CMP_MATCH | CMP_STOP;
797}
798
799static int contact_add_security_headers_to_status(void *obj, void *arg, int flags)
800{
801 struct ast_sip_contact *contact = obj;
802 struct pjsip_generic_string_hdr_vector *header_vector = arg;
803 struct ast_sip_contact_status *contact_status = ast_sip_get_contact_status(contact);
804
805 if (!contact_status) {
806 return 0;
807 }
808 if (AST_VECTOR_SIZE(&contact_status->security_mechanisms)) {
809 goto out;
810 }
811
812 ao2_lock(contact_status);
814 ao2_unlock(contact_status);
815
816out:
817 ao2_cleanup(contact_status);
818 return 0;
819}
820
821/*! \brief Adds security negotiation mechanisms of outbound registration client state as Security headers to tdata. */
823 pjsip_tx_data *tdata)
824{
825 int add_sec_client_header = 0;
826 struct sip_outbound_registration *reg = NULL;
827 struct ast_sip_endpoint *endpt = NULL;
828 struct ao2_container *contact_container;
829 struct ast_sip_contact_status *contact_status = NULL;
830 struct ast_sip_security_mechanism_vector *sec_mechs = NULL;
831 static const pj_str_t security_verify = { "Security-Verify", 15 };
832 static const pj_str_t security_client = { "Security-Client", 15 };
833
835 return;
836 }
837
838 /* Get contact status through registration -> endpoint name -> aor -> contact (if set) */
839 if ((reg = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", client_state->registration_name))
840 && !ast_strlen_zero(reg->endpoint) && (endpt = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", reg->endpoint))
841 && (contact_container = ast_sip_location_retrieve_contacts_from_aor_list(endpt->aors))) {
842 /* Retrieve all contacts associated with aors from this endpoint
843 * and find the first one that has security mechanisms.
844 */
845 ao2_callback(contact_container, OBJ_NODATA, contact_has_security_mechanisms, &contact_status);
846 if (contact_status) {
847 ao2_lock(contact_status);
848 sec_mechs = &contact_status->security_mechanisms;
849 }
850 ao2_cleanup(contact_container);
851 }
852 /* Use client_state->server_security_mechanisms if contact_status does not exist. */
853 if (!contact_status && AST_VECTOR_SIZE(&client_state->server_security_mechanisms)) {
854 sec_mechs = &client_state->server_security_mechanisms;
855 }
856 if (client_state->status == SIP_REGISTRATION_REJECTED_TEMPORARY || client_state->auth_attempted) {
857 if (sec_mechs != NULL && pjsip_msg_find_hdr_by_name(tdata->msg, &security_verify, NULL) == NULL) {
858 ast_sip_add_security_headers(sec_mechs, "Security-Verify", 0, tdata);
859 }
860 if (client_state->last_status_code == 494) {
861 ast_sip_remove_headers_by_name_and_value(tdata->msg, &security_client, NULL);
862 } else {
863 /* necessary if a retry occures */
864 add_sec_client_header = (pjsip_msg_find_hdr_by_name(tdata->msg, &security_client, NULL) == NULL) ? 1 : 0;
865 }
866 } else {
867 ast_sip_add_security_headers(&client_state->security_mechanisms, "Security-Client", 0, tdata);
868 }
869
870 if (add_sec_client_header) {
871 ast_sip_add_security_headers(&client_state->security_mechanisms, "Security-Client", 0, tdata);
872 }
873
874 /* Cleanup */
875 if (contact_status) {
876 ao2_unlock(contact_status);
877 ao2_cleanup(contact_status);
878 }
879 ao2_cleanup(endpt);
880 ao2_cleanup(reg);
881}
882
883/*! \brief Helper function which sends a message and cleans up, if needed, on failure */
885 pjsip_tx_data *tdata)
886{
887 pj_status_t status;
888 int *callback_invoked;
889 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
890
891 callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
892 if (!callback_invoked) {
893 pjsip_tx_data_dec_ref(tdata);
894 return PJ_ENOMEM;
895 }
896 *callback_invoked = 0;
897
898 /* Due to the message going out the callback may now be invoked, so bump the count */
899 ao2_ref(client_state, +1);
900 /*
901 * We also bump tdata in expectation of saving it to client_state->last_tdata.
902 * We have to do it BEFORE pjsip_regc_send because if it succeeds, it decrements
903 * the ref count on its own.
904 */
905 pjsip_tx_data_add_ref(tdata);
906
907 /* Add Security-Verify or Security-Client headers */
908 add_security_headers(client_state, tdata);
909
910 /*
911 * Replace the User-Agent header if a different one should be used
912 */
913 if (!ast_strlen_zero(client_state->user_agent)) {
914 static const pj_str_t user_agent_str = { "User-Agent", 10 };
915 pjsip_generic_string_hdr *default_user_agent_hdr;
916 pjsip_generic_string_hdr *user_agent_hdr;
917 pj_str_t user_agent_val;
918 default_user_agent_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &user_agent_str, NULL);
919 user_agent_val = pj_str(client_state->user_agent);
920 user_agent_hdr = pjsip_generic_string_hdr_create(tdata->pool, &user_agent_str, &user_agent_val);
921 if (!user_agent_hdr) {
922 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);
923 } else {
924 if (default_user_agent_hdr) {
925 pj_list_erase(default_user_agent_hdr);
926 }
927 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)user_agent_hdr);
928 }
929 }
930
931 /*
932 * Set the transport in case transports were reloaded.
933 * When pjproject removes the extraneous error messages produced,
934 * we can check status and only set the transport and resend if there was an error
935 */
937 pjsip_regc_set_transport(client_state->client, &selector);
938 ast_sip_tpselector_unref(&selector);
939
940 status = pjsip_regc_send(client_state->client, tdata);
941
942 /*
943 * If the attempt to send the message failed and the callback was not invoked we need to
944 * drop the references we just added
945 */
946 if ((status != PJ_SUCCESS) && !(*callback_invoked)) {
947 pjsip_tx_data_dec_ref(tdata);
948 ao2_ref(client_state, -1);
949 return status;
950 }
951
952 /*
953 * Decref the old last_data before replacing it.
954 * BTW, it's quite possible that last_data == tdata
955 * if we're trying successive servers in an SRV set.
956 */
957 if (client_state->last_tdata) {
958 pjsip_tx_data_dec_ref(client_state->last_tdata);
959 }
960 client_state->last_tdata = tdata;
961
962 return status;
963}
964
965/*! \brief Helper function to add string to Supported header */
966static int add_to_supported_header(pjsip_tx_data *tdata, pj_str_t *name)
967{
968 pjsip_supported_hdr *hdr;
969 int i;
970
971 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
972 if (!hdr) {
973 /* insert a new Supported header */
974 hdr = pjsip_supported_hdr_create(tdata->pool);
975 if (!hdr) {
976 pjsip_tx_data_dec_ref(tdata);
977 return 0;
978 }
979
980 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
981 }
982
983 /* Don't add the value if it's already there */
984 for (i = 0; i < hdr->count; ++i) {
985 if (pj_stricmp(&hdr->values[i], name) == 0) {
986 return 1;
987 }
988 }
989
990 if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
991 return 0;
992 }
993
994 /* add on to the existing Supported header */
995 pj_strassign(&hdr->values[hdr->count++], name);
996
997 return 1;
998}
999
1000/*! \brief Helper function to add configured supported headers */
1001static int add_configured_supported_headers(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
1002{
1003 if (client_state->support_path) {
1004 if (!add_to_supported_header(tdata, &PATH_NAME)) {
1005 return 0;
1006 }
1007 }
1008
1009 if (client_state->support_outbound) {
1010 if (!add_to_supported_header(tdata, &OUTBOUND_NAME)) {
1011 return 0;
1012 }
1013 }
1014
1015 return 1;
1016}
1017
1018/*! \brief Callback function for registering */
1019static int handle_client_registration(void *data)
1020{
1021 RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
1022 pjsip_tx_data *tdata;
1023
1024 if (set_outbound_initial_authentication_credentials(client_state->client, &client_state->outbound_auths)) {
1025 ast_log(LOG_WARNING, "Failed to set initial authentication credentials\n");
1026 }
1027
1028 if (client_state->status == SIP_REGISTRATION_STOPPED
1029 || pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
1030 return 0;
1031 }
1032
1033 if (DEBUG_ATLEAST(1)) {
1034 pjsip_regc_info info;
1035
1036 pjsip_regc_get_info(client_state->client, &info);
1037 ast_log(LOG_DEBUG, "Outbound REGISTER attempt %u to '%.*s' with client '%.*s'\n",
1038 client_state->retries + 1,
1039 (int) info.server_uri.slen, info.server_uri.ptr,
1040 (int) info.client_uri.slen, info.client_uri.ptr);
1041 }
1042
1043 if (!add_configured_supported_headers(client_state, tdata)) {
1044 ast_log(LOG_WARNING, "Failed to set supported headers\n");
1045 return -1;
1046 }
1047
1048 registration_client_send(client_state, tdata);
1049
1050 return 0;
1051}
1052
1053/*! \brief Timer callback function, used just for registrations */
1054static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
1055{
1056 struct sip_outbound_registration_client_state *client_state = entry->user_data;
1057
1058 entry->id = 0;
1059
1060 /*
1061 * Transfer client_state reference to serializer task so the
1062 * nominal path will not dec the client_state ref in this
1063 * pjproject callback thread.
1064 */
1065 if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
1066 ast_log(LOG_WARNING, "Scheduled outbound registration could not be executed.\n");
1067 ao2_ref(client_state, -1);
1068 }
1069}
1070
1071/*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
1072static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
1073{
1074 pj_time_val delay = { .sec = seconds, };
1075 pjsip_regc_info info;
1076
1077 cancel_registration(client_state);
1078
1079 pjsip_regc_get_info(client_state->client, &info);
1080 ast_debug(1, "Scheduling outbound registration to server '%.*s' from client '%.*s' in %d seconds\n",
1081 (int) info.server_uri.slen, info.server_uri.ptr,
1082 (int) info.client_uri.slen, info.client_uri.ptr,
1083 seconds);
1084
1085 ao2_ref(client_state, +1);
1086 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
1087 ast_log(LOG_WARNING, "Failed to schedule registration to server '%.*s' from client '%.*s'\n",
1088 (int) info.server_uri.slen, info.server_uri.ptr,
1089 (int) info.client_uri.slen, info.client_uri.ptr);
1090 ao2_ref(client_state, -1);
1091 }
1092 client_state->registration_expires = ((int) time(NULL)) + seconds;
1093}
1094
1096{
1097 const char *status_old;
1098 const char *status_new;
1099
1100 if (client_state->status == status) {
1101 /* Status state did not change at all. */
1102 return;
1103 }
1104
1105 status_old = sip_outbound_registration_status_str(client_state->status);
1107 client_state->status = status;
1108
1109 if (!strcmp(status_old, status_new)) {
1110 /*
1111 * The internal status state may have changed but the status
1112 * state we tell the world did not change at all.
1113 */
1114 return;
1115 }
1116
1117 ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
1118 status_old);
1119 ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
1120 status_new);
1121}
1122
1123/*! \brief Callback function for unregistering (potentially) and destroying state */
1125{
1126 struct sip_outbound_registration_client_state *client_state = data;
1127
1128 cancel_registration(client_state);
1129
1130 if (client_state->client) {
1131 pjsip_regc_info info;
1132 pjsip_tx_data *tdata;
1133
1134 pjsip_regc_get_info(client_state->client, &info);
1135
1136 if (info.is_busy == PJ_TRUE) {
1137 /* If a client transaction is in progress we defer until it is complete */
1138 ast_debug(1,
1139 "Registration transaction is busy with server '%.*s' from client '%.*s'.\n",
1140 (int) info.server_uri.slen, info.server_uri.ptr,
1141 (int) info.client_uri.slen, info.client_uri.ptr);
1142 client_state->destroy = 1;
1143 ao2_ref(client_state, -1);
1144 return 0;
1145 }
1146
1147 switch (client_state->status) {
1149 break;
1151 ast_debug(1,
1152 "Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n",
1153 (int) info.server_uri.slen, info.server_uri.ptr,
1154 (int) info.client_uri.slen, info.client_uri.ptr);
1155
1157 client_state->destroy = 1;
1158 if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS
1159 && add_configured_supported_headers(client_state, tdata)
1160 && registration_client_send(client_state, tdata) == PJ_SUCCESS) {
1161 ao2_ref(client_state, -1);
1162 return 0;
1163 }
1164 break;
1169 break;
1170 }
1171
1172 pjsip_regc_destroy(client_state->client);
1173 client_state->client = NULL;
1174 }
1175
1180 ao2_ref(client_state, -1);
1181
1182 return 0;
1183}
1184
1185/*! \brief Structure for registration response */
1187 /*! \brief Response code for the registration attempt */
1188 int code;
1189 /*! \brief Expiration time for registration */
1191 /*! \brief Retry-After value */
1193 /*! \brief Outbound registration client state */
1195 /*! \brief The response message */
1196 pjsip_rx_data *rdata;
1197 /*! \brief Request for which the response was received */
1198 pjsip_tx_data *old_request;
1199 /*! \brief Key for the reliable transport in use */
1201};
1202
1203/*! \brief Registration response structure destructor */
1204static void registration_response_destroy(void *obj)
1205{
1206 struct registration_response *response = obj;
1207
1208 if (response->rdata) {
1209 pjsip_rx_data_free_cloned(response->rdata);
1210 }
1211
1212 if (response->old_request) {
1213 pjsip_tx_data_dec_ref(response->old_request);
1214 }
1215
1216 ao2_cleanup(response->client_state);
1217}
1218
1219/*! \brief Helper function which determines if a response code is temporal or not */
1222{
1223 /* Shamelessly taken from pjsua */
1224 if (code == PJSIP_SC_REQUEST_TIMEOUT ||
1225 code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
1226 code == PJSIP_SC_BAD_GATEWAY ||
1227 code == PJSIP_SC_SERVICE_UNAVAILABLE ||
1228 code == PJSIP_SC_SERVER_TIMEOUT ||
1229 ((code == PJSIP_SC_UNAUTHORIZED ||
1230 code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
1232 PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
1233 return 1;
1234 } else {
1235 return 0;
1236 }
1237}
1238
1239static void schedule_retry(struct registration_response *response, unsigned int interval,
1240 const char *server_uri, const char *client_uri)
1241{
1243 schedule_registration(response->client_state, interval);
1244
1245 if (response->rdata) {
1246 ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
1247 "registration attempt to '%s', retrying in '%u'\n",
1248 response->code, server_uri, client_uri, interval);
1249 } else {
1250 ast_log(LOG_WARNING, "No response received from '%s' on "
1251 "registration attempt to '%s', retrying in '%u'\n",
1252 server_uri, client_uri, interval);
1253 }
1254}
1255
1256static int reregister_immediately_cb(void *obj)
1257{
1259
1260 if (state->client_state->status != SIP_REGISTRATION_REGISTERED) {
1261 ao2_ref(state, -1);
1262 return 0;
1263 }
1264
1265 if (DEBUG_ATLEAST(1)) {
1266 pjsip_regc_info info;
1267
1268 pjsip_regc_get_info(state->client_state->client, &info);
1270 "Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n",
1271 (int) info.server_uri.slen, info.server_uri.ptr,
1272 (int) info.client_uri.slen, info.client_uri.ptr);
1273 }
1274
1275 cancel_registration(state->client_state);
1276
1277 ao2_ref(state->client_state, +1);
1278 handle_client_registration(state->client_state);
1279
1280 ao2_ref(state, -1);
1281 return 0;
1282}
1283
1284/*!
1285 * \internal
1286 * \brief The reliable transport we registered using has shutdown.
1287 * \since 13.18.0
1288 *
1289 * \param obj What is needed to initiate a reregister attempt.
1290 *
1291 * \note Normally executed by the pjsip monitor thread.
1292 */
1294{
1295 const char *registration_name = obj;
1297
1298 state = get_state(registration_name);
1299 if (!state) {
1300 /* Registration no longer exists or shutting down. */
1301 return;
1302 }
1303 if (ast_sip_push_task(state->client_state->serializer, reregister_immediately_cb, state)) {
1304 ao2_ref(state, -1);
1305 }
1306}
1307
1308static int monitor_matcher(void *a, void *b)
1309{
1310 char *ma = a;
1311 char *mb = b;
1312
1313 return strcmp(ma, mb) == 0;
1314}
1315
1316static void registration_transport_monitor_setup(const char *transport_key, const char *registration_name)
1317{
1318 char *monitor;
1319 enum ast_transport_monitor_reg monitor_res;
1320
1321 monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL,
1323 if (!monitor) {
1324 return;
1325 }
1326 strcpy(monitor, registration_name);/* Safe */
1327
1328 /*
1329 * We'll ignore if the transport has already been shutdown before we
1330 * register the monitor. We might get into a message spamming infinite
1331 * loop of registration, shutdown, reregistration...
1332 */
1334 monitor, monitor_matcher))) {
1335 ast_log(LOG_NOTICE, "Failed to register transport monitor for regisration %s: %d\n", registration_name, monitor_res);
1336 }
1337 ao2_ref(monitor, -1);
1338}
1339
1341{
1342 static const pj_str_t associated_uri_str = { "P-Associated-URI", 16 };
1343 static const pj_str_t service_route_str = { "Service-Route", 13 };
1344 pjsip_hdr *header = NULL;
1345 pjsip_msg *msg = response->rdata->msg_info.msg;
1346 struct ast_sip_service_route_vector *service_routes = NULL;
1347
1348 /* If no transport is specified then we can't update any */
1350 return;
1351 }
1352
1353 ast_sip_transport_state_set_transport(response->client_state->transport_name, response->rdata->tp_info.transport);
1354
1355 while ((header = pjsip_msg_find_hdr_by_name(msg, &service_route_str, header ? header->next : NULL))) {
1356 char *service_route;
1357 size_t size;
1358
1359 /* The below code takes the approach that if we can't store all service routes then we
1360 * store none at all. This gives a predictable failure condition instead of storing a
1361 * partial list and having partial route headers.
1362 */
1363 size = pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1;
1364 service_route = ast_malloc(size);
1365 if (!service_route) {
1366 if (service_routes) {
1368 service_routes = NULL;
1369 }
1370 break;
1371 }
1372
1373 ast_copy_pj_str(service_route, &((pjsip_generic_string_hdr*)header)->hvalue, size);
1374
1375 if (!service_routes) {
1376 service_routes = ast_sip_service_route_vector_alloc();
1377 if (!service_routes) {
1378 ast_free(service_route);
1379 break;
1380 }
1381 }
1382
1383 if (AST_VECTOR_APPEND(service_routes, service_route)) {
1384 ast_free(service_route);
1386 service_routes = NULL;
1387 break;
1388 }
1389 }
1390
1391 /* If any service routes were handled then store them on the transport */
1392 if (service_routes) {
1394 }
1395
1396 /* If an associated URI is present in the response we need to use it on any outgoing
1397 * traffic on the transport.
1398 */
1399 header = pjsip_msg_find_hdr_by_name(msg, &associated_uri_str, NULL);
1400 if (header) {
1401 char value[pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1];
1402
1403 ast_copy_pj_str(value, &((pjsip_generic_string_hdr*)header)->hvalue, sizeof(value));
1405 }
1406}
1407
1408
1409/*! \brief Callback function for handling a response to a registration attempt */
1410static int handle_registration_response(void *data)
1411{
1412 struct registration_response *response = data;
1413 pjsip_regc_info info;
1414 char server_uri[PJSIP_MAX_URL_SIZE];
1415 char client_uri[PJSIP_MAX_URL_SIZE];
1416
1417 if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
1418 ao2_ref(response, -1);
1419 return 0;
1420 }
1421
1422 pjsip_regc_get_info(response->client_state->client, &info);
1423 ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
1424 ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
1425 response->client_state->last_status_code = response->code;
1426
1427 ast_debug(1, "Processing REGISTER response %d from server '%s' for client '%s'\n",
1428 response->code, server_uri, client_uri);
1429
1430 if (response->code == 408 || response->code == 503) {
1431 if ((ast_sip_failover_request(response->old_request))) {
1432 int res = registration_client_send(response->client_state, response->old_request);
1433 /* The tdata ref was stolen */
1434 response->old_request = NULL;
1435 if (res == PJ_SUCCESS) {
1436 ao2_ref(response, -1);
1437 return 0;
1438 }
1439 }
1440 } else if ((response->code == 401 || response->code == 407 || response->code == 494)
1441 && (!response->client_state->auth_attempted
1442 || response->rdata->msg_info.cseq->cseq != response->client_state->auth_cseq)) {
1443 int res;
1444 pjsip_cseq_hdr *cseq_hdr;
1445 pjsip_tx_data *tdata;
1446
1448 struct sip_outbound_registration *reg = NULL;
1449 struct ast_sip_endpoint *endpt = NULL;
1450 struct ao2_container *contact_container = NULL;
1451 pjsip_generic_string_hdr *header;
1452 struct pjsip_generic_string_hdr_vector header_vector;
1453 static const pj_str_t security_server = { "Security-Server", 15 };
1454
1455 if ((reg = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration",
1456 response->client_state->registration_name)) && reg->endpoint &&
1457 (endpt = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", reg->endpoint))) {
1458 /* Retrieve all contacts associated with aors from this endpoint (if set). */
1459 contact_container = ast_sip_location_retrieve_contacts_from_aor_list(endpt->aors);
1460 }
1461 /* Add server list of security mechanism to client_state and contact status if exists. */
1462 AST_VECTOR_INIT(&header_vector, 1);
1463 header = pjsip_msg_find_hdr_by_name(response->rdata->msg_info.msg, &security_server, NULL);
1464 for (; header;
1465 header = pjsip_msg_find_hdr_by_name(response->rdata->msg_info.msg, &security_server, header->next)) {
1466 AST_VECTOR_APPEND(&header_vector, header);
1468 }
1469 if (contact_container) {
1470 /* Add server security mechanisms to contact status of all associated contacts to be able to send correct
1471 * Security-Verify headers on subsequent non-REGISTER requests through this outbound registration.
1472 */
1473 ao2_callback(contact_container, OBJ_NODATA, contact_add_security_headers_to_status, &header_vector);
1474 ao2_cleanup(contact_container);
1475 }
1476 AST_VECTOR_FREE(&header_vector);
1477 ao2_cleanup(endpt);
1478 ao2_cleanup(reg);
1479 }
1480
1481 if (response->code == 494) {
1483 response->client_state->retries++;
1484 schedule_registration(response->client_state, 0);
1485 ao2_ref(response, -1);
1486 return 0;
1488 response->rdata, response->old_request, &tdata)) {
1489 response->client_state->auth_attempted = 1;
1490 ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
1491 server_uri, client_uri);
1492 pjsip_tx_data_add_ref(tdata);
1493
1494 res = registration_client_send(response->client_state, tdata);
1495
1496 /* Save the cseq that actually got sent. */
1497 cseq_hdr = (pjsip_cseq_hdr *) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ,
1498 NULL);
1499 response->client_state->auth_cseq = cseq_hdr->cseq;
1500 pjsip_tx_data_dec_ref(tdata);
1501 if (res == PJ_SUCCESS) {
1502 ao2_ref(response, -1);
1503 return 0;
1504 }
1505 } else {
1506 ast_log(LOG_WARNING, "Failed to create authenticated REGISTER request to server '%s' from client '%s'\n",
1507 server_uri, client_uri);
1508 }
1509 /* Otherwise, fall through so the failure is processed appropriately */
1510 }
1511
1512 response->client_state->auth_attempted = 0;
1513
1514 if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
1515 /* Check if this is in regards to registering or unregistering */
1516 if (response->expiration) {
1517 int next_registration_round;
1518
1519 /* If the registration went fine simply reschedule registration for the future */
1520 ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
1522 response->client_state->retries = 0;
1523 next_registration_round = response->expiration - REREGISTER_BUFFER_TIME;
1524 if (next_registration_round < 0) {
1525 /* Re-register immediately. */
1526 next_registration_round = 0;
1527 }
1528 schedule_registration(response->client_state, next_registration_round);
1529
1530 /* See if we should monitor for transport shutdown */
1531 if (PJSIP_TRANSPORT_IS_RELIABLE(response->rdata->tp_info.transport)) {
1533 response->client_state->registration_name);
1534 }
1535 } else {
1536 ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
1538 if (PJSIP_TRANSPORT_IS_RELIABLE(response->rdata->tp_info.transport)) {
1542 }
1543 }
1544
1546 } else if (response->client_state->destroy) {
1547 /* We need to deal with the pending destruction instead. */
1548 } else if (response->retry_after) {
1549 /* If we have been instructed to retry after a period of time, schedule it as such */
1550 schedule_retry(response, response->retry_after, server_uri, client_uri);
1551 } else if (response->client_state->retry_interval
1552 && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
1553 if (response->client_state->retries == response->client_state->max_retries) {
1554 /* If we received enough temporal responses to exceed our maximum give up permanently */
1556 ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
1557 server_uri, client_uri);
1558 } else {
1559 /* On the other hand if we can still try some more do so */
1560 response->client_state->retries++;
1561 schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
1562 }
1563 } else {
1564 if (response->code == 403
1566 && response->client_state->retries < response->client_state->max_retries) {
1567 /* A forbidden response retry interval is configured and there are retries remaining */
1569 response->client_state->retries++;
1571 ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1572 server_uri, client_uri, response->client_state->forbidden_retry_interval);
1573 } else if (response->client_state->fatal_retry_interval
1574 && response->client_state->retries < response->client_state->max_retries) {
1575 /* Some kind of fatal failure response received, so retry according to configured interval */
1577 response->client_state->retries++;
1579 ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1580 response->code, server_uri, client_uri, response->client_state->fatal_retry_interval);
1581 } else {
1582 /* Finally if there's no hope of registering give up */
1584 if (response->rdata) {
1585 ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
1586 response->code, server_uri, client_uri);
1587 } else {
1588 ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
1589 }
1590 }
1591 }
1592
1593 ast_system_publish_registry("PJSIP", client_uri, server_uri,
1595
1596 if (response->client_state->destroy) {
1597 /* We have a pending deferred destruction to complete now. */
1598 ao2_ref(response->client_state, +1);
1600 }
1601
1602 ao2_ref(response, -1);
1603 return 0;
1604}
1605
1606/*! \brief Callback function for outbound registration client */
1607static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
1608{
1609 struct sip_outbound_registration_client_state *client_state = param->token;
1610 struct registration_response *response;
1611 int *callback_invoked;
1612
1613 callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
1614
1615 ast_assert(callback_invoked != NULL);
1617
1618 *callback_invoked = 1;
1619
1620 response = ao2_alloc(sizeof(*response), registration_response_destroy);
1621 if (!response) {
1622 ao2_ref(client_state, -1);
1623 return;
1624 }
1625 response->code = param->code;
1626 response->expiration = param->expiration;
1627 /*
1628 * Transfer client_state reference to response so the
1629 * nominal path will not dec the client_state ref in this
1630 * pjproject callback thread.
1631 */
1632 response->client_state = client_state;
1633
1634 ast_debug(1, "Received REGISTER response %d(%.*s)\n",
1635 param->code, (int) param->reason.slen, param->reason.ptr);
1636
1637 if (param->rdata) {
1638 struct pjsip_retry_after_hdr *retry_after;
1639 pjsip_transaction *tsx;
1640
1641 retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER,
1642 NULL);
1643 response->retry_after = retry_after ? retry_after->ivalue : 0;
1644
1645 /*
1646 * If we got a response from the server, we have to use the tdata
1647 * from the transaction, not the tdata saved when we sent the
1648 * request. If we use the saved tdata, we won't process responses
1649 * like 423 Interval Too Brief correctly and we'll wind up sending
1650 * the bad Expires value again.
1651 */
1652 pjsip_tx_data_dec_ref(client_state->last_tdata);
1653
1654 tsx = pjsip_rdata_get_tsx(param->rdata);
1655 response->old_request = tsx->last_tx;
1656 pjsip_tx_data_add_ref(response->old_request);
1657 pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
1658 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(param->rdata->tp_info.transport,
1659 response->transport_key);
1660
1661 } else {
1662 /* old_request steals the reference */
1663 response->old_request = client_state->last_tdata;
1664 }
1665 client_state->last_tdata = NULL;
1666
1667 /*
1668 * Transfer response reference to serializer task so the
1669 * nominal path will not dec the response ref in this
1670 * pjproject callback thread.
1671 */
1672 if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
1673 ast_log(LOG_WARNING, "Failed to pass incoming registration response to taskpool\n");
1674 ao2_cleanup(response);
1675 }
1676}
1677
1678/*! \brief Destructor function for registration state */
1680{
1682
1683 ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n",
1684 state->registration ? state->registration->server_uri : "",
1685 state->registration ? state->registration->client_uri : "");
1686 ao2_cleanup(state->registration);
1687
1688 if (!state->client_state) {
1689 /* Nothing to do */
1690 } else if (!state->client_state->serializer) {
1691 ao2_ref(state->client_state, -1);
1692 } else if (ast_sip_push_task(state->client_state->serializer,
1693 handle_client_state_destruction, state->client_state)) {
1694 ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to taskpool\n");
1695 ao2_ref(state->client_state, -1);
1696 }
1697}
1698
1699/*! \brief Destructor function for client registration state */
1701{
1702 struct sip_outbound_registration_client_state *client_state = obj;
1703
1704 ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0);
1705 ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
1707
1709 ast_free(client_state->transport_name);
1710 ast_free(client_state->registration_name);
1711 ast_free(client_state->user_agent);
1712 if (client_state->last_tdata) {
1713 pjsip_tx_data_dec_ref(client_state->last_tdata);
1714 }
1715}
1716
1717/*! \brief Allocator function for registration state */
1719{
1721 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1722
1724 if (!state) {
1725 return NULL;
1726 }
1727 state->client_state = ao2_alloc(sizeof(*state->client_state),
1729 if (!state->client_state) {
1731 return NULL;
1732 }
1733
1734 state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
1735 pj_timer_entry_init(&state->client_state->timer, 0, state->client_state,
1737 state->client_state->transport_name = ast_strdup(registration->transport);
1738 state->client_state->registration_name =
1740 state->client_state->user_agent = ast_strdup(registration->user_agent);
1741
1742 ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0);
1743 ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
1744 sip_outbound_registration_status_str(state->client_state->status));
1745
1746 if (!state->client_state->transport_name
1747 || !state->client_state->registration_name) {
1749 return NULL;
1750 }
1751
1752 /* Create name with seq number appended. */
1753 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outreg/%s",
1755
1756 state->client_state->serializer = ast_sip_create_serializer_group(tps_name,
1758 if (!state->client_state->serializer) {
1760 return NULL;
1761 }
1762
1763 state->registration = ao2_bump(registration);
1764 return state;
1765}
1766
1767/*! \brief Destructor function for registration information */
1769{
1770 struct sip_outbound_registration *registration = obj;
1771
1774
1775 ast_string_field_free_memory(registration);
1776}
1777
1778/*! \brief Allocator function for registration information */
1779static void *sip_outbound_registration_alloc(const char *name)
1780{
1781 struct sip_outbound_registration *registration;
1782
1783 registration = ast_sorcery_generic_alloc(sizeof(*registration),
1785 if (!registration || ast_string_field_init(registration, 256)) {
1786 ao2_cleanup(registration);
1787 return NULL;
1788 }
1789
1790 return registration;
1791}
1792
1793/*! \brief Helper function which populates a pj_str_t with a contact header */
1794static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user,
1795 const pj_str_t *target, pjsip_tpselector *selector, const char *line, const char *header_params)
1796{
1797 pj_str_t tmp, local_addr;
1798 pjsip_uri *uri;
1799 pjsip_sip_uri *sip_uri;
1800 pjsip_transport_type_e type;
1801 int local_port;
1802
1803 pj_strdup_with_null(pool, &tmp, target);
1804
1805 if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
1806 (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
1807 return -1;
1808 }
1809
1810 sip_uri = pjsip_uri_get_uri(uri);
1811
1812 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
1813 if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
1814 if (type == PJSIP_TRANSPORT_UNSPECIFIED
1815 || !(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE)) {
1816 type = PJSIP_TRANSPORT_TLS;
1817 }
1818 } else if (!sip_uri->transport_param.slen) {
1819 type = PJSIP_TRANSPORT_UDP;
1820 } else if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
1821 return -1;
1822 }
1823
1824 if (pj_strchr(&sip_uri->host, ':')) {
1825 type |= PJSIP_TRANSPORT_IPV6;
1826 }
1827
1828 if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
1829 pool, type, selector, &local_addr, &local_port) != PJ_SUCCESS) {
1830 return -1;
1831 }
1832
1833 if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
1834 type |= PJSIP_TRANSPORT_IPV6;
1835 }
1836
1837 contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
1838 contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
1839 "<%s:%s@%s%.*s%s:%d%s%s%s%s>%s%s",
1840 ((pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) && PJSIP_URI_SCHEME_IS_SIPS(uri)) ? "sips" : "sip",
1841 user,
1842 (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
1843 (int)local_addr.slen,
1844 local_addr.ptr,
1845 (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
1846 local_port,
1847 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
1848 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "",
1849 !ast_strlen_zero(line) ? ";line=" : "",
1850 S_OR(line, ""),
1851 !ast_strlen_zero(header_params) ? ";" : "",
1852 S_OR(header_params, ""));
1853
1854 return 0;
1855}
1856
1857/*!
1858 * \internal
1859 * \brief Check if a registration can be reused
1860 *
1861 * This checks if the existing outbound registration's configuration differs from a newly-applied
1862 * outbound registration to see if the applied one.
1863 *
1864 * \param existing The pre-existing outbound registration
1865 * \param applied The newly-created registration
1866 */
1868 struct sip_outbound_registration *applied)
1869{
1870 int rc = 1;
1872 struct ast_variable *ve = ast_sorcery_objectset_create(sorcery, existing);
1873 struct ast_variable *va = ast_sorcery_objectset_create(sorcery, applied);
1874 struct ast_variable *vc = NULL;
1875
1876 if (ast_sorcery_changeset_create(ve, va, &vc) || vc != NULL) {
1877 rc = 0;
1878 ast_debug(4, "Registration '%s' changed. Can't re-use.\n", ast_sorcery_object_get_id(existing));
1879 } else {
1880 ast_debug(4, "Registration '%s' didn't change. Can re-use\n", ast_sorcery_object_get_id(existing));
1881 }
1882
1886
1887 return rc;
1888}
1889
1890/*! \brief Get google oauth2 access token using refresh token */
1891static const char *fetch_google_access_token(const struct ast_sip_auth *auth)
1892{
1893 char *cmd = NULL;
1894 const char *token;
1895 const char *url = "https://www.googleapis.com/oauth2/v3/token";
1896 char buf[4096];
1897 int res;
1898 struct ast_json_error error;
1899 struct ast_json *json;
1900
1901 /* set timeout to be shorter than default 180s (also checks func_curl is available) */
1902 if (ast_func_write(NULL, "CURLOPT(conntimeout)", "10")) {
1903 ast_log(LOG_ERROR, "CURL is unavailable. This is required for Google OAuth 2.0 authentication. Please ensure it is loaded.\n");
1904 return NULL;
1905 }
1906
1907 res = ast_asprintf(&cmd,
1908 "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)",
1909 url, auth->oauth_clientid, auth->oauth_secret, auth->refresh_token);
1910 if (res < 0) {
1911 return NULL;
1912 }
1913
1914 ast_debug(2, "Performing Google OAuth 2.0 authentication using command: %s\n", cmd);
1915
1916 buf[0] = '\0';
1917 res = ast_func_read(NULL, cmd, buf, sizeof(buf));
1918 ast_free(cmd);
1919 if (res) {
1920 ast_log(LOG_ERROR, "Could not retrieve Google OAuth 2.0 authentication\n");
1921 return NULL;
1922 }
1923
1924 ast_debug(2, "Google OAuth 2.0 authentication returned: %s\n", buf);
1925
1926 json = ast_json_load_string(buf, &error);
1927 if (!json) {
1928 ast_log(LOG_ERROR, "Could not parse Google OAuth 2.0 authentication: %d(%d) %s: '%s'\n",
1929 error.line, error.column, error.text, buf);
1930 return NULL;
1931 }
1932
1933 token = ast_json_string_get(ast_json_object_get(json, "access_token"));
1934 if (!token) {
1935 ast_log(LOG_ERROR, "Could not find Google OAuth 2.0 access_token in: '%s'\n",
1936 buf);
1937 }
1938 token = ast_strdup(token);
1939 ast_json_unref(json);
1940 return token;
1941}
1942
1943/*!
1944 * \internal
1945 * \brief Set pjsip registration context with any authentication credentials that need to be
1946 * sent in the initial registration request
1947 *
1948 * \param regc The pjsip registration context
1949 * \param auth_vector The vector of configured authentication credentials
1950 */
1952 const struct ast_sip_auth_vector *auth_vector)
1953{
1954 size_t auth_size = AST_VECTOR_SIZE(auth_vector);
1955 struct ast_sip_auth *auths[auth_size];
1956 const char *access_token;
1957 pjsip_cred_info auth_creds[1];
1958 pjsip_auth_clt_pref prefs;
1959 int res = 0;
1960 int idx;
1961
1962 memset(auths, 0, sizeof(auths));
1963 if (ast_sip_retrieve_auths(auth_vector, auths)) {
1964 res = -1;
1965 goto cleanup;
1966 }
1967
1968 for (idx = 0; idx < auth_size; ++idx) {
1969 switch (auths[idx]->type) {
1971 pj_cstr(&auth_creds[0].username, auths[idx]->auth_user);
1972 pj_cstr(&auth_creds[0].scheme, "Bearer");
1973 pj_cstr(&auth_creds[0].realm, auths[idx]->realm);
1974 ast_debug(2, "Obtaining Google OAuth access token\n");
1975 access_token = fetch_google_access_token(auths[idx]);
1976 if (!access_token) {
1977 ast_log(LOG_WARNING, "Obtaining Google OAuth access token failed\n");
1978 access_token = auths[idx]->auth_pass;
1979 res = -1;
1980 }
1981 ast_debug(2, "Setting data to '%s'\n", access_token);
1982
1983 pj_cstr(&auth_creds[0].data, access_token);
1984 auth_creds[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
1985
1986 pjsip_regc_set_credentials(regc, 1, auth_creds);
1987
1988 /* for oauth, send auth without waiting for unauthorized response */
1989 prefs.initial_auth = PJ_TRUE;
1990 pj_cstr(&prefs.algorithm, "oauth");
1991 pjsip_regc_set_prefs(regc, &prefs);
1992
1993 if (access_token != auths[idx]->auth_pass) {
1994 ast_free((char *) access_token);
1995 }
1996 break;
1997 default:
1998 /* other cases handled after receiving auth rejection */
1999 break;
2000 }
2001 }
2002
2003cleanup:
2004 ast_sip_cleanup_auths(auths, auth_size);
2005 return res;
2006}
2007
2008/*! \brief Helper function that allocates a pjsip registration client and configures it */
2010{
2013 ao2_bump(state->registration), ao2_cleanup);
2014 pj_pool_t *pool;
2015 pj_str_t tmp;
2016 pjsip_uri *uri;
2017 pj_str_t server_uri, client_uri, contact_uri;
2018 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
2019
2020 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
2021 if (!pool) {
2022 ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
2024 return -1;
2025 }
2026
2027 pj_strdup2_with_null(pool, &tmp, registration->server_uri);
2028 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
2029 if (!uri) {
2030 ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
2032 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
2033 return -1;
2034 }
2035
2036 pj_strdup2_with_null(pool, &tmp, registration->client_uri);
2037 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
2038 if (!uri) {
2039 ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
2041 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
2042 return -1;
2043 }
2044
2045 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
2046
2047 ast_assert(state->client_state->client == NULL);
2048 if (pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state,
2050 &state->client_state->client) != PJ_SUCCESS) {
2051 return -1;
2052 }
2053
2055 pjsip_regc_set_transport(state->client_state->client, &selector);
2056
2058 pjsip_route_hdr route_set, *route;
2059 static const pj_str_t ROUTE_HNAME = { "Route", 5 };
2060 pj_str_t tmp;
2061
2062 pj_list_init(&route_set);
2063
2064 pj_strdup2_with_null(pjsip_regc_get_pool(state->client_state->client), &tmp,
2066 route = pjsip_parse_hdr(pjsip_regc_get_pool(state->client_state->client),
2067 &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL);
2068 if (!route) {
2069 ast_sip_tpselector_unref(&selector);
2070 return -1;
2071 }
2072 pj_list_insert_nodes_before(&route_set, route);
2073
2074 pjsip_regc_set_route_set(state->client_state->client, &route_set);
2075 }
2076
2077 if (state->registration->line) {
2078 ast_generate_random_string(state->client_state->line, sizeof(state->client_state->line));
2079 }
2080
2082
2083 if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client),
2084 &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
2085 state->client_state->line, registration->contact_header_params)) {
2086 ast_sip_tpselector_unref(&selector);
2087 return -1;
2088 }
2089
2090 ast_sip_tpselector_unref(&selector);
2091
2092 pj_cstr(&client_uri, registration->client_uri);
2093 if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri,
2094 &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
2095 return -1;
2096 }
2097
2098 return 0;
2099}
2100
2101/*! \brief Helper function which performs a single registration */
2103{
2105 struct sip_outbound_registration *registration = ao2_bump(state->registration);
2106 size_t i;
2107 int max_delay;
2108
2109 /* Just in case the client state is being reused for this registration, free the auth information */
2110 ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
2111 ast_sip_security_mechanisms_vector_destroy(&state->client_state->security_mechanisms);
2112 ast_sip_security_mechanisms_vector_destroy(&state->client_state->server_security_mechanisms);
2113
2114 AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(&registration->outbound_auths));
2115 for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
2116 char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
2117
2118 if (name && AST_VECTOR_APPEND(&state->client_state->outbound_auths, name)) {
2119 ast_free(name);
2120 }
2121 }
2122 ast_sip_security_mechanisms_vector_copy(&state->client_state->security_mechanisms,
2123 &registration->security_mechanisms);
2124 state->client_state->retry_interval = registration->retry_interval;
2125 state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
2126 state->client_state->fatal_retry_interval = registration->fatal_retry_interval;
2127 state->client_state->max_retries = registration->max_retries;
2128 state->client_state->retries = 0;
2129 state->client_state->support_path = registration->support_path;
2130 state->client_state->support_outbound = registration->support_outbound;
2131 state->client_state->security_negotiation = registration->security_negotiation;
2132 state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
2133 max_delay = registration->max_random_initial_delay;
2134
2135 pjsip_regc_update_expires(state->client_state->client, registration->expiration);
2136
2137 /* n mod 0 is undefined, so don't let that happen */
2138 schedule_registration(state->client_state, (max_delay ? ast_random() % max_delay : 0) + 1);
2139
2140 ao2_ref(registration, -1);
2141 ao2_ref(state, -1);
2142 return 0;
2143}
2144
2145/*! \brief Apply function which finds or allocates a state structure */
2146static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
2147{
2148 RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup);
2151 struct sip_outbound_registration *applied = obj;
2152
2153 if (!states) {
2154 /* Global container has gone. Likely shutting down. */
2155 return -1;
2156 }
2158
2159 ast_debug(4, "Applying configuration to outbound registration '%s'\n", ast_sorcery_object_get_id(applied));
2160
2161 if (ast_strlen_zero(applied->server_uri)) {
2162 ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'\n",
2163 ast_sorcery_object_get_id(applied));
2164 return -1;
2165 } else if (ast_sip_validate_uri_length(applied->server_uri)) {
2166 ast_log(LOG_ERROR, "Server URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
2167 ast_sorcery_object_get_id(applied));
2168 return -1;
2169 } else if (ast_strlen_zero(applied->client_uri)) {
2170 ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
2171 ast_sorcery_object_get_id(applied));
2172 return -1;
2173 } else if (ast_sip_validate_uri_length(applied->client_uri)) {
2174 ast_log(LOG_ERROR, "Client URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
2175 ast_sorcery_object_get_id(applied));
2176 return -1;
2177 } else if (applied->line && ast_strlen_zero(applied->endpoint)) {
2178 ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
2179 ast_sorcery_object_get_id(applied));
2180 return -1;
2181 } else if (!ast_strlen_zero(applied->endpoint) && !applied->line) {
2182 ast_log(LOG_ERROR, "An endpoint has been specified on outbound registration '%s' without enabling line support\n",
2183 ast_sorcery_object_get_id(applied));
2184 return -1;
2185 }
2186
2187 if (state && can_reuse_registration(state->registration, applied)) {
2188 ast_debug(4,
2189 "No change between old configuration and new configuration on outbound registration '%s'. Using previous state\n",
2190 ast_sorcery_object_get_id(applied));
2191
2192 /*
2193 * This is OK to replace without relinking the state in the
2194 * current_states container since state->registration and
2195 * applied have the same key.
2196 */
2197 ao2_lock(states);
2198 ao2_replace(state->registration, applied);
2199 ao2_unlock(states);
2200 return 0;
2201 }
2202
2203 if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
2204 return -1;
2205 }
2206
2207 if (ast_sip_push_task_wait_serializer(new_state->client_state->serializer,
2209 return -1;
2210 }
2211
2212 if (ast_sip_push_task(new_state->client_state->serializer,
2214 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n",
2215 ast_sorcery_object_get_id(new_state->registration));
2216 ao2_ref(new_state, -1);
2217 return -1;
2218 }
2219
2220 ao2_lock(states);
2221 if (state) {
2222 ao2_unlink(states, state);
2223 }
2224 ao2_link(states, new_state);
2225 ao2_unlock(states);
2226
2227 return 0;
2228}
2229
2230static int security_mechanism_to_str(const void *obj, const intptr_t *args, char **buf)
2231{
2232 const struct sip_outbound_registration *registration = obj;
2233
2235}
2236
2237static const char *security_negotiation_map[] = {
2239 [AST_SIP_SECURITY_NEG_MEDIASEC] = "mediasec",
2240};
2241
2242static int security_negotiation_to_str(const void *obj, const intptr_t *args, char **buf)
2243{
2244 const struct sip_outbound_registration *registration = obj;
2247 }
2248 return 0;
2249}
2250
2251static int security_mechanisms_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2252{
2253 struct sip_outbound_registration *registration = obj;
2254
2255 return ast_sip_security_mechanism_vector_init(&registration->security_mechanisms, var->value);
2256}
2257
2258static int security_negotiation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2259{
2260 struct sip_outbound_registration *registration = obj;
2261
2262 return ast_sip_set_security_negotiation(&registration->security_negotiation, var->value);
2263}
2264
2265static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2266{
2267 struct sip_outbound_registration *registration = obj;
2268
2269 return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
2270}
2271
2272static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
2273{
2274 const struct sip_outbound_registration *registration = obj;
2275
2276 return ast_sip_auths_to_str(&registration->outbound_auths, buf);
2277}
2278
2279static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
2280{
2281 const struct sip_outbound_registration *registration = obj;
2282 int i;
2283 struct ast_variable *head = NULL;
2284
2285 for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
2286 ast_variable_list_append(&head, ast_variable_new("outbound_auth",
2287 AST_VECTOR_GET(&registration->outbound_auths, i), ""));
2288 }
2289
2290 if (head) {
2291 *fields = head;
2292 }
2293
2294 return 0;
2295}
2296
2297static int unregister_task(void *obj)
2298{
2300 struct pjsip_regc *client = state->client_state->client;
2301 pjsip_tx_data *tdata;
2302 pjsip_regc_info info;
2303
2304 pjsip_regc_get_info(client, &info);
2305 ast_debug(1, "Unregistering contacts with server '%s' from client '%s'\n",
2306 state->registration->server_uri, state->registration->client_uri);
2307
2308 cancel_registration(state->client_state);
2309
2310 if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS
2311 && add_configured_supported_headers(state->client_state, tdata)) {
2312 registration_client_send(state->client_state, tdata);
2313 }
2314
2315 ao2_ref(state, -1);
2316 return 0;
2317}
2318
2320{
2321 ao2_ref(state, +1);
2322 if (ast_sip_push_task(state->client_state->serializer, unregister_task, state)) {
2323 ao2_ref(state, -1);
2324 return -1;
2325 }
2326
2327 return 0;
2328}
2329
2331{
2332 ao2_ref(state, +1);
2333 if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) {
2334 ao2_ref(state, -1);
2335 return -1;
2336 }
2337
2338 return 0;
2339}
2340
2341static void unregister_all(void)
2342{
2343 struct ao2_container *states;
2344
2345 states = ao2_global_obj_ref(current_states);
2346 if (!states) {
2347 return;
2348 }
2349
2350 /* Clean out all the states and let sorcery handle recreating the registrations */
2352 ao2_ref(states, -1);
2353}
2354
2355static void reregister_all(void)
2356{
2359}
2360
2361static char *cli_complete_registration(const char *line, const char *word,
2362 int pos, int state)
2363{
2364 char *result = NULL;
2365 int wordlen;
2366 int which = 0;
2367 struct sip_outbound_registration *registration;
2369 struct ao2_iterator i;
2370
2371 if (pos != 3) {
2372 return NULL;
2373 }
2374
2375 wordlen = strlen(word);
2376 if (wordlen == 0 && ++which > state) {
2377 return ast_strdup("*all");
2378 }
2379
2382 if (!registrations) {
2383 return NULL;
2384 }
2385
2387 while ((registration = ao2_iterator_next(&i))) {
2388 const char *name = ast_sorcery_object_get_id(registration);
2389
2390 if (!strncasecmp(word, name, wordlen) && ++which > state) {
2392 }
2393
2394 ao2_ref(registration, -1);
2395 if (result) {
2396 break;
2397 }
2398 }
2400
2402 return result;
2403}
2404
2405static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2406{
2408 const char *registration_name;
2409
2410 switch (cmd) {
2411 case CLI_INIT:
2412 e->command = "pjsip send unregister";
2413 e->usage =
2414 "Usage: pjsip send unregister <registration> | *all\n"
2415 " Unregisters the specified (or all) outbound registration(s) "
2416 "and stops future registration attempts.\n";
2417 return NULL;
2418 case CLI_GENERATE:
2419 return cli_complete_registration(a->line, a->word, a->pos, a->n);
2420 }
2421
2422 if (a->argc != 4) {
2423 return CLI_SHOWUSAGE;
2424 }
2425
2426 registration_name = a->argv[3];
2427
2428 if (strcmp(registration_name, "*all") == 0) {
2430 ast_cli(a->fd, "Unregister all queued\n");
2431 return CLI_SUCCESS;
2432 }
2433
2434 state = get_state(registration_name);
2435 if (!state) {
2436 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
2437 return CLI_FAILURE;
2438 }
2439
2440 if (queue_unregister(state)) {
2441 ast_cli(a->fd, "Failed to queue unregistration\n");
2442 }
2443
2444 ao2_ref(state, -1);
2445 return CLI_SUCCESS;
2446}
2447
2448static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2449{
2451 const char *registration_name;
2452
2453 switch (cmd) {
2454 case CLI_INIT:
2455 e->command = "pjsip send register";
2456 e->usage =
2457 "Usage: pjsip send register <registration> | *all \n"
2458 " Unregisters the specified (or all) outbound "
2459 "registration(s) then starts registration(s) and schedules re-registrations.\n";
2460 return NULL;
2461 case CLI_GENERATE:
2462 return cli_complete_registration(a->line, a->word, a->pos, a->n);
2463 }
2464
2465 if (a->argc != 4) {
2466 return CLI_SHOWUSAGE;
2467 }
2468
2469 registration_name = a->argv[3];
2470
2471 if (strcmp(registration_name, "*all") == 0) {
2473 ast_cli(a->fd, "Re-register all queued\n");
2474 return CLI_SUCCESS;
2475 }
2476
2477 state = get_state(registration_name);
2478 if (!state) {
2479 ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
2480 return CLI_FAILURE;
2481 }
2482
2483 /* We need to serialize the unregister and register so they need
2484 * to be queued as separate tasks.
2485 */
2486 if (queue_unregister(state)) {
2487 ast_cli(a->fd, "Failed to queue unregistration\n");
2488 } else if (queue_register(state)) {
2489 ast_cli(a->fd, "Failed to queue registration\n");
2490 }
2491
2492 ao2_ref(state, -1);
2493 return CLI_SUCCESS;
2494}
2495
2496static int ami_unregister(struct mansession *s, const struct message *m)
2497{
2498 const char *registration_name = astman_get_header(m, "Registration");
2500
2501 if (ast_strlen_zero(registration_name)) {
2502 astman_send_error(s, m, "Registration parameter missing.");
2503 return 0;
2504 }
2505
2506 if (strcmp(registration_name, "*all") == 0) {
2508 astman_send_ack(s, m, "Unregistrations queued.");
2509 return 0;
2510 }
2511
2512 state = get_state(registration_name);
2513 if (!state) {
2514 astman_send_error(s, m, "Unable to retrieve registration entry\n");
2515 return 0;
2516 }
2517
2518 if (queue_unregister(state)) {
2519 astman_send_ack(s, m, "Failed to queue unregistration");
2520 } else {
2521 astman_send_ack(s, m, "Unregistration sent");
2522 }
2523
2524 ao2_ref(state, -1);
2525 return 0;
2526}
2527
2528static int ami_register(struct mansession *s, const struct message *m)
2529{
2530 const char *registration_name = astman_get_header(m, "Registration");
2532
2533 if (ast_strlen_zero(registration_name)) {
2534 astman_send_error(s, m, "Registration parameter missing.");
2535 return 0;
2536 }
2537
2538 if (strcmp(registration_name, "*all") == 0) {
2540 astman_send_ack(s, m, "Reregistrations queued.");
2541 return 0;
2542 }
2543
2544 state = get_state(registration_name);
2545 if (!state) {
2546 astman_send_error(s, m, "Unable to retrieve registration entry\n");
2547 return 0;
2548 }
2549
2550 /* We need to serialize the unregister and register so they need
2551 * to be queued as separate tasks.
2552 */
2553 if (queue_unregister(state)) {
2554 astman_send_ack(s, m, "Failed to queue unregistration");
2555 } else if (queue_register(state)) {
2556 astman_send_ack(s, m, "Failed to queue unregistration");
2557 } else {
2558 astman_send_ack(s, m, "Reregistration sent");
2559 }
2560
2561 ao2_ref(state, -1);
2562 return 0;
2563}
2564
2571
2573{
2574 struct sip_ami_outbound *ami = obj;
2575 struct ast_str *buf;
2577
2578 buf = ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami);
2579 if (!buf) {
2580 return -1;
2581 }
2582
2584
2586 pjsip_regc_info info;
2587
2588 if (state->client_state->status == SIP_REGISTRATION_REGISTERED) {
2589 ++ami->registered;
2590 } else {
2591 ++ami->not_registered;
2592 }
2593
2594 ast_str_append(&buf, 0, "Status: %s\r\n",
2595 sip_outbound_registration_status_str(state->client_state->status));
2596
2597 pjsip_regc_get_info(state->client_state->client, &info);
2598 ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg);
2599 ao2_ref(state, -1);
2600 }
2601
2602 astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
2603 ast_free(buf);
2604
2606}
2607
2608static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
2609{
2610 struct sip_ami_outbound *ami = arg;
2611
2612 ami->registration = obj;
2614}
2615
2617 const struct message *m)
2618{
2619 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2620 struct sip_ami_outbound ami_outbound = { .ami = &ami };
2621 struct ao2_container *regs;
2622
2623 regs = get_registrations();
2624 if (!regs) {
2625 astman_send_error(s, m, "Unable to retrieve "
2626 "outbound registrations\n");
2627 return -1;
2628 }
2629
2630 astman_send_listack(s, m, "Following are Events for each Outbound registration",
2631 "start");
2632
2634
2635 astman_send_list_complete_start(s, m, "OutboundRegistrationDetailComplete",
2636 ami_outbound.registered + ami_outbound.not_registered);
2637 astman_append(s,
2638 "Registered: %d\r\n"
2639 "NotRegistered: %d\r\n",
2640 ami_outbound.registered,
2641 ami_outbound.not_registered);
2643
2644 ao2_ref(regs, -1);
2645 return 0;
2646}
2647
2648static struct ao2_container *cli_get_container(const char *regex)
2649{
2651 struct ao2_container *s_container;
2652
2654 if (!container) {
2655 return NULL;
2656 }
2657
2660 if (!s_container) {
2661 return NULL;
2662 }
2663
2664 if (ao2_container_dup(s_container, container, 0)) {
2665 ao2_ref(s_container, -1);
2666 return NULL;
2667 }
2668
2669 return s_container;
2670}
2671
2673{
2675
2676 return 0;
2677}
2678
2679static void *cli_retrieve_by_id(const char *id)
2680{
2681 struct ao2_container *states;
2682 void *obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
2683
2684 if (!obj) {
2685 /* if the object no longer exists then remove its state */
2686 states = ao2_global_obj_ref(current_states);
2687 if (states) {
2689 ao2_ref(states, -1);
2690 }
2691 }
2692
2693 return obj;
2694}
2695
2696static int cli_print_header(void *obj, void *arg, int flags)
2697{
2698 struct ast_sip_cli_context *context = arg;
2699
2700 ast_assert(context->output_buffer != NULL);
2701
2702 ast_str_append(&context->output_buffer, 0,
2703 " <Registration/ServerURI..............................> <Auth....................> <Status.......>\n");
2704
2705 return 0;
2706}
2707
2708static int cli_print_body(void *obj, void *arg, int flags)
2709{
2710 struct sip_outbound_registration *registration = obj;
2711 struct ast_sip_cli_context *context = arg;
2712 const char *id = ast_sorcery_object_get_id(registration);
2714 int expsecs;
2715#define REGISTRATION_URI_FIELD_LEN 53
2716
2717 ast_assert(context->output_buffer != NULL);
2718 expsecs = state ? state->client_state->registration_expires - ((int) time(NULL)) : 0;
2719
2720 ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-26s %-16s %s%d%s\n",
2721 id,
2722 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2723 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2727 : "n/a",
2728 (state ? sip_outbound_registration_status_str(state->client_state->status) : "Unregistered"),
2729 state ? " (exp. " : "", abs(expsecs), state ? (expsecs < 0 ? "s ago)" : "s)") : "");
2731
2732 if (context->show_details
2733 || (context->show_details_only_level_0 && context->indent_level == 0)) {
2734 ast_str_append(&context->output_buffer, 0, "\n");
2736 }
2737
2738 return 0;
2739}
2740
2741/*
2742 * A function pointer to callback needs to be within the
2743 * module in order to avoid problems with an undefined
2744 * symbol when the module is loaded.
2745 */
2746static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2747{
2748 return ast_sip_cli_traverse_objects(e, cmd, a);
2749}
2750
2752 AST_CLI_DEFINE(cli_unregister, "Unregisters outbound registration target"),
2753 AST_CLI_DEFINE(cli_register, "Registers an outbound registration target"),
2754 AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
2755 .command = "pjsip list registrations",
2756 .usage = "Usage: pjsip list registrations [ like <pattern> ]\n"
2757 " List the configured PJSIP Registrations\n"
2758 " Optional regular expression pattern is used to filter the list.\n"),
2759 AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
2760 .command = "pjsip show registrations",
2761 .usage = "Usage: pjsip show registrations [ like <pattern> ]\n"
2762 " Show the configured PJSIP Registrations\n"
2763 " Optional regular expression pattern is used to filter the list.\n"),
2764 AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
2765 .command = "pjsip show registration",
2766 .usage = "Usage: pjsip show registration <id>\n"
2767 " Show the configured PJSIP Registration\n"),
2768};
2769
2771
2772static void auth_observer(const char *type)
2773{
2774 struct sip_outbound_registration *registration;
2776 struct ao2_container *regs;
2777 const char *registration_id;
2778 struct ao2_iterator i;
2779
2780 ast_debug(4, "Auths updated. Checking for any outbound registrations that are in permanent rejected state so they can be retried\n");
2781
2782 regs = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
2784 if (!regs || ao2_container_count(regs) == 0) {
2785 ao2_cleanup(regs);
2786 return;
2787 }
2788
2789 i = ao2_iterator_init(regs, 0);
2790 for (; (registration = ao2_iterator_next(&i)); ao2_ref(registration, -1)) {
2791 registration_id = ast_sorcery_object_get_id(registration);
2792 state = get_state(registration_id);
2793 if (state && state->client_state->status == SIP_REGISTRATION_REJECTED_PERMANENT) {
2794 ast_debug(4, "Trying outbound registration '%s' again\n", registration_id);
2795
2796 if (ast_sip_push_task(state->client_state->serializer,
2798 ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", registration_id);
2799 ao2_ref(state, -1);
2800 }
2801 }
2803 }
2805 ao2_cleanup(regs);
2806}
2807
2811
2812static int check_state(void *obj, void *arg, int flags)
2813{
2815 struct sip_outbound_registration *registration;
2816
2817 registration = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration",
2818 ast_sorcery_object_get_id(state->registration));
2819 if (!registration) {
2820 /* This is a dead registration */
2821 return CMP_MATCH;
2822 }
2823
2824 ao2_ref(registration, -1);
2825 return 0;
2826}
2827
2828/*!
2829 * \internal
2830 * \brief Observer to purge dead registration states.
2831 *
2832 * \param name Module name owning the sorcery instance.
2833 * \param sorcery Instance being observed.
2834 * \param object_type Name of object being observed.
2835 * \param reloaded Non-zero if the object is being reloaded.
2836 */
2837static void registration_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
2838{
2839 struct ao2_container *states;
2840
2841 if (strcmp(object_type, "registration")) {
2842 /* Not interested */
2843 return;
2844 }
2845
2846 states = ao2_global_obj_ref(current_states);
2847 if (!states) {
2848 /* Global container has gone. Likely shutting down. */
2849 return;
2850 }
2851
2852 /*
2853 * Refresh the current configured registrations. We don't need to hold
2854 * onto the objects, as the apply handler will cause their states to
2855 * be created appropriately.
2856 */
2858
2859 /* Now to purge dead registrations. */
2861 ao2_ref(states, -1);
2862}
2863
2867
2868static void registration_deleted_observer(const void *obj)
2869{
2870 const struct sip_outbound_registration *registration = obj;
2871 struct ao2_container *states;
2872
2873 states = ao2_global_obj_ref(current_states);
2874 if (!states) {
2875 /* Global container has gone. Likely shutting down. */
2876 return;
2877 }
2878
2880
2881 ao2_ref(states, -1);
2882}
2883
2887
2889{
2890 /* This callback is only concerned with network change messages from the system topic. */
2892 return;
2893 }
2894 ast_debug(3, "Received network change event\n");
2895
2897}
2898
2899static int unload_module(void)
2900{
2901 int remaining;
2902
2904
2905 ast_manager_unregister("PJSIPShowRegistrationsOutbound");
2906 ast_manager_unregister("PJSIPUnregister");
2907 ast_manager_unregister("PJSIPRegister");
2908
2912
2914
2917
2919
2920 ao2_global_obj_release(current_states);
2921
2923
2924 /* Wait for registration serializers to get destroyed. */
2925 ast_debug(2, "Waiting for registration transactions to complete for unload.\n");
2927 if (remaining) {
2928 /*
2929 * NOTE: We probably have a sip_outbound_registration_client_state
2930 * ref leak if the remaining count cannot reach zero after a few
2931 * minutes of trying to unload.
2932 */
2933 ast_log(LOG_WARNING, "Unload incomplete. Could not stop %d outbound registrations. Try again later.\n",
2934 remaining);
2935 return -1;
2936 }
2937
2938 ast_debug(2, "Successful shutdown.\n");
2939
2942
2943 return 0;
2944}
2945
2946static int load_module(void)
2947{
2948 struct ao2_container *new_states;
2949
2951 if (!shutdown_group) {
2953 }
2954
2955 /* Create outbound registration states container. */
2958 if (!new_states) {
2959 ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
2960 unload_module();
2962 }
2964 ao2_ref(new_states, -1);
2965
2966 /*
2967 * Register sorcery object descriptions.
2968 */
2969 ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_registration");
2970 ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
2971
2973 unload_module();
2975 }
2976
2977 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
2979 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
2980 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
2981 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));
2982 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
2983 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
2984 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
2985 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));
2986 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
2987 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));
2988 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));
2990 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));
2992 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
2993 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_outbound", "no", OPT_YESNO_T, 1, FLDSET(struct sip_outbound_registration, support_outbound));
2996 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));
2997 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));
2998 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, user_agent));
2999
3000 /*
3001 * Register sorcery observers.
3002 */
3007 || ast_sorcery_observer_add(ast_sip_get_sorcery(), "registration",
3009 ast_log(LOG_ERROR, "Unable to register observers.\n");
3010 unload_module();
3012 }
3013
3014 /* Register how this module identifies endpoints. */
3016
3017 /* Register CLI commands. */
3019 if (!cli_formatter) {
3020 ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
3021 unload_module();
3023 }
3024 cli_formatter->name = "registration";
3033
3034 /* Register AMI actions. */
3038
3039 /* Clear any previous statsd gauges in case we weren't shutdown cleanly */
3040 ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GAUGE, 0);
3041 ast_statsd_log("PJSIP.registrations.state.Registered", AST_STATSD_GAUGE, 0);
3042 ast_statsd_log("PJSIP.registrations.state.Unregistered", AST_STATSD_GAUGE, 0);
3043 ast_statsd_log("PJSIP.registrations.state.Rejected", AST_STATSD_GAUGE, 0);
3044
3045 /* Load configuration objects */
3047
3052
3054}
3055
3056static int reload_module(void)
3057{
3059 return 0;
3060}
3061
3062AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
3063 .support_level = AST_MODULE_SUPPORT_CORE,
3064 .load = load_module,
3066 .unload = unload_module,
3067 .load_pri = AST_MODPRI_APP_DEPEND,
3068 .requires = "res_pjsip",
3069 .optional_modules = "res_statsd",
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
jack_status_t status
Definition app_jack.c:149
const char * str
Definition app_jack.c:150
#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_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
Definition astobj2.h:847
#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 PGresult * result
Definition cel_pgsql.c:84
static int max_retries
Definition chan_iax2.c:356
static const char type[]
static struct ast_sorcery * sorcery
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags, int rdlock)
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#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:2024
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1982
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:2060
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:2014
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1643
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2068
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1903
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7698
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2094
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:2083
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Definition res_pjsip.h:2189
#define ast_sip_push_task_wait_servant(serializer, sip_task, task_data)
Definition res_pjsip.h:2133
#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:1260
#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:192
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
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 struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
static char url[512]
static int reload(void)
struct ao2_container * container
Definition res_fax.c:603
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:3482
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.
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:208
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:514
int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Register a SIP endpoint identifier.
Definition res_pjsip.c:304
#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:91
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:309
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:2172
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:83
void ast_sip_tpselector_unref(pjsip_tpselector *selector)
Unreference a pjsip_tpselector.
Definition res_pjsip.c:917
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:583
ast_transport_monitor_reg
Definition res_pjsip.h:4129
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:351
@ AST_SIP_SECURITY_NEG_MEDIASEC
Definition res_pjsip.h:355
@ AST_SIP_SECURITY_NEG_NONE
Definition res_pjsip.h:353
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:887
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:1810
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 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 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.
int ast_sip_validate_uri_length(const char *uri)
Definition location.c:529
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition res_stasis.c:327
static struct @522 args
#define NULL
Definition resample.c:96
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.
struct ast_serializer_shutdown_group * ast_serializer_shutdown_group_alloc(void)
Create a serializer group shutdown control object.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
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:2487
#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:601
@ 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:1917
#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:2018
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:2455
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:1457
#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:1792
int ast_sorcery_object_unregister(struct ast_sorcery *sorcery, const char *type)
Unregister an object type.
Definition sorcery.c:1125
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition sorcery.c:2528
#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:1727
#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:2504
#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:1506
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:584
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:1961
@ 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:1090
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:1144
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition stasis.c:1201
#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_OPTIONAL_API_NAME() 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:205
#define AST_STATSD_GAUGE
Support for publishing to a statsd server.
Definition statsd.h:32
void AST_OPTIONAL_API_NAME() 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:136
void AST_OPTIONAL_API_NAME() 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:251
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
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
#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 *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
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:3225
struct mansession * s
Definition res_pjsip.h:3227
const struct message * m
Definition res_pjsip.h:3229
const ast_string_field oauth_clientid
Definition res_pjsip.h:681
const ast_string_field oauth_secret
Definition res_pjsip.h:681
const ast_string_field realm
Definition res_pjsip.h:681
const ast_string_field auth_user
Definition res_pjsip.h:681
const ast_string_field refresh_token
Definition res_pjsip.h:681
const ast_string_field auth_pass
Definition res_pjsip.h:681
CLI Formatter Context passed to all formatters.
CLI Formatter Registry Entry.
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
ao2_callback_fn * print_header
void *(* retrieve_by_id)(const char *id)
const char *(* get_id)(const void *obj)
const char * name
ao2_callback_fn * print_body
struct ao2_container *(* get_container)(const char *regex)
A contact's status.
Definition res_pjsip.h:451
struct ast_sip_security_mechanism_vector security_mechanisms
Definition res_pjsip.h:466
Contact associated with an address of record.
Definition res_pjsip.h:390
An entity responsible for identifying the source of a SIP message.
Definition res_pjsip.h:1421
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:1426
An entity with which Asterisk communicates.
Definition res_pjsip.h:1061
const ast_string_field aors
Definition res_pjsip.h:1090
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:231
Support for dynamic strings.
Definition strings.h:623
A ast_taskprocessor structure is a singleton by name.
Structure for variables, used for configurations and for channel variables.
struct header * next
In case you didn't read that giant block of text above the mansession_session struct,...
Definition manager.c:323
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 phoneprov_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).
static char server_uri[512]
static struct test_val b
static struct test_val a
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.
FILE * out
Definition utils/frame.c:33
int error(const char *format,...)
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:981
#define ast_assert(a)
Definition utils.h:779
long int ast_random(void)
Definition utils.c:2348
#define ARRAY_IN_BOUNDS(v, a)
Checks to see if value is within the bounds of the given array.
Definition utils.h:727
#define ARRAY_LEN(a)
Definition utils.h:706
Vector container support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition vector.h:873
#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:691