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