Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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"
32 #include "asterisk/res_pjsip_cli.h"
33 #include "asterisk/module.h"
34 #include "asterisk/taskprocessor.h"
35 #include "asterisk/cli.h"
36 #include "asterisk/stasis_system.h"
37 #include "asterisk/threadstorage.h"
38 #include "asterisk/threadpool.h"
39 #include "asterisk/statsd.h"
41 #include "asterisk/vector.h"
42 #include "asterisk/pbx.h"
43 
44 /*** DOCUMENTATION
45  <configInfo name="res_pjsip_outbound_registration" language="en_US">
46  <synopsis>SIP resource for outbound registrations</synopsis>
47  <description><para>
48  <emphasis>Outbound Registration</emphasis>
49  </para>
50  <para>This module allows <literal>res_pjsip</literal> to register to other SIP servers.</para>
51  </description>
52  <configFile name="pjsip.conf">
53  <configObject name="registration">
54  <synopsis>The configuration for outbound registration</synopsis>
55  <description><para>
56  Registration is <emphasis>COMPLETELY</emphasis> separate from the rest of
57  <literal>pjsip.conf</literal>. A minimal configuration consists of
58  setting a <literal>server_uri</literal> and a <literal>client_uri</literal>.
59  </para></description>
60  <configOption name="auth_rejection_permanent" default="yes">
61  <synopsis>Determines whether failed authentication challenges are treated
62  as permanent failures.</synopsis>
63  <description><para>If this option is enabled and an authentication challenge fails,
64  registration will not be attempted again until the configuration is reloaded.</para></description>
65  </configOption>
66  <configOption name="client_uri">
67  <synopsis>Client SIP URI used when attemping outbound registration</synopsis>
68  <description><para>
69  This is the address-of-record for the outbound registration (i.e. the URI in
70  the To header of the REGISTER).</para>
71  <para>For registration with an ITSP, the client SIP URI may need to consist of
72  an account name or number and the provider's hostname for their registrar, e.g.
73  client_uri=1234567890@example.com. This may differ between providers.</para>
74  <para>For registration to generic registrars, the client SIP URI will depend
75  on networking specifics and configuration of the registrar.
76  </para></description>
77  </configOption>
78  <configOption name="contact_user">
79  <synopsis>Contact User to use in request</synopsis>
80  </configOption>
81  <configOption name="contact_header_params">
82  <synopsis>Header parameters to place in the Contact header</synopsis>
83  </configOption>
84  <configOption name="expiration" default="3600">
85  <synopsis>Expiration time for registrations in seconds</synopsis>
86  </configOption>
87  <configOption name="max_retries" default="10">
88  <synopsis>Maximum number of registration attempts.</synopsis>
89  <description><para>
90  This sets the maximum number of registration attempts that are made before
91  stopping any further attempts. If set to 0 then upon failure no further attempts
92  are made.
93  </para></description>
94  </configOption>
95  <configOption name="outbound_auth" default="">
96  <synopsis>Authentication object(s) to be used for outbound registrations.</synopsis>
97  <description><para>
98  This is a comma-delimited list of <replaceable>auth</replaceable>
99  sections defined in <filename>pjsip.conf</filename> used to respond
100  to outbound authentication challenges.</para>
101  <note><para>
102  Using the same auth section for inbound and outbound
103  authentication is not recommended. There is a difference in
104  meaning for an empty realm setting between inbound and outbound
105  authentication uses. See the auth realm description for details.
106  </para></note>
107  </description>
108  </configOption>
109  <configOption name="outbound_proxy" default="">
110  <synopsis>Full SIP URI of the outbound proxy used to send registrations</synopsis>
111  </configOption>
112  <configOption name="retry_interval" default="60">
113  <synopsis>Interval in seconds between retries if outbound registration is unsuccessful</synopsis>
114  </configOption>
115  <configOption name="forbidden_retry_interval" default="0">
116  <synopsis>Interval used when receiving a 403 Forbidden response.</synopsis>
117  <description><para>
118  If a 403 Forbidden is received, chan_pjsip will wait
119  <replaceable>forbidden_retry_interval</replaceable> seconds before
120  attempting registration again. If 0 is specified, chan_pjsip will not
121  retry after receiving a 403 Forbidden response. Setting this to a non-zero
122  value goes against a "SHOULD NOT" in RFC3261, but can be used to work around
123  buggy registrars.
124  </para></description>
125  </configOption>
126  <configOption name="fatal_retry_interval" default="0">
127  <synopsis>Interval used when receiving a Fatal response.</synopsis>
128  <description><para>
129  If a fatal response is received, chan_pjsip will wait
130  <replaceable>fatal_retry_interval</replaceable> seconds before
131  attempting registration again. If 0 is specified, chan_pjsip will not
132  retry after receiving a fatal (non-temporary 4xx, 5xx, 6xx) response.
133  Setting this to a non-zero value may go against a "SHOULD NOT" in RFC3261,
134  but can be used to work around buggy registrars.</para>
135  <note><para>if also set the <replaceable>forbidden_retry_interval</replaceable>
136  takes precedence over this one when a 403 is received.
137  Also, if <replaceable>auth_rejection_permanent</replaceable> equals 'yes' then
138  a 401 and 407 become subject to this retry interval.</para></note>
139  </description>
140  </configOption>
141  <configOption name="server_uri">
142  <synopsis>SIP URI of the server to register against</synopsis>
143  <description><para>
144  This is the URI at which to find the registrar to send the outbound REGISTER. This URI
145  is used as the request URI of the outbound REGISTER request from Asterisk.</para>
146  <para>For registration with an ITSP, the setting may often be just the domain of
147  the registrar, e.g. sip:sip.example.com.
148  </para></description>
149  </configOption>
150  <configOption name="transport">
151  <synopsis>Transport used for outbound authentication</synopsis>
152  <description>
153  <note><para>A <replaceable>transport</replaceable> configured in
154  <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>
155  </description>
156  </configOption>
157  <configOption name="line">
158  <synopsis>Whether to add a 'line' parameter to the Contact for inbound call matching</synopsis>
159  <description><para>
160  When enabled this option will cause a 'line' parameter to be added to the Contact
161  header placed into the outgoing registration request. If the remote server sends a call
162  this line parameter will be used to establish a relationship to the outbound registration,
163  ultimately causing the configured endpoint to be used.
164  </para></description>
165  </configOption>
166  <configOption name="endpoint">
167  <synopsis>Endpoint to use for incoming related calls</synopsis>
168  <description><para>
169  When line support is enabled this configured endpoint name is used for incoming calls
170  that are related to the outbound registration.
171  </para></description>
172  </configOption>
173  <configOption name="type">
174  <synopsis>Must be of type 'registration'.</synopsis>
175  </configOption>
176  <configOption name="support_path">
177  <synopsis>Enables advertising SIP Path support for outbound REGISTER requests.</synopsis>
178  <description><para>
179  When this option is enabled, outbound REGISTER requests will advertise
180  support for Path headers so that intervening proxies can add to the Path
181  header as necessary.
182  </para></description>
183  </configOption>
184  <configOption name="support_outbound">
185  <synopsis>Enables advertising SIP Outbound support (RFC5626) for outbound REGISTER requests.</synopsis>
186  </configOption>
187  </configObject>
188  </configFile>
189  </configInfo>
190  <manager name="PJSIPUnregister" language="en_US">
191  <synopsis>
192  Unregister an outbound registration.
193  </synopsis>
194  <syntax>
195  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
196  <parameter name="Registration" required="true">
197  <para>The outbound registration to unregister or '*all' to unregister them all.</para>
198  </parameter>
199  </syntax>
200  <description>
201  <para>
202  Unregisters the specified (or all) outbound registration(s) and stops future registration attempts.
203  Call PJSIPRegister to start registration and schedule re-registrations according to configuration.
204  </para>
205  </description>
206  </manager>
207  <manager name="PJSIPRegister" language="en_US">
208  <synopsis>
209  Register an outbound registration.
210  </synopsis>
211  <syntax>
212  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
213  <parameter name="Registration" required="true">
214  <para>The outbound registration to register or '*all' to register them all.</para>
215  </parameter>
216  </syntax>
217  <description>
218  <para>
219  Unregisters the specified (or all) outbound registration(s) then starts registration and schedules re-registrations
220  according to configuration.
221  </para>
222  </description>
223  </manager>
224  <manager name="PJSIPShowRegistrationsOutbound" language="en_US">
225  <synopsis>
226  Lists PJSIP outbound registrations.
227  </synopsis>
228  <syntax />
229  <description>
230  <para>
231  In response <literal>OutboundRegistrationDetail</literal> events showing configuration and status
232  information are raised for each outbound registration object. <literal>AuthDetail</literal>
233  events are raised for each associated auth object as well. Once all events are completed an
234  <literal>OutboundRegistrationDetailComplete</literal> is issued.
235  </para>
236  </description>
237  </manager>
238  ***/
239 
240 /* forward declarations */
241 static int set_outbound_initial_authentication_credentials(pjsip_regc *regc,
242  const struct ast_sip_auth_vector *auth_vector);
243 
244 /*! \brief Some thread local storage used to determine if the running thread invoked the callback */
246 
247 /*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
248 #define REREGISTER_BUFFER_TIME 10
249 
250 /*! \brief Size of the buffer for creating a unique string for the line */
251 #define LINE_PARAMETER_SIZE 8
252 
253 /*! \brief Various states that an outbound registration may be in */
255  /*! \brief Currently unregistered */
257  /*! \brief Registered, yay! */
259  /*! \brief Registration was rejected, but response was temporal */
261  /*! \brief Registration was rejected, permanently */
263  /*! \brief Registration is stopping. */
265  /*! \brief Registration has been stopped */
267 };
268 
269 /*!
270  * \internal
271  * \brief Convert the internal registration state to an external status string.
272  * \since 13.5.0
273  *
274  * \param state Current outbound registration state.
275  *
276  * \return External registration status string.
277  */
279 {
280  const char *str;
281 
282  str = "Unregistered";
283  switch (state) {
287  break;
289  str = "Registered";
290  break;
293  str = "Rejected";
294  break;
295  }
296  return str;
297 }
298 
299 /*! \brief Outbound registration information */
301  /*! \brief Sorcery object details */
302  SORCERY_OBJECT(details);
303  /*! \brief Stringfields */
305  /*! \brief URI for the registrar */
307  /*! \brief URI for the AOR */
309  /*! \brief Optional user for contact header */
311  /*! \brief Optional header parameters for contact */
313  /*! \brief Explicit transport to use for registration */
315  /*! \brief Outbound proxy to use */
317  /*! \brief Endpoint to use for related incoming calls */
319  );
320  /*! \brief Requested expiration time */
321  unsigned int expiration;
322  /*! \brief Interval at which retries should occur for temporal responses */
323  unsigned int retry_interval;
324  /*! \brief Interval at which retries should occur for permanent responses */
326  /*! \brief Interval at which retries should occur for all permanent responses */
327  unsigned int fatal_retry_interval;
328  /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
330  /*! \brief Maximum number of retries permitted */
331  unsigned int max_retries;
332  /*! \brief Whether to add a line parameter to the outbound Contact or not */
333  unsigned int line;
334  /*! \brief Configured authentication credentials */
336  /*! \brief Whether Path support is enabled */
337  unsigned int support_path;
338  /*! \brief Whether Outbound support is enabled */
339  unsigned int support_outbound;
340 };
341 
342 /*! \brief Outbound registration client state information (persists for lifetime of regc) */
344  /*! \brief Current state of this registration */
346  /*!
347  * \brief Outbound registration client
348  * \note May only be accessed within the serializer thread
349  * because it might get destroyed and set to NULL for
350  * module unload.
351  */
352  pjsip_regc *client;
353  /*!
354  * \brief Last tdata sent
355  * We need the original tdata to resend a request on auth failure
356  * or timeout. On an auth failure, we use the original tdata
357  * to initialize the new tdata for the authorized response. On a timeout
358  * we need it to skip failed SRV entries if any.
359  */
360  pjsip_tx_data *last_tdata;
361  /*! \brief Timer entry for retrying on temporal responses */
362  pj_timer_entry timer;
363  /*! \brief Optional line parameter placed into Contact */
365  /*! \brief Current number of retries */
366  unsigned int retries;
367  /*! \brief Maximum number of retries permitted */
368  unsigned int max_retries;
369  /*! \brief Interval at which retries should occur for temporal responses */
370  unsigned int retry_interval;
371  /*! \brief Interval at which retries should occur for permanent responses */
373  /*! \brief Interval at which retries should occur for all permanent responses */
374  unsigned int fatal_retry_interval;
375  /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
377  /*! \brief Determines whether SIP Path support should be advertised */
378  unsigned int support_path;
379  /*! \brief Determines whether SIP Outbound support should be advertised */
380  unsigned int support_outbound;
381  /*! CSeq number of last sent auth request. */
382  unsigned int auth_cseq;
383  /*! \brief Serializer for stuff and things */
385  /*! \brief Configured authentication credentials */
387  /*! \brief Registration should be destroyed after completion of transaction */
388  unsigned int destroy:1;
389  /*! \brief Non-zero if we have attempted sending a REGISTER with authentication */
390  unsigned int auth_attempted:1;
391  /*! \brief The name of the transport to be used for the registration */
393  /*! \brief The name of the registration sorcery object */
395 };
396 
397 /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
399  /*! \brief Outbound registration configuration object */
401  /*! \brief Client state information */
403 };
404 
405 /*! Time needs to be long enough for a transaction to timeout if nothing replies. */
406 #define MAX_UNLOAD_TIMEOUT_TIME 35 /* Seconds */
407 
408 /*! Shutdown group to monitor sip_outbound_registration_client_state serializers. */
410 
411 /*! \brief Default number of state container buckets */
412 #define DEFAULT_STATE_BUCKETS 53
413 static AO2_GLOBAL_OBJ_STATIC(current_states);
414 
415 /*! subscription id for network change events */
417 
418 /*! \brief hashing function for state objects */
419 static int registration_state_hash(const void *obj, const int flags)
420 {
421  const struct sip_outbound_registration_state *object;
422  const char *key;
423 
424  switch (flags & OBJ_SEARCH_MASK) {
425  case OBJ_SEARCH_KEY:
426  key = obj;
427  break;
428  case OBJ_SEARCH_OBJECT:
429  object = obj;
431  break;
432  default:
433  ast_assert(0);
434  return 0;
435  }
436  return ast_str_hash(key);
437 }
438 
439 /*! \brief comparator function for state objects */
440 static int registration_state_cmp(void *obj, void *arg, int flags)
441 {
442  const struct sip_outbound_registration_state *object_left = obj;
443  const struct sip_outbound_registration_state *object_right = arg;
444  const char *right_key = arg;
445  int cmp;
446 
447  switch (flags & OBJ_SEARCH_MASK) {
448  case OBJ_SEARCH_OBJECT:
449  right_key = ast_sorcery_object_get_id(object_right->registration);
450  /* Fall through */
451  case OBJ_SEARCH_KEY:
452  cmp = strcmp(ast_sorcery_object_get_id(object_left->registration), right_key);
453  break;
455  /* Not supported by container. */
456  ast_assert(0);
457  return 0;
458  default:
459  cmp = 0;
460  break;
461  }
462  if (cmp) {
463  return 0;
464  }
465  return CMP_MATCH;
466 }
467 
468 static struct sip_outbound_registration_state *get_state(const char *id)
469 {
471  struct ao2_container *states;
472 
473  states = ao2_global_obj_ref(current_states);
474  if (states) {
475  state = ao2_find(states, id, OBJ_SEARCH_KEY);
476  ao2_ref(states, -1);
477  }
478  return state;
479 }
480 
481 static struct ao2_container *get_registrations(void)
482 {
484  ast_sip_get_sorcery(), "registration",
486 
487  return registrations;
488 }
489 
490 /*! \brief Callback function for matching an outbound registration based on line */
491 static int line_identify_relationship(void *obj, void *arg, int flags)
492 {
494  pjsip_param *line = arg;
495 
496  return !pj_strcmp2(&line->value, state->client_state->line) ? CMP_MATCH : 0;
497 }
498 
499 static struct pjsip_param *get_uri_option_line(const void *uri)
500 {
501  pjsip_sip_uri *pjuri;
502  static const pj_str_t LINE_STR = { "line", 4 };
503 
504  if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
505  return NULL;
506  }
507  pjuri = pjsip_uri_get_uri(uri);
508  return pjsip_param_find(&pjuri->other_param, &LINE_STR);
509 }
510 
511 /*! \brief Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing registration */
512 static struct ast_sip_endpoint *line_identify(pjsip_rx_data *rdata)
513 {
514  pjsip_param *line;
515  RAII_VAR(struct ao2_container *, states, NULL, ao2_cleanup);
517 
518  if (!(line = get_uri_option_line(rdata->msg_info.to->uri))
519  && !(line = get_uri_option_line(rdata->msg_info.msg->line.req.uri))) {
520  return NULL;
521  }
522 
523  states = ao2_global_obj_ref(current_states);
524  if (!states) {
525  return NULL;
526  }
527 
528  state = ao2_callback(states, 0, line_identify_relationship, line);
529  if (!state || ast_strlen_zero(state->registration->endpoint)) {
530  return NULL;
531  }
532 
533  ast_debug(3, "Determined relationship to outbound registration '%s' based on line '%s', using configured endpoint '%s'\n",
534  ast_sorcery_object_get_id(state->registration), state->client_state->line, state->registration->endpoint);
535 
536  return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", state->registration->endpoint);
537 }
538 
541 };
542 
543 /*! \brief Helper function which cancels the timer on a client */
545 {
546  if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
547  &client_state->timer, client_state->timer.id)) {
548  /* The timer was successfully cancelled, drop the refcount of client_state */
549  ao2_ref(client_state, -1);
550  }
551 }
552 
553 static pj_str_t PATH_NAME = { "path", 4 };
554 static pj_str_t OUTBOUND_NAME = { "outbound", 8 };
555 
556 /*! \brief Helper function which sends a message and cleans up, if needed, on failure */
557 static pj_status_t registration_client_send(struct sip_outbound_registration_client_state *client_state,
558  pjsip_tx_data *tdata)
559 {
560  pj_status_t status;
561  int *callback_invoked;
562  pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
563 
564  callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
565  if (!callback_invoked) {
566  pjsip_tx_data_dec_ref(tdata);
567  return PJ_ENOMEM;
568  }
569  *callback_invoked = 0;
570 
571  /* Due to the message going out the callback may now be invoked, so bump the count */
572  ao2_ref(client_state, +1);
573  /*
574  * We also bump tdata in expectation of saving it to client_state->last_tdata.
575  * We have to do it BEFORE pjsip_regc_send because if it succeeds, it decrements
576  * the ref count on its own.
577  */
578  pjsip_tx_data_add_ref(tdata);
579 
580  /*
581  * Set the transport in case transports were reloaded.
582  * When pjproject removes the extraneous error messages produced,
583  * we can check status and only set the transport and resend if there was an error
584  */
586  pjsip_regc_set_transport(client_state->client, &selector);
587  ast_sip_tpselector_unref(&selector);
588 
589  status = pjsip_regc_send(client_state->client, tdata);
590 
591  /*
592  * If the attempt to send the message failed and the callback was not invoked we need to
593  * drop the references we just added
594  */
595  if ((status != PJ_SUCCESS) && !(*callback_invoked)) {
596  pjsip_tx_data_dec_ref(tdata);
597  ao2_ref(client_state, -1);
598  return status;
599  }
600 
601  /*
602  * Decref the old last_data before replacing it.
603  * BTW, it's quite possible that last_data == tdata
604  * if we're trying successive servers in an SRV set.
605  */
606  if (client_state->last_tdata) {
607  pjsip_tx_data_dec_ref(client_state->last_tdata);
608  }
609  client_state->last_tdata = tdata;
610 
611  return status;
612 }
613 
614 /*! \brief Helper function to add string to Supported header */
615 static int add_to_supported_header(pjsip_tx_data *tdata, pj_str_t *name)
616 {
617  pjsip_supported_hdr *hdr;
618  int i;
619 
620  hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
621  if (!hdr) {
622  /* insert a new Supported header */
623  hdr = pjsip_supported_hdr_create(tdata->pool);
624  if (!hdr) {
625  pjsip_tx_data_dec_ref(tdata);
626  return 0;
627  }
628 
629  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
630  }
631 
632  /* Don't add the value if it's already there */
633  for (i = 0; i < hdr->count; ++i) {
634  if (pj_stricmp(&hdr->values[i], name) == 0) {
635  return 1;
636  }
637  }
638 
639  if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
640  return 0;
641  }
642 
643  /* add on to the existing Supported header */
644  pj_strassign(&hdr->values[hdr->count++], name);
645 
646  return 1;
647 }
648 
649 /*! \brief Helper function to add configured supported headers */
650 static int add_configured_supported_headers(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
651 {
652  if (client_state->support_path) {
653  if (!add_to_supported_header(tdata, &PATH_NAME)) {
654  return 0;
655  }
656  }
657 
658  if (client_state->support_outbound) {
659  if (!add_to_supported_header(tdata, &OUTBOUND_NAME)) {
660  return 0;
661  }
662  }
663 
664  return 1;
665 }
666 
667 /*! \brief Callback function for registering */
668 static int handle_client_registration(void *data)
669 {
670  RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
671  pjsip_tx_data *tdata;
672 
673  if (set_outbound_initial_authentication_credentials(client_state->client, &client_state->outbound_auths)) {
674  ast_log(LOG_WARNING, "Failed to set initial authentication credentials\n");
675  }
676 
677  if (client_state->status == SIP_REGISTRATION_STOPPED
678  || pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
679  return 0;
680  }
681 
682  if (DEBUG_ATLEAST(1)) {
683  pjsip_regc_info info;
684 
685  pjsip_regc_get_info(client_state->client, &info);
686  ast_log(LOG_DEBUG, "Outbound REGISTER attempt %u to '%.*s' with client '%.*s'\n",
687  client_state->retries + 1,
688  (int) info.server_uri.slen, info.server_uri.ptr,
689  (int) info.client_uri.slen, info.client_uri.ptr);
690  }
691 
692  if (!add_configured_supported_headers(client_state, tdata)) {
693  ast_log(LOG_WARNING, "Failed to set supported headers\n");
694  return -1;
695  }
696 
697  registration_client_send(client_state, tdata);
698 
699  return 0;
700 }
701 
702 /*! \brief Timer callback function, used just for registrations */
703 static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
704 {
705  struct sip_outbound_registration_client_state *client_state = entry->user_data;
706 
707  entry->id = 0;
708 
709  /*
710  * Transfer client_state reference to serializer task so the
711  * nominal path will not dec the client_state ref in this
712  * pjproject callback thread.
713  */
714  if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
715  ast_log(LOG_WARNING, "Scheduled outbound registration could not be executed.\n");
716  ao2_ref(client_state, -1);
717  }
718 }
719 
720 /*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
721 static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
722 {
723  pj_time_val delay = { .sec = seconds, };
724  pjsip_regc_info info;
725 
726  cancel_registration(client_state);
727 
728  pjsip_regc_get_info(client_state->client, &info);
729  ast_debug(1, "Scheduling outbound registration to server '%.*s' from client '%.*s' in %d seconds\n",
730  (int) info.server_uri.slen, info.server_uri.ptr,
731  (int) info.client_uri.slen, info.client_uri.ptr,
732  seconds);
733 
734  ao2_ref(client_state, +1);
735  if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
736  ast_log(LOG_WARNING, "Failed to schedule registration to server '%.*s' from client '%.*s'\n",
737  (int) info.server_uri.slen, info.server_uri.ptr,
738  (int) info.client_uri.slen, info.client_uri.ptr);
739  ao2_ref(client_state, -1);
740  }
741 }
742 
744 {
745  const char *status_old;
746  const char *status_new;
747 
748  if (client_state->status == status) {
749  /* Status state did not change at all. */
750  return;
751  }
752 
753  status_old = sip_outbound_registration_status_str(client_state->status);
755  client_state->status = status;
756 
757  if (!strcmp(status_old, status_new)) {
758  /*
759  * The internal status state may have changed but the status
760  * state we tell the world did not change at all.
761  */
762  return;
763  }
764 
765  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
766  status_old);
767  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
768  status_new);
769 }
770 
771 /*! \brief Callback function for unregistering (potentially) and destroying state */
772 static int handle_client_state_destruction(void *data)
773 {
774  struct sip_outbound_registration_client_state *client_state = data;
775 
776  cancel_registration(client_state);
777 
778  if (client_state->client) {
779  pjsip_regc_info info;
780  pjsip_tx_data *tdata;
781 
782  pjsip_regc_get_info(client_state->client, &info);
783 
784  if (info.is_busy == PJ_TRUE) {
785  /* If a client transaction is in progress we defer until it is complete */
786  ast_debug(1,
787  "Registration transaction is busy with server '%.*s' from client '%.*s'.\n",
788  (int) info.server_uri.slen, info.server_uri.ptr,
789  (int) info.client_uri.slen, info.client_uri.ptr);
790  client_state->destroy = 1;
791  ao2_ref(client_state, -1);
792  return 0;
793  }
794 
795  switch (client_state->status) {
797  break;
799  ast_debug(1,
800  "Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n",
801  (int) info.server_uri.slen, info.server_uri.ptr,
802  (int) info.client_uri.slen, info.client_uri.ptr);
803 
805  client_state->destroy = 1;
806  if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS
807  && add_configured_supported_headers(client_state, tdata)
808  && registration_client_send(client_state, tdata) == PJ_SUCCESS) {
809  ao2_ref(client_state, -1);
810  return 0;
811  }
812  break;
817  break;
818  }
819 
820  pjsip_regc_destroy(client_state->client);
821  client_state->client = NULL;
822  }
823 
826  ao2_ref(client_state, -1);
827 
828  return 0;
829 }
830 
831 /*! \brief Structure for registration response */
833  /*! \brief Response code for the registration attempt */
834  int code;
835  /*! \brief Expiration time for registration */
837  /*! \brief Retry-After value */
839  /*! \brief Outbound registration client state */
841  /*! \brief The response message */
842  pjsip_rx_data *rdata;
843  /*! \brief Request for which the response was received */
844  pjsip_tx_data *old_request;
845 };
846 
847 /*! \brief Registration response structure destructor */
848 static void registration_response_destroy(void *obj)
849 {
850  struct registration_response *response = obj;
851 
852  if (response->rdata) {
853  pjsip_rx_data_free_cloned(response->rdata);
854  }
855 
856  if (response->old_request) {
857  pjsip_tx_data_dec_ref(response->old_request);
858  }
859 
860  ao2_cleanup(response->client_state);
861 }
862 
863 /*! \brief Helper function which determines if a response code is temporal or not */
866 {
867  /* Shamelessly taken from pjsua */
868  if (code == PJSIP_SC_REQUEST_TIMEOUT ||
869  code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
870  code == PJSIP_SC_BAD_GATEWAY ||
871  code == PJSIP_SC_SERVICE_UNAVAILABLE ||
872  code == PJSIP_SC_SERVER_TIMEOUT ||
873  ((code == PJSIP_SC_UNAUTHORIZED ||
874  code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
876  PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
877  return 1;
878  } else {
879  return 0;
880  }
881 }
882 
883 static void schedule_retry(struct registration_response *response, unsigned int interval,
884  const char *server_uri, const char *client_uri)
885 {
887  schedule_registration(response->client_state, interval);
888 
889  if (response->rdata) {
890  ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
891  "registration attempt to '%s', retrying in '%u'\n",
892  response->code, server_uri, client_uri, interval);
893  } else {
894  ast_log(LOG_WARNING, "No response received from '%s' on "
895  "registration attempt to '%s', retrying in '%u'\n",
896  server_uri, client_uri, interval);
897  }
898 }
899 
900 static int reregister_immediately_cb(void *obj)
901 {
903 
904  if (state->client_state->status != SIP_REGISTRATION_REGISTERED) {
905  ao2_ref(state, -1);
906  return 0;
907  }
908 
909  if (DEBUG_ATLEAST(1)) {
910  pjsip_regc_info info;
911 
912  pjsip_regc_get_info(state->client_state->client, &info);
914  "Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n",
915  (int) info.server_uri.slen, info.server_uri.ptr,
916  (int) info.client_uri.slen, info.client_uri.ptr);
917  }
918 
919  cancel_registration(state->client_state);
920 
921  ao2_ref(state->client_state, +1);
922  handle_client_registration(state->client_state);
923 
924  ao2_ref(state, -1);
925  return 0;
926 }
927 
928 /*!
929  * \internal
930  * \brief The reliable transport we registered using has shutdown.
931  * \since 13.18.0
932  *
933  * \param obj What is needed to initiate a reregister attempt.
934  *
935  * \note Normally executed by the pjsip monitor thread.
936  */
938 {
939  const char *registration_name = obj;
941 
942  state = get_state(registration_name);
943  if (!state) {
944  /* Registration no longer exists or shutting down. */
945  return;
946  }
947  if (ast_sip_push_task(state->client_state->serializer, reregister_immediately_cb, state)) {
948  ao2_ref(state, -1);
949  }
950 }
951 
952 static int monitor_matcher(void *a, void *b)
953 {
954  char *ma = a;
955  char *mb = b;
956 
957  return strcmp(ma, mb) == 0;
958 }
959 
960 static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name)
961 {
962  char *monitor;
963 
964  if (!PJSIP_TRANSPORT_IS_RELIABLE(transport)) {
965  return;
966  }
967  monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL,
969  if (!monitor) {
970  return;
971  }
972  strcpy(monitor, registration_name);/* Safe */
973 
974  /*
975  * We'll ignore if the transport has already been shutdown before we
976  * register the monitor. We might get into a message spamming infinite
977  * loop of registration, shutdown, reregistration...
978  */
980  monitor);
981  ao2_ref(monitor, -1);
982 }
983 
985 {
986  static const pj_str_t associated_uri_str = { "P-Associated-URI", 16 };
987  static const pj_str_t service_route_str = { "Service-Route", 13 };
988  pjsip_hdr *header = NULL;
989  pjsip_msg *msg = response->rdata->msg_info.msg;
990  struct ast_sip_service_route_vector *service_routes = NULL;
991 
992  /* If no transport is specified then we can't update any */
993  if (ast_strlen_zero(response->client_state->transport_name)) {
994  return;
995  }
996 
997  ast_sip_transport_state_set_transport(response->client_state->transport_name, response->rdata->tp_info.transport);
998 
999  while ((header = pjsip_msg_find_hdr_by_name(msg, &service_route_str, header ? header->next : NULL))) {
1000  char *service_route;
1001  size_t size;
1002 
1003  /* The below code takes the approach that if we can't store all service routes then we
1004  * store none at all. This gives a predictable failure condition instead of storing a
1005  * partial list and having partial route headers.
1006  */
1007  size = pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1;
1008  service_route = ast_malloc(size);
1009  if (!service_route) {
1010  if (service_routes) {
1011  ast_sip_service_route_vector_destroy(service_routes);
1012  service_routes = NULL;
1013  }
1014  break;
1015  }
1016 
1017  ast_copy_pj_str(service_route, &((pjsip_generic_string_hdr*)header)->hvalue, size);
1018 
1019  if (!service_routes) {
1020  service_routes = ast_sip_service_route_vector_alloc();
1021  if (!service_routes) {
1022  ast_free(service_route);
1023  break;
1024  }
1025  }
1026 
1027  if (AST_VECTOR_APPEND(service_routes, service_route)) {
1028  ast_free(service_route);
1029  ast_sip_service_route_vector_destroy(service_routes);
1030  service_routes = NULL;
1031  break;
1032  }
1033  }
1034 
1035  /* If any service routes were handled then store them on the transport */
1036  if (service_routes) {
1038  }
1039 
1040  /* If an associated URI is present in the response we need to use it on any outgoing
1041  * traffic on the transport.
1042  */
1043  header = pjsip_msg_find_hdr_by_name(msg, &associated_uri_str, NULL);
1044  if (header) {
1045  char value[pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1];
1046 
1047  ast_copy_pj_str(value, &((pjsip_generic_string_hdr*)header)->hvalue, sizeof(value));
1049  }
1050 }
1051 
1052 
1053 /*! \brief Callback function for handling a response to a registration attempt */
1054 static int handle_registration_response(void *data)
1055 {
1056  struct registration_response *response = data;
1057  pjsip_regc_info info;
1058  char server_uri[PJSIP_MAX_URL_SIZE];
1059  char client_uri[PJSIP_MAX_URL_SIZE];
1060 
1061  if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
1062  ao2_ref(response, -1);
1063  return 0;
1064  }
1065 
1066  pjsip_regc_get_info(response->client_state->client, &info);
1067  ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
1068  ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
1069 
1070  ast_debug(1, "Processing REGISTER response %d from server '%s' for client '%s'\n",
1071  response->code, server_uri, client_uri);
1072 
1073  if (response->code == 408 || response->code == 503) {
1074  if ((ast_sip_failover_request(response->old_request))) {
1075  int res = registration_client_send(response->client_state, response->old_request);
1076  /* The tdata ref was stolen */
1077  response->old_request = NULL;
1078  if (res == PJ_SUCCESS) {
1079  ao2_ref(response, -1);
1080  return 0;
1081  }
1082  }
1083  } else if ((response->code == 401 || response->code == 407)
1084  && (!response->client_state->auth_attempted
1085  || response->rdata->msg_info.cseq->cseq != response->client_state->auth_cseq)) {
1086  int res;
1087  pjsip_cseq_hdr *cseq_hdr;
1088  pjsip_tx_data *tdata;
1089 
1091  response->rdata, response->old_request, &tdata)) {
1092  response->client_state->auth_attempted = 1;
1093  ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
1094  server_uri, client_uri);
1095  pjsip_tx_data_add_ref(tdata);
1096  res = registration_client_send(response->client_state, tdata);
1097 
1098  /* Save the cseq that actually got sent. */
1099  cseq_hdr = (pjsip_cseq_hdr *) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ,
1100  NULL);
1101  response->client_state->auth_cseq = cseq_hdr->cseq;
1102  pjsip_tx_data_dec_ref(tdata);
1103  if (res == PJ_SUCCESS) {
1104  ao2_ref(response, -1);
1105  return 0;
1106  }
1107  } else {
1108  ast_log(LOG_WARNING, "Failed to create authenticated REGISTER request to server '%s' from client '%s'\n",
1109  server_uri, client_uri);
1110  }
1111  /* Otherwise, fall through so the failure is processed appropriately */
1112  }
1113 
1114  response->client_state->auth_attempted = 0;
1115 
1116  if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
1117  /* Check if this is in regards to registering or unregistering */
1118  if (response->expiration) {
1119  int next_registration_round;
1120 
1121  /* If the registration went fine simply reschedule registration for the future */
1122  ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
1124  response->client_state->retries = 0;
1125  next_registration_round = response->expiration - REREGISTER_BUFFER_TIME;
1126  if (next_registration_round < 0) {
1127  /* Re-register immediately. */
1128  next_registration_round = 0;
1129  }
1130  schedule_registration(response->client_state, next_registration_round);
1131 
1132  /* See if we should monitor for transport shutdown */
1133  registration_transport_monitor_setup(response->rdata->tp_info.transport,
1134  response->client_state->registration_name);
1135  } else {
1136  ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
1138  ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport,
1140  monitor_matcher);
1141  }
1142 
1144  } else if (response->client_state->destroy) {
1145  /* We need to deal with the pending destruction instead. */
1146  } else if (response->retry_after) {
1147  /* If we have been instructed to retry after a period of time, schedule it as such */
1148  schedule_retry(response, response->retry_after, server_uri, client_uri);
1149  } else if (response->client_state->retry_interval
1150  && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
1151  if (response->client_state->retries == response->client_state->max_retries) {
1152  /* If we received enough temporal responses to exceed our maximum give up permanently */
1154  ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
1155  server_uri, client_uri);
1156  } else {
1157  /* On the other hand if we can still try some more do so */
1158  response->client_state->retries++;
1159  schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
1160  }
1161  } else {
1162  if (response->code == 403
1164  && response->client_state->retries < response->client_state->max_retries) {
1165  /* A forbidden response retry interval is configured and there are retries remaining */
1167  response->client_state->retries++;
1169  ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1170  server_uri, client_uri, response->client_state->forbidden_retry_interval);
1171  } else if (response->client_state->fatal_retry_interval
1172  && response->client_state->retries < response->client_state->max_retries) {
1173  /* Some kind of fatal failure response received, so retry according to configured interval */
1175  response->client_state->retries++;
1177  ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1178  response->code, server_uri, client_uri, response->client_state->fatal_retry_interval);
1179  } else {
1180  /* Finally if there's no hope of registering give up */
1182  if (response->rdata) {
1183  ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
1184  response->code, server_uri, client_uri);
1185  } else {
1186  ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
1187  }
1188  }
1189  }
1190 
1191  ast_system_publish_registry("PJSIP", client_uri, server_uri,
1193 
1194  if (response->client_state->destroy) {
1195  /* We have a pending deferred destruction to complete now. */
1196  ao2_ref(response->client_state, +1);
1198  }
1199 
1200  ao2_ref(response, -1);
1201  return 0;
1202 }
1203 
1204 /*! \brief Callback function for outbound registration client */
1205 static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
1206 {
1207  struct sip_outbound_registration_client_state *client_state = param->token;
1208  struct registration_response *response;
1209  int *callback_invoked;
1210 
1211  callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
1212 
1213  ast_assert(callback_invoked != NULL);
1215 
1216  *callback_invoked = 1;
1217 
1218  response = ao2_alloc(sizeof(*response), registration_response_destroy);
1219  if (!response) {
1220  ao2_ref(client_state, -1);
1221  return;
1222  }
1223  response->code = param->code;
1224  response->expiration = param->expiration;
1225  /*
1226  * Transfer client_state reference to response so the
1227  * nominal path will not dec the client_state ref in this
1228  * pjproject callback thread.
1229  */
1230  response->client_state = client_state;
1231 
1232  ast_debug(1, "Received REGISTER response %d(%.*s)\n",
1233  param->code, (int) param->reason.slen, param->reason.ptr);
1234 
1235  if (param->rdata) {
1236  struct pjsip_retry_after_hdr *retry_after;
1237  pjsip_transaction *tsx;
1238 
1239  retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER,
1240  NULL);
1241  response->retry_after = retry_after ? retry_after->ivalue : 0;
1242 
1243  /*
1244  * If we got a response from the server, we have to use the tdata
1245  * from the transaction, not the tdata saved when we sent the
1246  * request. If we use the saved tdata, we won't process responses
1247  * like 423 Interval Too Brief correctly and we'll wind up sending
1248  * the bad Expires value again.
1249  */
1250  pjsip_tx_data_dec_ref(client_state->last_tdata);
1251 
1252  tsx = pjsip_rdata_get_tsx(param->rdata);
1253  response->old_request = tsx->last_tx;
1254  pjsip_tx_data_add_ref(response->old_request);
1255  pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
1256  } else {
1257  /* old_request steals the reference */
1258  response->old_request = client_state->last_tdata;
1259  }
1260  client_state->last_tdata = NULL;
1261 
1262  /*
1263  * Transfer response reference to serializer task so the
1264  * nominal path will not dec the response ref in this
1265  * pjproject callback thread.
1266  */
1267  if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
1268  ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
1269  ao2_cleanup(response);
1270  }
1271 }
1272 
1273 /*! \brief Destructor function for registration state */
1275 {
1276  struct sip_outbound_registration_state *state = obj;
1277 
1278  ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n",
1279  state->registration ? state->registration->server_uri : "",
1280  state->registration ? state->registration->client_uri : "");
1281  ao2_cleanup(state->registration);
1282 
1283  if (!state->client_state) {
1284  /* Nothing to do */
1285  } else if (!state->client_state->serializer) {
1286  ao2_ref(state->client_state, -1);
1287  } else if (ast_sip_push_task(state->client_state->serializer,
1288  handle_client_state_destruction, state->client_state)) {
1289  ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
1290  ao2_ref(state->client_state, -1);
1291  }
1292 }
1293 
1294 /*! \brief Destructor function for client registration state */
1296 {
1297  struct sip_outbound_registration_client_state *client_state = obj;
1298 
1299  ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0);
1300  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
1302 
1304  ast_free(client_state->transport_name);
1305  ast_free(client_state->registration_name);
1306  if (client_state->last_tdata) {
1307  pjsip_tx_data_dec_ref(client_state->last_tdata);
1308  }
1309 }
1310 
1311 /*! \brief Allocator function for registration state */
1313 {
1315  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1316 
1318  if (!state) {
1319  return NULL;
1320  }
1321  state->client_state = ao2_alloc(sizeof(*state->client_state),
1323  if (!state->client_state) {
1324  ao2_cleanup(state);
1325  return NULL;
1326  }
1327 
1328  state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
1329  pj_timer_entry_init(&state->client_state->timer, 0, state->client_state,
1331  state->client_state->transport_name = ast_strdup(registration->transport);
1332  state->client_state->registration_name =
1334 
1335  ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0);
1336  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
1337  sip_outbound_registration_status_str(state->client_state->status));
1338 
1339  if (!state->client_state->transport_name
1340  || !state->client_state->registration_name) {
1341  ao2_cleanup(state);
1342  return NULL;
1343  }
1344 
1345  /* Create name with seq number appended. */
1346  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outreg/%s",
1348 
1349  state->client_state->serializer = ast_sip_create_serializer_group(tps_name,
1350  shutdown_group);
1351  if (!state->client_state->serializer) {
1352  ao2_cleanup(state);
1353  return NULL;
1354  }
1355 
1356  state->registration = ao2_bump(registration);
1357  return state;
1358 }
1359 
1360 /*! \brief Destructor function for registration information */
1362 {
1363  struct sip_outbound_registration *registration = obj;
1364 
1366 
1367  ast_string_field_free_memory(registration);
1368 }
1369 
1370 /*! \brief Allocator function for registration information */
1371 static void *sip_outbound_registration_alloc(const char *name)
1372 {
1373  struct sip_outbound_registration *registration;
1374 
1375  registration = ast_sorcery_generic_alloc(sizeof(*registration),
1377  if (!registration || ast_string_field_init(registration, 256)) {
1378  ao2_cleanup(registration);
1379  return NULL;
1380  }
1381 
1382  return registration;
1383 }
1384 
1385 /*! \brief Helper function which populates a pj_str_t with a contact header */
1386 static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user,
1387  const pj_str_t *target, pjsip_tpselector *selector, const char *line, const char *header_params)
1388 {
1389  pj_str_t tmp, local_addr;
1390  pjsip_uri *uri;
1391  pjsip_sip_uri *sip_uri;
1392  pjsip_transport_type_e type;
1393  int local_port;
1394 
1395  pj_strdup_with_null(pool, &tmp, target);
1396 
1397  if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
1398  (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
1399  return -1;
1400  }
1401 
1402  sip_uri = pjsip_uri_get_uri(uri);
1403 
1404  type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
1405  if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
1406  if (type == PJSIP_TRANSPORT_UNSPECIFIED
1407  || !(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE)) {
1408  type = PJSIP_TRANSPORT_TLS;
1409  }
1410  } else if (!sip_uri->transport_param.slen) {
1411  type = PJSIP_TRANSPORT_UDP;
1412  } else if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
1413  return -1;
1414  }
1415 
1416  if (pj_strchr(&sip_uri->host, ':')) {
1417  type |= PJSIP_TRANSPORT_IPV6;
1418  }
1419 
1420  if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
1421  pool, type, selector, &local_addr, &local_port) != PJ_SUCCESS) {
1422  return -1;
1423  }
1424 
1425  if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
1426  type |= PJSIP_TRANSPORT_IPV6;
1427  }
1428 
1429  contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
1430  contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
1431  "<%s:%s@%s%.*s%s:%d%s%s%s%s>%s%s",
1432  ((pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) && PJSIP_URI_SCHEME_IS_SIPS(uri)) ? "sips" : "sip",
1433  user,
1434  (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
1435  (int)local_addr.slen,
1436  local_addr.ptr,
1437  (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
1438  local_port,
1439  (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
1440  (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "",
1441  !ast_strlen_zero(line) ? ";line=" : "",
1442  S_OR(line, ""),
1443  !ast_strlen_zero(header_params) ? ";" : "",
1444  S_OR(header_params, ""));
1445 
1446  return 0;
1447 }
1448 
1449 /*!
1450  * \internal
1451  * \brief Check if a registration can be reused
1452  *
1453  * This checks if the existing outbound registration's configuration differs from a newly-applied
1454  * outbound registration to see if the applied one.
1455  *
1456  * \param existing The pre-existing outbound registration
1457  * \param applied The newly-created registration
1458  */
1460  struct sip_outbound_registration *applied)
1461 {
1462  int rc = 1;
1464  struct ast_variable *ve = ast_sorcery_objectset_create(sorcery, existing);
1465  struct ast_variable *va = ast_sorcery_objectset_create(sorcery, applied);
1466  struct ast_variable *vc = NULL;
1467 
1468  if (ast_sorcery_changeset_create(ve, va, &vc) || vc != NULL) {
1469  rc = 0;
1470  ast_debug(4, "Registration '%s' changed. Can't re-use.\n", ast_sorcery_object_get_id(existing));
1471  } else {
1472  ast_debug(4, "Registration '%s' didn't change. Can re-use\n", ast_sorcery_object_get_id(existing));
1473  }
1474 
1478 
1479  return rc;
1480 }
1481 
1482 /*! \brief Get google oauth2 access token using refresh token */
1483 static const char *fetch_google_access_token(const struct ast_sip_auth *auth)
1484 {
1485  char *cmd = NULL;
1486  const char *token;
1487  const char *url = "https://www.googleapis.com/oauth2/v3/token";
1488  char buf[4096];
1489  int res;
1490  struct ast_json_error error;
1491  struct ast_json *json;
1492 
1493  /* set timeout to be shorter than default 180s (also checks func_curl is available) */
1494  if (ast_func_write(NULL, "CURLOPT(conntimeout)", "10")) {
1495  ast_log(LOG_ERROR, "CURL is unavailable. This is required for Google OAuth 2.0 authentication. Please ensure it is loaded.\n");
1496  return NULL;
1497  }
1498 
1499  res = ast_asprintf(&cmd,
1500  "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)",
1501  url, auth->oauth_clientid, auth->oauth_secret, auth->refresh_token);
1502  if (res < 0) {
1503  return NULL;
1504  }
1505 
1506  ast_debug(2, "Performing Google OAuth 2.0 authentication using command: %s\n", cmd);
1507 
1508  buf[0] = '\0';
1509  res = ast_func_read(NULL, cmd, buf, sizeof(buf));
1510  ast_free(cmd);
1511  if (res) {
1512  ast_log(LOG_ERROR, "Could not retrieve Google OAuth 2.0 authentication\n");
1513  return NULL;
1514  }
1515 
1516  ast_debug(2, "Google OAuth 2.0 authentication returned: %s\n", buf);
1517 
1518  json = ast_json_load_string(buf, &error);
1519  if (!json) {
1520  ast_log(LOG_ERROR, "Could not parse Google OAuth 2.0 authentication: %d(%d) %s: '%s'\n",
1521  error.line, error.column, error.text, buf);
1522  return NULL;
1523  }
1524 
1525  token = ast_json_string_get(ast_json_object_get(json, "access_token"));
1526  if (!token) {
1527  ast_log(LOG_ERROR, "Could not find Google OAuth 2.0 access_token in: '%s'\n",
1528  buf);
1529  }
1530  token = ast_strdup(token);
1531  ast_json_unref(json);
1532  return token;
1533 }
1534 
1535 /*!
1536  * \internal
1537  * \brief Set pjsip registration context with any authentication credentials that need to be
1538  * sent in the initial registration request
1539  *
1540  * \param regc The pjsip registration context
1541  * \param auth_vector The vector of configured authentication credentials
1542  */
1544  const struct ast_sip_auth_vector *auth_vector)
1545 {
1546  size_t auth_size = AST_VECTOR_SIZE(auth_vector);
1547  struct ast_sip_auth *auths[auth_size];
1548  const char *access_token;
1549  pjsip_cred_info auth_creds[1];
1550  pjsip_auth_clt_pref prefs;
1551  int res = 0;
1552  int idx;
1553 
1554  memset(auths, 0, sizeof(auths));
1555  if (ast_sip_retrieve_auths(auth_vector, auths)) {
1556  res = -1;
1557  goto cleanup;
1558  }
1559 
1560  for (idx = 0; idx < auth_size; ++idx) {
1561  switch (auths[idx]->type) {
1563  pj_cstr(&auth_creds[0].username, auths[idx]->auth_user);
1564  pj_cstr(&auth_creds[0].scheme, "Bearer");
1565  pj_cstr(&auth_creds[0].realm, auths[idx]->realm);
1566  ast_debug(2, "Obtaining Google OAuth access token\n");
1567  access_token = fetch_google_access_token(auths[idx]);
1568  if (!access_token) {
1569  ast_log(LOG_WARNING, "Obtaining Google OAuth access token failed\n");
1570  access_token = auths[idx]->auth_pass;
1571  res = -1;
1572  }
1573  ast_debug(2, "Setting data to '%s'\n", access_token);
1574 
1575  pj_cstr(&auth_creds[0].data, access_token);
1576  auth_creds[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
1577 
1578  pjsip_regc_set_credentials(regc, 1, auth_creds);
1579 
1580  /* for oauth, send auth without waiting for unauthorized response */
1581  prefs.initial_auth = PJ_TRUE;
1582  pj_cstr(&prefs.algorithm, "oauth");
1583  pjsip_regc_set_prefs(regc, &prefs);
1584 
1585  if (access_token != auths[idx]->auth_pass) {
1586  ast_free((char *) access_token);
1587  }
1588  break;
1589  default:
1590  /* other cases handled after receiving auth rejection */
1591  break;
1592  }
1593  }
1594 
1595 cleanup:
1596  ast_sip_cleanup_auths(auths, auth_size);
1597  return res;
1598 }
1599 
1600 /*! \brief Helper function that allocates a pjsip registration client and configures it */
1602 {
1603  struct sip_outbound_registration_state *state = data;
1605  ao2_bump(state->registration), ao2_cleanup);
1606  pj_pool_t *pool;
1607  pj_str_t tmp;
1608  pjsip_uri *uri;
1609  pj_str_t server_uri, client_uri, contact_uri;
1610  pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
1611 
1612  pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
1613  if (!pool) {
1614  ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
1616  return -1;
1617  }
1618 
1619  pj_strdup2_with_null(pool, &tmp, registration->server_uri);
1620  uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1621  if (!uri) {
1622  ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
1624  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1625  return -1;
1626  }
1627 
1628  pj_strdup2_with_null(pool, &tmp, registration->client_uri);
1629  uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1630  if (!uri) {
1631  ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
1633  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1634  return -1;
1635  }
1636 
1638  pj_strdup2_with_null(pool, &tmp, registration->outbound_proxy);
1639  uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1640  if (!uri) {
1641  ast_log(LOG_ERROR, "Invalid outbound proxy URI '%s' specified on outbound registration '%s'\n",
1643  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1644  return -1;
1645  }
1646  }
1647 
1648  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1649 
1650 
1651  ast_assert(state->client_state->client == NULL);
1652  if (pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state,
1654  &state->client_state->client) != PJ_SUCCESS) {
1655  return -1;
1656  }
1657 
1659  pjsip_regc_set_transport(state->client_state->client, &selector);
1660 
1662  pjsip_route_hdr route_set, *route;
1663  static const pj_str_t ROUTE_HNAME = { "Route", 5 };
1664  pj_str_t tmp;
1665 
1666  pj_list_init(&route_set);
1667 
1668  pj_strdup2_with_null(pjsip_regc_get_pool(state->client_state->client), &tmp,
1670  route = pjsip_parse_hdr(pjsip_regc_get_pool(state->client_state->client),
1671  &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL);
1672  if (!route) {
1673  ast_sip_tpselector_unref(&selector);
1674  return -1;
1675  }
1676  pj_list_insert_nodes_before(&route_set, route);
1677 
1678  pjsip_regc_set_route_set(state->client_state->client, &route_set);
1679  }
1680 
1681  if (state->registration->line) {
1682  ast_generate_random_string(state->client_state->line, sizeof(state->client_state->line));
1683  }
1684 
1685  pj_cstr(&server_uri, registration->server_uri);
1686 
1687  if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client),
1688  &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
1689  state->client_state->line, registration->contact_header_params)) {
1690  ast_sip_tpselector_unref(&selector);
1691  return -1;
1692  }
1693 
1694  ast_sip_tpselector_unref(&selector);
1695 
1696  pj_cstr(&client_uri, registration->client_uri);
1697  if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri,
1698  &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
1699  return -1;
1700  }
1701 
1702  return 0;
1703 }
1704 
1705 /*! \brief Helper function which performs a single registration */
1707 {
1708  struct sip_outbound_registration_state *state = data;
1709  struct sip_outbound_registration *registration = ao2_bump(state->registration);
1710  size_t i;
1711 
1712  /* Just in case the client state is being reused for this registration, free the auth information */
1713  ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
1714 
1715  AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(&registration->outbound_auths));
1716  for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
1717  char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
1718 
1719  if (name && AST_VECTOR_APPEND(&state->client_state->outbound_auths, name)) {
1720  ast_free(name);
1721  }
1722  }
1723  state->client_state->retry_interval = registration->retry_interval;
1724  state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
1725  state->client_state->fatal_retry_interval = registration->fatal_retry_interval;
1726  state->client_state->max_retries = registration->max_retries;
1727  state->client_state->retries = 0;
1728  state->client_state->support_path = registration->support_path;
1729  state->client_state->support_outbound = registration->support_outbound;
1730  state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
1731 
1732  pjsip_regc_update_expires(state->client_state->client, registration->expiration);
1733 
1734  schedule_registration(state->client_state, (ast_random() % 10) + 1);
1735 
1736  ao2_ref(registration, -1);
1737  ao2_ref(state, -1);
1738  return 0;
1739 }
1740 
1741 /*! \brief Apply function which finds or allocates a state structure */
1742 static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
1743 {
1744  RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup);
1747  struct sip_outbound_registration *applied = obj;
1748 
1749  if (!states) {
1750  /* Global container has gone. Likely shutting down. */
1751  return -1;
1752  }
1754 
1755  ast_debug(4, "Applying configuration to outbound registration '%s'\n", ast_sorcery_object_get_id(applied));
1756 
1757  if (ast_strlen_zero(applied->server_uri)) {
1758  ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'\n",
1759  ast_sorcery_object_get_id(applied));
1760  return -1;
1761  } else if (ast_sip_validate_uri_length(applied->server_uri)) {
1762  ast_log(LOG_ERROR, "Server URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
1763  ast_sorcery_object_get_id(applied));
1764  return -1;
1765  } else if (ast_strlen_zero(applied->client_uri)) {
1766  ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
1767  ast_sorcery_object_get_id(applied));
1768  return -1;
1769  } else if (ast_sip_validate_uri_length(applied->client_uri)) {
1770  ast_log(LOG_ERROR, "Client URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
1771  ast_sorcery_object_get_id(applied));
1772  return -1;
1773  } else if (applied->line && ast_strlen_zero(applied->endpoint)) {
1774  ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
1775  ast_sorcery_object_get_id(applied));
1776  return -1;
1777  } else if (!ast_strlen_zero(applied->endpoint) && !applied->line) {
1778  ast_log(LOG_ERROR, "An endpoint has been specified on outbound registration '%s' without enabling line support\n",
1779  ast_sorcery_object_get_id(applied));
1780  return -1;
1781  }
1782 
1783  if (state && can_reuse_registration(state->registration, applied)) {
1784  ast_debug(4,
1785  "No change between old configuration and new configuration on outbound registration '%s'. Using previous state\n",
1786  ast_sorcery_object_get_id(applied));
1787 
1788  /*
1789  * This is OK to replace without relinking the state in the
1790  * current_states container since state->registration and
1791  * applied have the same key.
1792  */
1793  ao2_lock(states);
1794  ao2_replace(state->registration, applied);
1795  ao2_unlock(states);
1796  return 0;
1797  }
1798 
1799  if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
1800  return -1;
1801  }
1802 
1803  if (ast_sip_push_task_wait_serializer(new_state->client_state->serializer,
1805  return -1;
1806  }
1807 
1808  if (ast_sip_push_task(new_state->client_state->serializer,
1810  ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n",
1811  ast_sorcery_object_get_id(new_state->registration));
1812  ao2_ref(new_state, -1);
1813  return -1;
1814  }
1815 
1816  ao2_lock(states);
1817  if (state) {
1818  ao2_unlink(states, state);
1819  }
1820  ao2_link(states, new_state);
1821  ao2_unlock(states);
1822 
1823  return 0;
1824 }
1825 
1826 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1827 {
1828  struct sip_outbound_registration *registration = obj;
1829 
1830  return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
1831 }
1832 
1833 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
1834 {
1835  const struct sip_outbound_registration *registration = obj;
1836 
1837  return ast_sip_auths_to_str(&registration->outbound_auths, buf);
1838 }
1839 
1840 static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
1841 {
1842  const struct sip_outbound_registration *registration = obj;
1843  int i;
1844  struct ast_variable *head = NULL;
1845 
1846  for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
1847  ast_variable_list_append(&head, ast_variable_new("outbound_auth",
1848  AST_VECTOR_GET(&registration->outbound_auths, i), ""));
1849  }
1850 
1851  if (head) {
1852  *fields = head;
1853  }
1854 
1855  return 0;
1856 }
1857 
1858 static int unregister_task(void *obj)
1859 {
1860  struct sip_outbound_registration_state *state = obj;
1861  struct pjsip_regc *client = state->client_state->client;
1862  pjsip_tx_data *tdata;
1863  pjsip_regc_info info;
1864 
1865  pjsip_regc_get_info(client, &info);
1866  ast_debug(1, "Unregistering contacts with server '%s' from client '%s'\n",
1867  state->registration->server_uri, state->registration->client_uri);
1868 
1869  cancel_registration(state->client_state);
1870 
1871  if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS
1872  && add_configured_supported_headers(state->client_state, tdata)) {
1873  registration_client_send(state->client_state, tdata);
1874  }
1875 
1876  ao2_ref(state, -1);
1877  return 0;
1878 }
1879 
1881 {
1882  ao2_ref(state, +1);
1883  if (ast_sip_push_task(state->client_state->serializer, unregister_task, state)) {
1884  ao2_ref(state, -1);
1885  return -1;
1886  }
1887 
1888  return 0;
1889 }
1890 
1892 {
1893  ao2_ref(state, +1);
1894  if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) {
1895  ao2_ref(state, -1);
1896  return -1;
1897  }
1898 
1899  return 0;
1900 }
1901 
1902 static void unregister_all(void)
1903 {
1904  struct ao2_container *states;
1905 
1906  states = ao2_global_obj_ref(current_states);
1907  if (!states) {
1908  return;
1909  }
1910 
1911  /* Clean out all the states and let sorcery handle recreating the registrations */
1913  ao2_ref(states, -1);
1914 }
1915 
1916 static void reregister_all(void)
1917 {
1918  unregister_all();
1919  ast_sorcery_load_object(ast_sip_get_sorcery(), "registration");
1920 }
1921 
1922 static char *cli_complete_registration(const char *line, const char *word,
1923  int pos, int state)
1924 {
1925  char *result = NULL;
1926  int wordlen;
1927  int which = 0;
1928  struct sip_outbound_registration *registration;
1929  struct ao2_container *registrations;
1930  struct ao2_iterator i;
1931 
1932  if (pos != 3) {
1933  return NULL;
1934  }
1935 
1936  wordlen = strlen(word);
1937  if (wordlen == 0 && ++which > state) {
1938  return ast_strdup("*all");
1939  }
1940 
1943  if (!registrations) {
1944  return NULL;
1945  }
1946 
1948  while ((registration = ao2_iterator_next(&i))) {
1949  const char *name = ast_sorcery_object_get_id(registration);
1950 
1951  if (!strncasecmp(word, name, wordlen) && ++which > state) {
1952  result = ast_strdup(name);
1953  }
1954 
1955  ao2_ref(registration, -1);
1956  if (result) {
1957  break;
1958  }
1959  }
1961 
1962  ao2_ref(registrations, -1);
1963  return result;
1964 }
1965 
1966 static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1967 {
1969  const char *registration_name;
1970 
1971  switch (cmd) {
1972  case CLI_INIT:
1973  e->command = "pjsip send unregister";
1974  e->usage =
1975  "Usage: pjsip send unregister <registration> | *all\n"
1976  " Unregisters the specified (or all) outbound registration(s) "
1977  "and stops future registration attempts.\n";
1978  return NULL;
1979  case CLI_GENERATE:
1980  return cli_complete_registration(a->line, a->word, a->pos, a->n);
1981  }
1982 
1983  if (a->argc != 4) {
1984  return CLI_SHOWUSAGE;
1985  }
1986 
1987  registration_name = a->argv[3];
1988 
1989  if (strcmp(registration_name, "*all") == 0) {
1990  unregister_all();
1991  ast_cli(a->fd, "Unregister all queued\n");
1992  return CLI_SUCCESS;
1993  }
1994 
1995  state = get_state(registration_name);
1996  if (!state) {
1997  ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
1998  return CLI_FAILURE;
1999  }
2000 
2001  if (queue_unregister(state)) {
2002  ast_cli(a->fd, "Failed to queue unregistration\n");
2003  }
2004 
2005  ao2_ref(state, -1);
2006  return CLI_SUCCESS;
2007 }
2008 
2009 static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2010 {
2012  const char *registration_name;
2013 
2014  switch (cmd) {
2015  case CLI_INIT:
2016  e->command = "pjsip send register";
2017  e->usage =
2018  "Usage: pjsip send register <registration> | *all \n"
2019  " Unregisters the specified (or all) outbound "
2020  "registration(s) then starts registration(s) and schedules re-registrations.\n";
2021  return NULL;
2022  case CLI_GENERATE:
2023  return cli_complete_registration(a->line, a->word, a->pos, a->n);
2024  }
2025 
2026  if (a->argc != 4) {
2027  return CLI_SHOWUSAGE;
2028  }
2029 
2030  registration_name = a->argv[3];
2031 
2032  if (strcmp(registration_name, "*all") == 0) {
2033  reregister_all();
2034  ast_cli(a->fd, "Re-register all queued\n");
2035  return CLI_SUCCESS;
2036  }
2037 
2038  state = get_state(registration_name);
2039  if (!state) {
2040  ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
2041  return CLI_FAILURE;
2042  }
2043 
2044  /* We need to serialize the unregister and register so they need
2045  * to be queued as separate tasks.
2046  */
2047  if (queue_unregister(state)) {
2048  ast_cli(a->fd, "Failed to queue unregistration\n");
2049  } else if (queue_register(state)) {
2050  ast_cli(a->fd, "Failed to queue registration\n");
2051  }
2052 
2053  ao2_ref(state, -1);
2054  return CLI_SUCCESS;
2055 }
2056 
2057 static int ami_unregister(struct mansession *s, const struct message *m)
2058 {
2059  const char *registration_name = astman_get_header(m, "Registration");
2061 
2062  if (ast_strlen_zero(registration_name)) {
2063  astman_send_error(s, m, "Registration parameter missing.");
2064  return 0;
2065  }
2066 
2067  if (strcmp(registration_name, "*all") == 0) {
2068  unregister_all();
2069  astman_send_ack(s, m, "Unregistrations queued.");
2070  return 0;
2071  }
2072 
2073  state = get_state(registration_name);
2074  if (!state) {
2075  astman_send_error(s, m, "Unable to retrieve registration entry\n");
2076  return 0;
2077  }
2078 
2079  if (queue_unregister(state)) {
2080  astman_send_ack(s, m, "Failed to queue unregistration");
2081  } else {
2082  astman_send_ack(s, m, "Unregistration sent");
2083  }
2084 
2085  ao2_ref(state, -1);
2086  return 0;
2087 }
2088 
2089 static int ami_register(struct mansession *s, const struct message *m)
2090 {
2091  const char *registration_name = astman_get_header(m, "Registration");
2093 
2094  if (ast_strlen_zero(registration_name)) {
2095  astman_send_error(s, m, "Registration parameter missing.");
2096  return 0;
2097  }
2098 
2099  if (strcmp(registration_name, "*all") == 0) {
2100  reregister_all();
2101  astman_send_ack(s, m, "Reregistrations queued.");
2102  return 0;
2103  }
2104 
2105  state = get_state(registration_name);
2106  if (!state) {
2107  astman_send_error(s, m, "Unable to retrieve registration entry\n");
2108  return 0;
2109  }
2110 
2111  /* We need to serialize the unregister and register so they need
2112  * to be queued as separate tasks.
2113  */
2114  if (queue_unregister(state)) {
2115  astman_send_ack(s, m, "Failed to queue unregistration");
2116  } else if (queue_register(state)) {
2117  astman_send_ack(s, m, "Failed to queue unregistration");
2118  } else {
2119  astman_send_ack(s, m, "Reregistration sent");
2120  }
2121 
2122  ao2_ref(state, -1);
2123  return 0;
2124 }
2125 
2127  struct ast_sip_ami *ami;
2131 };
2132 
2133 static int ami_outbound_registration_task(void *obj)
2134 {
2135  struct sip_ami_outbound *ami = obj;
2136  struct ast_str *buf;
2138 
2139  buf = ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami);
2140  if (!buf) {
2141  return -1;
2142  }
2143 
2145 
2147  pjsip_regc_info info;
2148 
2149  if (state->client_state->status == SIP_REGISTRATION_REGISTERED) {
2150  ++ami->registered;
2151  } else {
2152  ++ami->not_registered;
2153  }
2154 
2155  ast_str_append(&buf, 0, "Status: %s\r\n",
2156  sip_outbound_registration_status_str(state->client_state->status));
2157 
2158  pjsip_regc_get_info(state->client_state->client, &info);
2159  ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg);
2160  ao2_ref(state, -1);
2161  }
2162 
2163  astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
2164  ast_free(buf);
2165 
2167 }
2168 
2169 static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
2170 {
2171  struct sip_ami_outbound *ami = arg;
2172 
2173  ami->registration = obj;
2175 }
2176 
2178  const struct message *m)
2179 {
2180  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2181  struct sip_ami_outbound ami_outbound = { .ami = &ami };
2182  struct ao2_container *regs;
2183 
2184  regs = get_registrations();
2185  if (!regs) {
2186  astman_send_error(s, m, "Unable to retrieve "
2187  "outbound registrations\n");
2188  return -1;
2189  }
2190 
2191  astman_send_listack(s, m, "Following are Events for each Outbound registration",
2192  "start");
2193 
2195 
2196  astman_send_list_complete_start(s, m, "OutboundRegistrationDetailComplete",
2197  ami_outbound.registered + ami_outbound.not_registered);
2198  astman_append(s,
2199  "Registered: %d\r\n"
2200  "NotRegistered: %d\r\n",
2201  ami_outbound.registered,
2202  ami_outbound.not_registered);
2204 
2205  ao2_ref(regs, -1);
2206  return 0;
2207 }
2208 
2209 static struct ao2_container *cli_get_container(const char *regex)
2210 {
2212  struct ao2_container *s_container;
2213 
2215  if (!container) {
2216  return NULL;
2217  }
2218 
2221  if (!s_container) {
2222  return NULL;
2223  }
2224 
2225  if (ao2_container_dup(s_container, container, 0)) {
2226  ao2_ref(s_container, -1);
2227  return NULL;
2228  }
2229 
2230  return s_container;
2231 }
2232 
2233 static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
2234 {
2235  ao2_callback(container, OBJ_NODATA, callback, args);
2236 
2237  return 0;
2238 }
2239 
2240 static void *cli_retrieve_by_id(const char *id)
2241 {
2242  struct ao2_container *states;
2243  void *obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
2244 
2245  if (!obj) {
2246  /* if the object no longer exists then remove its state */
2247  states = ao2_global_obj_ref(current_states);
2248  if (states) {
2249  ao2_find(states, id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
2250  ao2_ref(states, -1);
2251  }
2252  }
2253 
2254  return obj;
2255 }
2256 
2257 static int cli_print_header(void *obj, void *arg, int flags)
2258 {
2259  struct ast_sip_cli_context *context = arg;
2260 
2261  ast_assert(context->output_buffer != NULL);
2262 
2263  ast_str_append(&context->output_buffer, 0,
2264  " <Registration/ServerURI..............................> <Auth..........> <Status.......>\n");
2265 
2266  return 0;
2267 }
2268 
2269 static int cli_print_body(void *obj, void *arg, int flags)
2270 {
2271  struct sip_outbound_registration *registration = obj;
2272  struct ast_sip_cli_context *context = arg;
2273  const char *id = ast_sorcery_object_get_id(registration);
2275 #define REGISTRATION_URI_FIELD_LEN 53
2276 
2277  ast_assert(context->output_buffer != NULL);
2278 
2279  ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-16s %-16s\n",
2280  id,
2281  (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2282  (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2286  : "n/a",
2287  (state ? sip_outbound_registration_status_str(state->client_state->status) : "Unregistered"));
2288  ao2_cleanup(state);
2289 
2290  if (context->show_details
2291  || (context->show_details_only_level_0 && context->indent_level == 0)) {
2292  ast_str_append(&context->output_buffer, 0, "\n");
2294  }
2295 
2296  return 0;
2297 }
2298 
2299 /*
2300  * A function pointer to callback needs to be within the
2301  * module in order to avoid problems with an undefined
2302  * symbol when the module is loaded.
2303  */
2304 static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2305 {
2306  return ast_sip_cli_traverse_objects(e, cmd, a);
2307 }
2308 
2309 static struct ast_cli_entry cli_outbound_registration[] = {
2310  AST_CLI_DEFINE(cli_unregister, "Unregisters outbound registration target"),
2311  AST_CLI_DEFINE(cli_register, "Registers an outbound registration target"),
2312  AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
2313  .command = "pjsip list registrations",
2314  .usage = "Usage: pjsip list registrations [ like <pattern> ]\n"
2315  " List the configured PJSIP Registrations\n"
2316  " Optional regular expression pattern is used to filter the list.\n"),
2317  AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
2318  .command = "pjsip show registrations",
2319  .usage = "Usage: pjsip show registrations [ like <pattern> ]\n"
2320  " Show the configured PJSIP Registrations\n"
2321  " Optional regular expression pattern is used to filter the list.\n"),
2322  AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
2323  .command = "pjsip show registration",
2324  .usage = "Usage: pjsip show registration <id>\n"
2325  " Show the configured PJSIP Registration\n"),
2326 };
2327 
2329 
2330 static void auth_observer(const char *type)
2331 {
2332  struct sip_outbound_registration *registration;
2334  struct ao2_container *regs;
2335  const char *registration_id;
2336  struct ao2_iterator i;
2337 
2338  ast_debug(4, "Auths updated. Checking for any outbound registrations that are in permanent rejected state so they can be retried\n");
2339 
2340  regs = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
2342  if (!regs || ao2_container_count(regs) == 0) {
2343  ao2_cleanup(regs);
2344  return;
2345  }
2346 
2347  i = ao2_iterator_init(regs, 0);
2348  for (; (registration = ao2_iterator_next(&i)); ao2_ref(registration, -1)) {
2349  registration_id = ast_sorcery_object_get_id(registration);
2350  state = get_state(registration_id);
2351  if (state && state->client_state->status == SIP_REGISTRATION_REJECTED_PERMANENT) {
2352  ast_debug(4, "Trying outbound registration '%s' again\n", registration_id);
2353 
2354  if (ast_sip_push_task(state->client_state->serializer,
2356  ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", registration_id);
2357  ao2_ref(state, -1);
2358  }
2359  }
2360  ao2_cleanup(state);
2361  }
2363  ao2_cleanup(regs);
2364 }
2365 
2366 static const struct ast_sorcery_observer observer_callbacks_auth = {
2367  .loaded = auth_observer,
2368 };
2369 
2370 static int check_state(void *obj, void *arg, int flags)
2371 {
2372  struct sip_outbound_registration_state *state = obj;
2373  struct sip_outbound_registration *registration;
2374 
2375  registration = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration",
2376  ast_sorcery_object_get_id(state->registration));
2377  if (!registration) {
2378  /* This is a dead registration */
2379  return CMP_MATCH;
2380  }
2381 
2382  ao2_ref(registration, -1);
2383  return 0;
2384 }
2385 
2386 /*!
2387  * \internal
2388  * \brief Observer to purge dead registration states.
2389  *
2390  * \param name Module name owning the sorcery instance.
2391  * \param sorcery Instance being observed.
2392  * \param object_type Name of object being observed.
2393  * \param reloaded Non-zero if the object is being reloaded.
2394  */
2395 static void registration_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
2396 {
2397  struct ao2_container *states;
2398 
2399  if (strcmp(object_type, "registration")) {
2400  /* Not interested */
2401  return;
2402  }
2403 
2404  states = ao2_global_obj_ref(current_states);
2405  if (!states) {
2406  /* Global container has gone. Likely shutting down. */
2407  return;
2408  }
2409 
2410  /*
2411  * Refresh the current configured registrations. We don't need to hold
2412  * onto the objects, as the apply handler will cause their states to
2413  * be created appropriately.
2414  */
2416 
2417  /* Now to purge dead registrations. */
2419  ao2_ref(states, -1);
2420 }
2421 
2424 };
2425 
2426 static void registration_deleted_observer(const void *obj)
2427 {
2428  const struct sip_outbound_registration *registration = obj;
2429  struct ao2_container *states;
2430 
2431  states = ao2_global_obj_ref(current_states);
2432  if (!states) {
2433  /* Global container has gone. Likely shutting down. */
2434  return;
2435  }
2436 
2438 
2439  ao2_ref(states, -1);
2440 }
2441 
2442 static const struct ast_sorcery_observer registration_observer = {
2444 };
2445 
2446 static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
2447 {
2448  /* This callback is only concerned with network change messages from the system topic. */
2450  return;
2451  }
2452  ast_debug(3, "Received network change event\n");
2453 
2454  reregister_all();
2455 }
2456 
2457 static int unload_module(void)
2458 {
2459  int remaining;
2460 
2462 
2463  ast_manager_unregister("PJSIPShowRegistrationsOutbound");
2464  ast_manager_unregister("PJSIPUnregister");
2465  ast_manager_unregister("PJSIPRegister");
2466 
2469  cli_formatter = NULL;
2470 
2472 
2475 
2477 
2478  ao2_global_obj_release(current_states);
2479 
2481 
2482  /* Wait for registration serializers to get destroyed. */
2483  ast_debug(2, "Waiting for registration transactions to complete for unload.\n");
2485  if (remaining) {
2486  /*
2487  * NOTE: We probably have a sip_outbound_registration_client_state
2488  * ref leak if the remaining count cannot reach zero after a few
2489  * minutes of trying to unload.
2490  */
2491  ast_log(LOG_WARNING, "Unload incomplete. Could not stop %d outbound registrations. Try again later.\n",
2492  remaining);
2493  return -1;
2494  }
2495 
2496  ast_debug(2, "Successful shutdown.\n");
2497 
2499  shutdown_group = NULL;
2500 
2501  return 0;
2502 }
2503 
2504 static int load_module(void)
2505 {
2506  struct ao2_container *new_states;
2507 
2509  if (!shutdown_group) {
2510  return AST_MODULE_LOAD_DECLINE;
2511  }
2512 
2513  /* Create outbound registration states container. */
2516  if (!new_states) {
2517  ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
2518  unload_module();
2519  return AST_MODULE_LOAD_DECLINE;
2520  }
2521  ao2_global_obj_replace_unref(current_states, new_states);
2522  ao2_ref(new_states, -1);
2523 
2524  /*
2525  * Register sorcery object descriptions.
2526  */
2527  ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_registration");
2528  ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
2529 
2531  unload_module();
2532  return AST_MODULE_LOAD_DECLINE;
2533  }
2534 
2535  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
2537  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
2538  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
2539  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));
2540  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
2541  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
2542  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
2543  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
2544  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));
2545  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));
2547  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));
2549  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
2550  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_outbound", "no", OPT_YESNO_T, 1, FLDSET(struct sip_outbound_registration, support_outbound));
2551  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));
2552  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));
2553 
2554  /*
2555  * Register sorcery observers.
2556  */
2561  || ast_sorcery_observer_add(ast_sip_get_sorcery(), "registration",
2563  ast_log(LOG_ERROR, "Unable to register observers.\n");
2564  unload_module();
2565  return AST_MODULE_LOAD_DECLINE;
2566  }
2567 
2568  /* Register how this module identifies endpoints. */
2570 
2571  /* Register CLI commands. */
2573  if (!cli_formatter) {
2574  ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
2575  unload_module();
2576  return AST_MODULE_LOAD_DECLINE;
2577  }
2578  cli_formatter->name = "registration";
2587 
2588  /* Register AMI actions. */
2592 
2593  /* Clear any previous statsd gauges in case we weren't shutdown cleanly */
2594  ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GAUGE, 0);
2595  ast_statsd_log("PJSIP.registrations.state.Registered", AST_STATSD_GAUGE, 0);
2596  ast_statsd_log("PJSIP.registrations.state.Unregistered", AST_STATSD_GAUGE, 0);
2597  ast_statsd_log("PJSIP.registrations.state.Rejected", AST_STATSD_GAUGE, 0);
2598 
2599  /* Load configuration objects */
2600  ast_sorcery_load_object(ast_sip_get_sorcery(), "registration");
2601 
2606 
2607  return AST_MODULE_LOAD_SUCCESS;
2608 }
2609 
2610 static int reload_module(void)
2611 {
2613  return 0;
2614 }
2615 
2616 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
2617  .support_level = AST_MODULE_SUPPORT_CORE,
2618  .load = load_module,
2619  .reload = reload_module,
2620  .unload = unload_module,
2621  .load_pri = AST_MODPRI_APP_DEPEND,
2622  .requires = "res_pjsip",
2623  .optional_modules = "res_statsd",
2624 );
jack_status_t status
Definition: app_jack.c:146
const char * str
Definition: app_jack.c:147
#define var
Definition: ast_expr2f.c:614
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
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
int() ao2_callback_fn(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1226
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
static int tmp()
Definition: bt_open.c:389
static PGresult * result
Definition: cel_pgsql.c:84
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
static struct registrations registrations
static int max_retries
Definition: chan_iax2.c:325
static const char type[]
Definition: chan_ooh323.c:109
enum sip_cc_notify_state state
Definition: chan_sip.c:966
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
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:3208
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3166
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:3244
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3198
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3252
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3087
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:2827
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7268
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:1933
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:1923
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:1999
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:2013
#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_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_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
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:546
#define EVENT_FLAG_REPORTING
Definition: manager.h:84
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_APP_DEPEND
Definition: module.h:328
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
def info(msg)
Core PBX routines and definitions.
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
static char url[512]
static int reload(void)
struct stasis_forward * sub
Definition: res_corosync.c:240
struct ao2_container * container
Definition: res_fax.c:501
int ast_sip_transport_state_set_transport(const char *transport_name, pjsip_transport *transport)
Sets the PJSIP transport on a child transport.
struct ast_sip_service_route_vector * ast_sip_service_route_vector_alloc(void)
Allocate a vector of service routes.
void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
Clean up retrieved auth structures from memory.
int ast_sip_format_auths_ami(const struct ast_sip_auth_vector *auths, struct ast_sip_ami *ami)
Format auth details for AMI.
Definition: config_auth.c:195
int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, pjsip_tx_data *tdata, pjsip_tx_data **new_request)
Create a response to an authentication challenge.
Definition: res_pjsip.c:207
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
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.
void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
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.
int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Register a SIP endpoint identifier.
Definition: res_pjsip.c:303
int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
Retrieve relevant SIP auth structures from sorcery.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:513
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:308
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:2035
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.
void ast_sip_tpselector_unref(pjsip_tpselector *selector)
Unreference a pjsip_tpselector.
Definition: res_pjsip.c:782
enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *ao2_data)
Register a reliable transport shutdown monitor callback.
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:456
void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *vector)
Free contents of an auth vector.
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:752
int ast_sip_auth_vector_init(struct ast_sip_auth_vector *vector, const char *auth_names)
Initialize an auth vector with the configured values.
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:1666
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
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_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
Prints a sorcery object's ast_variable list.
Definition: pjsip_cli.c:36
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 char * cli_complete_registration(const char *line, const char *word, int pos, int state)
static int sip_outbound_registration_regc_alloc(void *data)
Helper function that allocates a pjsip registration client and configures it.
static void * cli_retrieve_by_id(const char *id)
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 save_response_fields_to_transport(struct registration_response *response)
#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 char * my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 void * sip_outbound_registration_alloc(const char *name)
Allocator function for registration information.
#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 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 int ami_register(struct mansession *s, const struct message *m)
static pj_str_t PATH_NAME
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 * sip_outbound_registration_status_str(enum sip_outbound_registration_status state)
static char * cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct pjsip_param * get_uri_option_line(const void *uri)
static void registration_response_destroy(void *obj)
Registration response structure destructor.
static void sip_outbound_registration_client_state_destroy(void *obj)
Destructor function for client registration state.
static int reload_module(void)
static const char * fetch_google_access_token(const struct ast_sip_auth *auth)
Get google oauth2 access token using refresh token.
static int reregister_immediately_cb(void *obj)
static int add_to_supported_header(pjsip_tx_data *tdata, pj_str_t *name)
Helper function to add string to Supported header.
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 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 registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name)
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 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 sip_outbound_registration_state * get_state(const char *id)
static struct ao2_container * get_registrations(void)
static void sip_outbound_registration_destroy(void *obj)
Destructor function for registration information.
static pj_str_t OUTBOUND_NAME
static struct stasis_subscription * network_change_sub
static struct ao2_container * cli_get_container(const char *regex)
static int load_module(void)
static int cli_print_body(void *obj, void *arg, int flags)
static struct sip_outbound_registration_state * sip_outbound_registration_state_alloc(struct sip_outbound_registration *registration)
Allocator function for registration state.
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 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 char * cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_sip_cli_formatter_entry * cli_formatter
static int check_state(void *obj, void *arg, int flags)
static int sip_outbound_registration_perform(void *data)
Helper function which performs a single registration.
static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
Callback function for outbound registration client.
static int registration_state_hash(const void *obj, const int flags)
hashing function for state objects
static int monitor_matcher(void *a, void *b)
static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
Helper function which cancels the timer on a client.
static void registration_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
static int ami_outbound_registration_task(void *obj)
static int add_configured_supported_headers(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
Helper function to add configured supported headers.
static struct ast_sorcery * sorcery
int ast_sip_validate_uri_length(const char *uri)
Definition: location.c:528
#define NULL
Definition: resample.c:96
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
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:2418
#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_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
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:1949
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
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:2386
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
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:2459
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
#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
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
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition: sorcery.c:2435
#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
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1136
@ 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:1025
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:1079
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
void ast_system_publish_registry(const char *channeltype, const char *username, const char *domain, const char *status, const char *cause)
Publish a channel driver outgoing registration message.
struct stasis_topic * ast_system_topic(void)
A Stasis Message Bus API topic which publishes messages regarding system changes.
struct stasis_message_type * ast_network_change_type(void)
A stasis_message_type for network changes.
void ast_statsd_log_string_va(const char *metric_name, const char *metric_type, const char *value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition: res_statsd.c:186
#define AST_STATSD_GAUGE
Support for publishing to a statsd server.
Definition: statsd.h:32
void ast_statsd_log_string(const char *metric_name, const char *metric_type, const char *value, double sample_rate)
Send a stat to the configured statsd server.
Definition: res_statsd.c:117
void ast_statsd_log(const char *metric_name, const char *metric_type, intmax_t value)
Send a stat to the configured statsd server.
Definition: res_statsd.c:232
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1117
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
#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:1237
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:227
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:849
Abstract JSON element (object, array, string, int, ...).
AMI variable container.
Definition: res_pjsip.h:2819
struct mansession * s
Definition: res_pjsip.h:2821
const struct message * m
Definition: res_pjsip.h:2823
const ast_string_field oauth_clientid
Definition: res_pjsip.h:481
const ast_string_field oauth_secret
Definition: res_pjsip.h:481
const ast_string_field realm
Definition: res_pjsip.h:481
const ast_string_field auth_user
Definition: res_pjsip.h:481
const ast_string_field refresh_token
Definition: res_pjsip.h:481
const ast_string_field auth_pass
Definition: res_pjsip.h:481
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
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
const char * name
Definition: res_pjsip_cli.h:58
ao2_callback_fn * print_body
Definition: res_pjsip_cli.h:62
An entity responsible for identifying the source of a SIP message.
Definition: res_pjsip.h:1073
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:1078
An entity with which Asterisk communicates.
Definition: res_pjsip.h:854
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:604
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
Structure for variables, used for configurations and for channel variables.
Definition: search.h:40
struct header * next
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:1632
Structure for registration response.
struct sip_outbound_registration_client_state * client_state
Outbound registration client state.
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.
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.
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.
unsigned int retry_interval
Interval at which retries should occur for temporal responses.
unsigned int destroy
Registration should be destroyed after completion of transaction.
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.
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.
unsigned int support_path
Whether Path support is enabled.
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.
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
struct ast_serializer_shutdown_group * ast_serializer_shutdown_group_alloc(void)
Create a serializer group shutdown control object.
Definition: threadpool.c:1229
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
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
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:936
#define ast_assert(a)
Definition: utils.h:734
long int ast_random(void)
Definition: main/utils.c:2210
#define ARRAY_LEN(a)
Definition: utils.h:661
Vector container support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#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_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680