Asterisk - The Open Source Telephony Project  GIT-master-a1fa8df
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  /*! \bried 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);
754  status_new = sip_outbound_registration_status_str(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) &&
875  !client_state->auth_rejection_permanent) ||
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 
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 
920 
921  ao2_ref(state->client_state, +1);
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  *
937  * \return Nothing
938  */
940 {
941  const char *registration_name = obj;
943 
944  state = get_state(registration_name);
945  if (!state) {
946  /* Registration no longer exists or shutting down. */
947  return;
948  }
950  ao2_ref(state, -1);
951  }
952 }
953 
954 static int monitor_matcher(void *a, void *b)
955 {
956  char *ma = a;
957  char *mb = b;
958 
959  return strcmp(ma, mb) == 0;
960 }
961 
962 static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name)
963 {
964  char *monitor;
965 
966  if (!PJSIP_TRANSPORT_IS_RELIABLE(transport)) {
967  return;
968  }
969  monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL,
971  if (!monitor) {
972  return;
973  }
974  strcpy(monitor, registration_name);/* Safe */
975 
976  /*
977  * We'll ignore if the transport has already been shutdown before we
978  * register the monitor. We might get into a message spamming infinite
979  * loop of registration, shutdown, reregistration...
980  */
982  monitor);
983  ao2_ref(monitor, -1);
984 }
985 
987 {
988  static const pj_str_t associated_uri_str = { "P-Associated-URI", 16 };
989  static const pj_str_t service_route_str = { "Service-Route", 13 };
990  pjsip_hdr *header = NULL;
991  pjsip_msg *msg = response->rdata->msg_info.msg;
992  struct ast_sip_service_route_vector *service_routes = NULL;
993 
994  /* If no transport is specified then we can't update any */
995  if (ast_strlen_zero(response->client_state->transport_name)) {
996  return;
997  }
998 
999  ast_sip_transport_state_set_transport(response->client_state->transport_name, response->rdata->tp_info.transport);
1000 
1001  while ((header = pjsip_msg_find_hdr_by_name(msg, &service_route_str, header ? header->next : NULL))) {
1002  char *service_route;
1003  size_t size;
1004 
1005  /* The below code takes the approach that if we can't store all service routes then we
1006  * store none at all. This gives a predictable failure condition instead of storing a
1007  * partial list and having partial route headers.
1008  */
1009  size = pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1;
1010  service_route = ast_malloc(size);
1011  if (!service_route) {
1012  if (service_routes) {
1013  ast_sip_service_route_vector_destroy(service_routes);
1014  service_routes = NULL;
1015  }
1016  break;
1017  }
1018 
1019  ast_copy_pj_str(service_route, &((pjsip_generic_string_hdr*)header)->hvalue, size);
1020 
1021  if (!service_routes) {
1022  service_routes = ast_sip_service_route_vector_alloc();
1023  if (!service_routes) {
1024  ast_free(service_route);
1025  break;
1026  }
1027  }
1028 
1029  if (AST_VECTOR_APPEND(service_routes, service_route)) {
1030  ast_free(service_route);
1031  ast_sip_service_route_vector_destroy(service_routes);
1032  service_routes = NULL;
1033  break;
1034  }
1035  }
1036 
1037  /* If any service routes were handled then store them on the transport */
1038  if (service_routes) {
1040  }
1041 
1042  /* If an associated URI is present in the response we need to use it on any outgoing
1043  * traffic on the transport.
1044  */
1045  header = pjsip_msg_find_hdr_by_name(msg, &associated_uri_str, NULL);
1046  if (header) {
1047  char value[pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1];
1048 
1049  ast_copy_pj_str(value, &((pjsip_generic_string_hdr*)header)->hvalue, sizeof(value));
1051  }
1052 }
1053 
1054 
1055 /*! \brief Callback function for handling a response to a registration attempt */
1056 static int handle_registration_response(void *data)
1057 {
1058  struct registration_response *response = data;
1059  pjsip_regc_info info;
1060  char server_uri[PJSIP_MAX_URL_SIZE];
1061  char client_uri[PJSIP_MAX_URL_SIZE];
1062 
1063  if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
1064  ao2_ref(response, -1);
1065  return 0;
1066  }
1067 
1068  pjsip_regc_get_info(response->client_state->client, &info);
1069  ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
1070  ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
1071 
1072  ast_debug(1, "Processing REGISTER response %d from server '%s' for client '%s'\n",
1073  response->code, server_uri, client_uri);
1074 
1075  if (response->code == 408 || response->code == 503) {
1076  if ((ast_sip_failover_request(response->old_request))) {
1077  int res = registration_client_send(response->client_state, response->old_request);
1078  /* The tdata ref was stolen */
1079  response->old_request = NULL;
1080  if (res == PJ_SUCCESS) {
1081  ao2_ref(response, -1);
1082  return 0;
1083  }
1084  }
1085  } else if ((response->code == 401 || response->code == 407)
1086  && (!response->client_state->auth_attempted
1087  || response->rdata->msg_info.cseq->cseq != response->client_state->auth_cseq)) {
1088  int res;
1089  pjsip_cseq_hdr *cseq_hdr;
1090  pjsip_tx_data *tdata;
1091 
1093  response->rdata, response->old_request, &tdata)) {
1094  response->client_state->auth_attempted = 1;
1095  ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
1096  server_uri, client_uri);
1097  pjsip_tx_data_add_ref(tdata);
1098  res = registration_client_send(response->client_state, tdata);
1099 
1100  /* Save the cseq that actually got sent. */
1101  cseq_hdr = (pjsip_cseq_hdr *) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ,
1102  NULL);
1103  response->client_state->auth_cseq = cseq_hdr->cseq;
1104  pjsip_tx_data_dec_ref(tdata);
1105  if (res == PJ_SUCCESS) {
1106  ao2_ref(response, -1);
1107  return 0;
1108  }
1109  } else {
1110  ast_log(LOG_WARNING, "Failed to create authenticated REGISTER request to server '%s' from client '%s'\n",
1111  server_uri, client_uri);
1112  }
1113  /* Otherwise, fall through so the failure is processed appropriately */
1114  }
1115 
1116  response->client_state->auth_attempted = 0;
1117 
1118  if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
1119  /* Check if this is in regards to registering or unregistering */
1120  if (response->expiration) {
1121  int next_registration_round;
1122 
1123  /* If the registration went fine simply reschedule registration for the future */
1124  ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
1126  response->client_state->retries = 0;
1127  next_registration_round = response->expiration - REREGISTER_BUFFER_TIME;
1128  if (next_registration_round < 0) {
1129  /* Re-register immediately. */
1130  next_registration_round = 0;
1131  }
1132  schedule_registration(response->client_state, next_registration_round);
1133 
1134  /* See if we should monitor for transport shutdown */
1135  registration_transport_monitor_setup(response->rdata->tp_info.transport,
1136  response->client_state->registration_name);
1137  } else {
1138  ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
1140  ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport,
1142  monitor_matcher);
1143  }
1144 
1146  } else if (response->client_state->destroy) {
1147  /* We need to deal with the pending destruction instead. */
1148  } else if (response->retry_after) {
1149  /* If we have been instructed to retry after a period of time, schedule it as such */
1150  schedule_retry(response, response->retry_after, server_uri, client_uri);
1151  } else if (response->client_state->retry_interval
1152  && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
1153  if (response->client_state->retries == response->client_state->max_retries) {
1154  /* If we received enough temporal responses to exceed our maximum give up permanently */
1156  ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
1157  server_uri, client_uri);
1158  } else {
1159  /* On the other hand if we can still try some more do so */
1160  response->client_state->retries++;
1161  schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
1162  }
1163  } else {
1164  if (response->code == 403
1166  && response->client_state->retries < response->client_state->max_retries) {
1167  /* A forbidden response retry interval is configured and there are retries remaining */
1169  response->client_state->retries++;
1171  ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1172  server_uri, client_uri, response->client_state->forbidden_retry_interval);
1173  } else if (response->client_state->fatal_retry_interval
1174  && response->client_state->retries < response->client_state->max_retries) {
1175  /* Some kind of fatal failure response received, so retry according to configured interval */
1177  response->client_state->retries++;
1179  ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1180  response->code, server_uri, client_uri, response->client_state->fatal_retry_interval);
1181  } else {
1182  /* Finally if there's no hope of registering give up */
1184  if (response->rdata) {
1185  ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
1186  response->code, server_uri, client_uri);
1187  } else {
1188  ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
1189  }
1190  }
1191  }
1192 
1193  ast_system_publish_registry("PJSIP", client_uri, server_uri,
1195 
1196  if (response->client_state->destroy) {
1197  /* We have a pending deferred destruction to complete now. */
1198  ao2_ref(response->client_state, +1);
1200  }
1201 
1202  ao2_ref(response, -1);
1203  return 0;
1204 }
1205 
1206 /*! \brief Callback function for outbound registration client */
1207 static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
1208 {
1209  struct sip_outbound_registration_client_state *client_state = param->token;
1210  struct registration_response *response;
1211  int *callback_invoked;
1212 
1213  callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
1214 
1215  ast_assert(callback_invoked != NULL);
1216  ast_assert(client_state != NULL);
1217 
1218  *callback_invoked = 1;
1219 
1220  response = ao2_alloc(sizeof(*response), registration_response_destroy);
1221  if (!response) {
1222  ao2_ref(client_state, -1);
1223  return;
1224  }
1225  response->code = param->code;
1226  response->expiration = param->expiration;
1227  /*
1228  * Transfer client_state reference to response so the
1229  * nominal path will not dec the client_state ref in this
1230  * pjproject callback thread.
1231  */
1232  response->client_state = client_state;
1233 
1234  ast_debug(1, "Received REGISTER response %d(%.*s)\n",
1235  param->code, (int) param->reason.slen, param->reason.ptr);
1236 
1237  if (param->rdata) {
1238  struct pjsip_retry_after_hdr *retry_after;
1239  pjsip_transaction *tsx;
1240 
1241  retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER,
1242  NULL);
1243  response->retry_after = retry_after ? retry_after->ivalue : 0;
1244 
1245  /*
1246  * If we got a response from the server, we have to use the tdata
1247  * from the transaction, not the tdata saved when we sent the
1248  * request. If we use the saved tdata, we won't process responses
1249  * like 423 Interval Too Brief correctly and we'll wind up sending
1250  * the bad Expires value again.
1251  */
1252  pjsip_tx_data_dec_ref(client_state->last_tdata);
1253 
1254  tsx = pjsip_rdata_get_tsx(param->rdata);
1255  response->old_request = tsx->last_tx;
1256  pjsip_tx_data_add_ref(response->old_request);
1257  pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
1258  } else {
1259  /* old_request steals the reference */
1260  response->old_request = client_state->last_tdata;
1261  }
1262  client_state->last_tdata = NULL;
1263 
1264  /*
1265  * Transfer response reference to serializer task so the
1266  * nominal path will not dec the response ref in this
1267  * pjproject callback thread.
1268  */
1269  if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
1270  ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
1271  ao2_cleanup(response);
1272  }
1273 }
1274 
1275 /*! \brief Destructor function for registration state */
1277 {
1278  struct sip_outbound_registration_state *state = obj;
1279 
1280  ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n",
1281  state->registration ? state->registration->server_uri : "",
1282  state->registration ? state->registration->client_uri : "");
1283  ao2_cleanup(state->registration);
1284 
1285  if (!state->client_state) {
1286  /* Nothing to do */
1287  } else if (!state->client_state->serializer) {
1288  ao2_ref(state->client_state, -1);
1289  } else if (ast_sip_push_task(state->client_state->serializer,
1291  ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
1292  ao2_ref(state->client_state, -1);
1293  }
1294 }
1295 
1296 /*! \brief Destructor function for client registration state */
1298 {
1299  struct sip_outbound_registration_client_state *client_state = obj;
1300 
1301  ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0);
1302  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
1304 
1306  ast_free(client_state->transport_name);
1307  ast_free(client_state->registration_name);
1308  if (client_state->last_tdata) {
1309  pjsip_tx_data_dec_ref(client_state->last_tdata);
1310  }
1311 }
1312 
1313 /*! \brief Allocator function for registration state */
1315 {
1317  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1318 
1319  state = ao2_alloc(sizeof(*state), sip_outbound_registration_state_destroy);
1320  if (!state) {
1321  return NULL;
1322  }
1323  state->client_state = ao2_alloc(sizeof(*state->client_state),
1325  if (!state->client_state) {
1326  ao2_cleanup(state);
1327  return NULL;
1328  }
1329 
1331  pj_timer_entry_init(&state->client_state->timer, 0, state->client_state,
1333  state->client_state->transport_name = ast_strdup(registration->transport);
1335  ast_strdup(ast_sorcery_object_get_id(registration));
1336 
1337  ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0);
1338  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
1340 
1341  if (!state->client_state->transport_name
1342  || !state->client_state->registration_name) {
1343  ao2_cleanup(state);
1344  return NULL;
1345  }
1346 
1347  /* Create name with seq number appended. */
1348  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outreg/%s",
1349  ast_sorcery_object_get_id(registration));
1350 
1352  shutdown_group);
1353  if (!state->client_state->serializer) {
1354  ao2_cleanup(state);
1355  return NULL;
1356  }
1357 
1358  state->registration = ao2_bump(registration);
1359  return state;
1360 }
1361 
1362 /*! \brief Destructor function for registration information */
1364 {
1365  struct sip_outbound_registration *registration = obj;
1366 
1368 
1369  ast_string_field_free_memory(registration);
1370 }
1371 
1372 /*! \brief Allocator function for registration information */
1373 static void *sip_outbound_registration_alloc(const char *name)
1374 {
1375  struct sip_outbound_registration *registration;
1376 
1377  registration = ast_sorcery_generic_alloc(sizeof(*registration),
1379  if (!registration || ast_string_field_init(registration, 256)) {
1380  ao2_cleanup(registration);
1381  return NULL;
1382  }
1383 
1384  return registration;
1385 }
1386 
1387 /*! \brief Helper function which populates a pj_str_t with a contact header */
1388 static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user,
1389  const pj_str_t *target, pjsip_tpselector *selector, const char *line, const char *header_params)
1390 {
1391  pj_str_t tmp, local_addr;
1392  pjsip_uri *uri;
1393  pjsip_sip_uri *sip_uri;
1394  pjsip_transport_type_e type;
1395  int local_port;
1396 
1397  pj_strdup_with_null(pool, &tmp, target);
1398 
1399  if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
1400  (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
1401  return -1;
1402  }
1403 
1404  sip_uri = pjsip_uri_get_uri(uri);
1405 
1406  type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
1407  if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
1408  if (type == PJSIP_TRANSPORT_UNSPECIFIED
1409  || !(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE)) {
1410  type = PJSIP_TRANSPORT_TLS;
1411  }
1412  } else if (!sip_uri->transport_param.slen) {
1413  type = PJSIP_TRANSPORT_UDP;
1414  } else if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
1415  return -1;
1416  }
1417 
1418  if (pj_strchr(&sip_uri->host, ':')) {
1419  type |= PJSIP_TRANSPORT_IPV6;
1420  }
1421 
1422  if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
1423  pool, type, selector, &local_addr, &local_port) != PJ_SUCCESS) {
1424  return -1;
1425  }
1426 
1427  if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
1428  type |= PJSIP_TRANSPORT_IPV6;
1429  }
1430 
1431  contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
1432  contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
1433  "<%s:%s@%s%.*s%s:%d%s%s%s%s>%s%s",
1434  ((pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) && PJSIP_URI_SCHEME_IS_SIPS(uri)) ? "sips" : "sip",
1435  user,
1436  (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
1437  (int)local_addr.slen,
1438  local_addr.ptr,
1439  (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
1440  local_port,
1441  (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
1442  (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "",
1443  !ast_strlen_zero(line) ? ";line=" : "",
1444  S_OR(line, ""),
1445  !ast_strlen_zero(header_params) ? ";" : "",
1446  S_OR(header_params, ""));
1447 
1448  return 0;
1449 }
1450 
1451 /*!
1452  * \internal
1453  * \brief Check if a registration can be reused
1454  *
1455  * This checks if the existing outbound registration's configuration differs from a newly-applied
1456  * outbound registration to see if the applied one.
1457  *
1458  * \param existing The pre-existing outbound registration
1459  * \param applied The newly-created registration
1460  */
1462  struct sip_outbound_registration *applied)
1463 {
1464  int rc = 1;
1466  struct ast_variable *ve = ast_sorcery_objectset_create(sorcery, existing);
1467  struct ast_variable *va = ast_sorcery_objectset_create(sorcery, applied);
1468  struct ast_variable *vc = NULL;
1469 
1470  if (ast_sorcery_changeset_create(ve, va, &vc) || vc != NULL) {
1471  rc = 0;
1472  ast_debug(4, "Registration '%s' changed. Can't re-use.\n", ast_sorcery_object_get_id(existing));
1473  } else {
1474  ast_debug(4, "Registration '%s' didn't change. Can re-use\n", ast_sorcery_object_get_id(existing));
1475  }
1476 
1480 
1481  return rc;
1482 }
1483 
1484 /* \brief Get google oauth2 access token using refresh token */
1485 static const char *fetch_google_access_token(const struct ast_sip_auth *auth)
1486 {
1487  char *cmd = NULL;
1488  const char *token;
1489  const char *url = "https://www.googleapis.com/oauth2/v3/token";
1490  char buf[4096];
1491  int res;
1492  struct ast_json_error error;
1493  struct ast_json *json;
1494 
1495  /* set timeout to be shorter than default 180s (also checks func_curl is available) */
1496  if (ast_func_write(NULL, "CURLOPT(conntimeout)", "10")) {
1497  ast_log(LOG_ERROR, "CURL is unavailable. This is required for Google OAuth 2.0 authentication. Please ensure it is loaded.\n");
1498  return NULL;
1499  }
1500 
1501  res = ast_asprintf(&cmd,
1502  "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)",
1503  url, auth->oauth_clientid, auth->oauth_secret, auth->refresh_token);
1504  if (res < 0) {
1505  return NULL;
1506  }
1507 
1508  ast_debug(2, "Performing Google OAuth 2.0 authentication using command: %s\n", cmd);
1509 
1510  buf[0] = '\0';
1511  res = ast_func_read(NULL, cmd, buf, sizeof(buf));
1512  ast_free(cmd);
1513  if (res) {
1514  ast_log(LOG_ERROR, "Could not retrieve Google OAuth 2.0 authentication\n");
1515  return NULL;
1516  }
1517 
1518  ast_debug(2, "Google OAuth 2.0 authentication returned: %s\n", buf);
1519 
1520  json = ast_json_load_string(buf, &error);
1521  if (!json) {
1522  ast_log(LOG_ERROR, "Could not parse Google OAuth 2.0 authentication: %d(%d) %s: '%s'\n",
1523  error.line, error.column, error.text, buf);
1524  return NULL;
1525  }
1526 
1527  token = ast_json_string_get(ast_json_object_get(json, "access_token"));
1528  if (!token) {
1529  ast_log(LOG_ERROR, "Could not find Google OAuth 2.0 access_token in: '%s'\n",
1530  buf);
1531  }
1532  token = ast_strdup(token);
1533  ast_json_unref(json);
1534  return token;
1535 }
1536 
1537 /*!
1538  * \internal
1539  * \brief Set pjsip registration context with any authentication credentials that need to be
1540  * sent in the initial registration request
1541  *
1542  * \param regc The pjsip registration context
1543  * \param auth_vector The vector of configured authentication credentials
1544  */
1546  const struct ast_sip_auth_vector *auth_vector)
1547 {
1548  size_t auth_size = AST_VECTOR_SIZE(auth_vector);
1549  struct ast_sip_auth *auths[auth_size];
1550  const char *access_token;
1551  pjsip_cred_info auth_creds[1];
1552  pjsip_auth_clt_pref prefs;
1553  int res = 0;
1554  int idx;
1555 
1556  memset(auths, 0, sizeof(auths));
1557  if (ast_sip_retrieve_auths(auth_vector, auths)) {
1558  res = -1;
1559  goto cleanup;
1560  }
1561 
1562  for (idx = 0; idx < auth_size; ++idx) {
1563  switch (auths[idx]->type) {
1565  pj_cstr(&auth_creds[0].username, auths[idx]->auth_user);
1566  pj_cstr(&auth_creds[0].scheme, "Bearer");
1567  pj_cstr(&auth_creds[0].realm, auths[idx]->realm);
1568  ast_debug(2, "Obtaining Google OAuth access token\n");
1569  access_token = fetch_google_access_token(auths[idx]);
1570  if (!access_token) {
1571  ast_log(LOG_WARNING, "Obtaining Google OAuth access token failed\n");
1572  access_token = auths[idx]->auth_pass;
1573  res = -1;
1574  }
1575  ast_debug(2, "Setting data to '%s'\n", access_token);
1576 
1577  pj_cstr(&auth_creds[0].data, access_token);
1578  auth_creds[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
1579 
1580  pjsip_regc_set_credentials(regc, 1, auth_creds);
1581 
1582  /* for oauth, send auth without waiting for unauthorized response */
1583  prefs.initial_auth = PJ_TRUE;
1584  pj_cstr(&prefs.algorithm, "oauth");
1585  pjsip_regc_set_prefs(regc, &prefs);
1586 
1587  if (access_token != auths[idx]->auth_pass) {
1588  ast_free((char *) access_token);
1589  }
1590  break;
1591  default:
1592  /* other cases handled after receiving auth rejection */
1593  break;
1594  }
1595  }
1596 
1597 cleanup:
1598  ast_sip_cleanup_auths(auths, auth_size);
1599  return res;
1600 }
1601 
1602 /*! \brief Helper function that allocates a pjsip registration client and configures it */
1604 {
1605  struct sip_outbound_registration_state *state = data;
1607  ao2_bump(state->registration), ao2_cleanup);
1608  pj_pool_t *pool;
1609  pj_str_t tmp;
1610  pjsip_uri *uri;
1611  pj_str_t server_uri, client_uri, contact_uri;
1612  pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
1613 
1614  pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
1615  if (!pool) {
1616  ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
1618  return -1;
1619  }
1620 
1621  pj_strdup2_with_null(pool, &tmp, registration->server_uri);
1622  uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1623  if (!uri) {
1624  ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
1626  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1627  return -1;
1628  }
1629 
1630  pj_strdup2_with_null(pool, &tmp, registration->client_uri);
1631  uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1632  if (!uri) {
1633  ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
1635  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1636  return -1;
1637  }
1638 
1640  pj_strdup2_with_null(pool, &tmp, registration->outbound_proxy);
1641  uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1642  if (!uri) {
1643  ast_log(LOG_ERROR, "Invalid outbound proxy URI '%s' specified on outbound registration '%s'\n",
1645  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1646  return -1;
1647  }
1648  }
1649 
1650  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1651 
1652 
1653  ast_assert(state->client_state->client == NULL);
1654  if (pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state,
1656  &state->client_state->client) != PJ_SUCCESS) {
1657  return -1;
1658  }
1659 
1661  pjsip_regc_set_transport(state->client_state->client, &selector);
1662 
1664  pjsip_route_hdr route_set, *route;
1665  static const pj_str_t ROUTE_HNAME = { "Route", 5 };
1666  pj_str_t tmp;
1667 
1668  pj_list_init(&route_set);
1669 
1670  pj_strdup2_with_null(pjsip_regc_get_pool(state->client_state->client), &tmp,
1672  route = pjsip_parse_hdr(pjsip_regc_get_pool(state->client_state->client),
1673  &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL);
1674  if (!route) {
1675  ast_sip_tpselector_unref(&selector);
1676  return -1;
1677  }
1678  pj_list_insert_nodes_before(&route_set, route);
1679 
1680  pjsip_regc_set_route_set(state->client_state->client, &route_set);
1681  }
1682 
1683  if (state->registration->line) {
1684  ast_generate_random_string(state->client_state->line, sizeof(state->client_state->line));
1685  }
1686 
1687  pj_cstr(&server_uri, registration->server_uri);
1688 
1689  if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client),
1690  &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
1692  ast_sip_tpselector_unref(&selector);
1693  return -1;
1694  }
1695 
1696  ast_sip_tpselector_unref(&selector);
1697 
1698  pj_cstr(&client_uri, registration->client_uri);
1699  if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri,
1700  &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
1701  return -1;
1702  }
1703 
1704  return 0;
1705 }
1706 
1707 /*! \brief Helper function which performs a single registration */
1709 {
1710  struct sip_outbound_registration_state *state = data;
1711  struct sip_outbound_registration *registration = ao2_bump(state->registration);
1712  size_t i;
1713 
1714  /* Just in case the client state is being reused for this registration, free the auth information */
1716 
1718  for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
1719  char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
1720 
1721  if (name && AST_VECTOR_APPEND(&state->client_state->outbound_auths, name)) {
1722  ast_free(name);
1723  }
1724  }
1725  state->client_state->retry_interval = registration->retry_interval;
1727  state->client_state->fatal_retry_interval = registration->fatal_retry_interval;
1728  state->client_state->max_retries = registration->max_retries;
1729  state->client_state->retries = 0;
1730  state->client_state->support_path = registration->support_path;
1731  state->client_state->support_outbound = registration->support_outbound;
1733 
1734  pjsip_regc_update_expires(state->client_state->client, registration->expiration);
1735 
1736  schedule_registration(state->client_state, (ast_random() % 10) + 1);
1737 
1738  ao2_ref(registration, -1);
1739  ao2_ref(state, -1);
1740  return 0;
1741 }
1742 
1743 /*! \brief Apply function which finds or allocates a state structure */
1744 static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
1745 {
1746  RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup);
1749  struct sip_outbound_registration *applied = obj;
1750 
1751  if (!states) {
1752  /* Global container has gone. Likely shutting down. */
1753  return -1;
1754  }
1756 
1757  ast_debug(4, "Applying configuration to outbound registration '%s'\n", ast_sorcery_object_get_id(applied));
1758 
1759  if (ast_strlen_zero(applied->server_uri)) {
1760  ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'\n",
1761  ast_sorcery_object_get_id(applied));
1762  return -1;
1763  } else if (ast_sip_validate_uri_length(applied->server_uri)) {
1764  ast_log(LOG_ERROR, "Server URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
1765  ast_sorcery_object_get_id(applied));
1766  return -1;
1767  } else if (ast_strlen_zero(applied->client_uri)) {
1768  ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
1769  ast_sorcery_object_get_id(applied));
1770  return -1;
1771  } else if (ast_sip_validate_uri_length(applied->client_uri)) {
1772  ast_log(LOG_ERROR, "Client URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
1773  ast_sorcery_object_get_id(applied));
1774  return -1;
1775  } else if (applied->line && ast_strlen_zero(applied->endpoint)) {
1776  ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
1777  ast_sorcery_object_get_id(applied));
1778  return -1;
1779  } else if (!ast_strlen_zero(applied->endpoint) && !applied->line) {
1780  ast_log(LOG_ERROR, "An endpoint has been specified on outbound registration '%s' without enabling line support\n",
1781  ast_sorcery_object_get_id(applied));
1782  return -1;
1783  }
1784 
1785  if (state && can_reuse_registration(state->registration, applied)) {
1786  ast_debug(4,
1787  "No change between old configuration and new configuration on outbound registration '%s'. Using previous state\n",
1788  ast_sorcery_object_get_id(applied));
1789 
1790  /*
1791  * This is OK to replace without relinking the state in the
1792  * current_states container since state->registration and
1793  * applied have the same key.
1794  */
1795  ao2_lock(states);
1796  ao2_replace(state->registration, applied);
1797  ao2_unlock(states);
1798  return 0;
1799  }
1800 
1801  if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
1802  return -1;
1803  }
1804 
1805  if (ast_sip_push_task_wait_serializer(new_state->client_state->serializer,
1807  return -1;
1808  }
1809 
1810  if (ast_sip_push_task(new_state->client_state->serializer,
1812  ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n",
1813  ast_sorcery_object_get_id(new_state->registration));
1814  ao2_ref(new_state, -1);
1815  return -1;
1816  }
1817 
1818  ao2_lock(states);
1819  if (state) {
1820  ao2_unlink(states, state);
1821  }
1822  ao2_link(states, new_state);
1823  ao2_unlock(states);
1824 
1825  return 0;
1826 }
1827 
1828 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1829 {
1830  struct sip_outbound_registration *registration = obj;
1831 
1832  return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
1833 }
1834 
1835 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
1836 {
1837  const struct sip_outbound_registration *registration = obj;
1838 
1839  return ast_sip_auths_to_str(&registration->outbound_auths, buf);
1840 }
1841 
1842 static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
1843 {
1844  const struct sip_outbound_registration *registration = obj;
1845  int i;
1846  struct ast_variable *head = NULL;
1847 
1848  for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
1849  ast_variable_list_append(&head, ast_variable_new("outbound_auth",
1850  AST_VECTOR_GET(&registration->outbound_auths, i), ""));
1851  }
1852 
1853  if (head) {
1854  *fields = head;
1855  }
1856 
1857  return 0;
1858 }
1859 
1860 static int unregister_task(void *obj)
1861 {
1862  struct sip_outbound_registration_state *state = obj;
1863  struct pjsip_regc *client = state->client_state->client;
1864  pjsip_tx_data *tdata;
1865  pjsip_regc_info info;
1866 
1867  pjsip_regc_get_info(client, &info);
1868  ast_debug(1, "Unregistering contacts with server '%s' from client '%s'\n",
1869  state->registration->server_uri, state->registration->client_uri);
1870 
1872 
1873  if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS
1874  && add_configured_supported_headers(state->client_state, tdata)) {
1875  registration_client_send(state->client_state, tdata);
1876  }
1877 
1878  ao2_ref(state, -1);
1879  return 0;
1880 }
1881 
1883 {
1884  ao2_ref(state, +1);
1886  ao2_ref(state, -1);
1887  return -1;
1888  }
1889 
1890  return 0;
1891 }
1892 
1894 {
1895  ao2_ref(state, +1);
1897  ao2_ref(state, -1);
1898  return -1;
1899  }
1900 
1901  return 0;
1902 }
1903 
1904 static void unregister_all(void)
1905 {
1906  struct ao2_container *states;
1907 
1908  states = ao2_global_obj_ref(current_states);
1909  if (!states) {
1910  return;
1911  }
1912 
1913  /* Clean out all the states and let sorcery handle recreating the registrations */
1915  ao2_ref(states, -1);
1916 }
1917 
1918 static void reregister_all(void)
1919 {
1920  unregister_all();
1921  ast_sorcery_load_object(ast_sip_get_sorcery(), "registration");
1922 }
1923 
1924 static char *cli_complete_registration(const char *line, const char *word,
1925  int pos, int state)
1926 {
1927  char *result = NULL;
1928  int wordlen;
1929  int which = 0;
1930  struct sip_outbound_registration *registration;
1931  struct ao2_container *registrations;
1932  struct ao2_iterator i;
1933 
1934  if (pos != 3) {
1935  return NULL;
1936  }
1937 
1938  wordlen = strlen(word);
1939  if (wordlen == 0 && ++which > state) {
1940  return ast_strdup("*all");
1941  }
1942 
1943  registrations = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
1945  if (!registrations) {
1946  return NULL;
1947  }
1948 
1949  i = ao2_iterator_init(registrations, 0);
1950  while ((registration = ao2_iterator_next(&i))) {
1951  const char *name = ast_sorcery_object_get_id(registration);
1952 
1953  if (!strncasecmp(word, name, wordlen) && ++which > state) {
1954  result = ast_strdup(name);
1955  }
1956 
1957  ao2_ref(registration, -1);
1958  if (result) {
1959  break;
1960  }
1961  }
1963 
1964  ao2_ref(registrations, -1);
1965  return result;
1966 }
1967 
1968 static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1969 {
1971  const char *registration_name;
1972 
1973  switch (cmd) {
1974  case CLI_INIT:
1975  e->command = "pjsip send unregister";
1976  e->usage =
1977  "Usage: pjsip send unregister <registration> | *all\n"
1978  " Unregisters the specified (or all) outbound registration(s) "
1979  "and stops future registration attempts.\n";
1980  return NULL;
1981  case CLI_GENERATE:
1982  return cli_complete_registration(a->line, a->word, a->pos, a->n);
1983  }
1984 
1985  if (a->argc != 4) {
1986  return CLI_SHOWUSAGE;
1987  }
1988 
1989  registration_name = a->argv[3];
1990 
1991  if (strcmp(registration_name, "*all") == 0) {
1992  unregister_all();
1993  ast_cli(a->fd, "Unregister all queued\n");
1994  return CLI_SUCCESS;
1995  }
1996 
1997  state = get_state(registration_name);
1998  if (!state) {
1999  ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
2000  return CLI_FAILURE;
2001  }
2002 
2003  if (queue_unregister(state)) {
2004  ast_cli(a->fd, "Failed to queue unregistration\n");
2005  }
2006 
2007  ao2_ref(state, -1);
2008  return CLI_SUCCESS;
2009 }
2010 
2011 static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2012 {
2014  const char *registration_name;
2015 
2016  switch (cmd) {
2017  case CLI_INIT:
2018  e->command = "pjsip send register";
2019  e->usage =
2020  "Usage: pjsip send register <registration> | *all \n"
2021  " Unregisters the specified (or all) outbound "
2022  "registration(s) then starts registration(s) and schedules re-registrations.\n";
2023  return NULL;
2024  case CLI_GENERATE:
2025  return cli_complete_registration(a->line, a->word, a->pos, a->n);
2026  }
2027 
2028  if (a->argc != 4) {
2029  return CLI_SHOWUSAGE;
2030  }
2031 
2032  registration_name = a->argv[3];
2033 
2034  if (strcmp(registration_name, "*all") == 0) {
2035  reregister_all();
2036  ast_cli(a->fd, "Re-register all queued\n");
2037  return CLI_SUCCESS;
2038  }
2039 
2040  state = get_state(registration_name);
2041  if (!state) {
2042  ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
2043  return CLI_FAILURE;
2044  }
2045 
2046  /* We need to serialize the unregister and register so they need
2047  * to be queued as separate tasks.
2048  */
2049  if (queue_unregister(state)) {
2050  ast_cli(a->fd, "Failed to queue unregistration\n");
2051  } else if (queue_register(state)) {
2052  ast_cli(a->fd, "Failed to queue registration\n");
2053  }
2054 
2055  ao2_ref(state, -1);
2056  return CLI_SUCCESS;
2057 }
2058 
2059 static int ami_unregister(struct mansession *s, const struct message *m)
2060 {
2061  const char *registration_name = astman_get_header(m, "Registration");
2063 
2064  if (ast_strlen_zero(registration_name)) {
2065  astman_send_error(s, m, "Registration parameter missing.");
2066  return 0;
2067  }
2068 
2069  if (strcmp(registration_name, "*all") == 0) {
2070  unregister_all();
2071  astman_send_ack(s, m, "Unregistrations queued.");
2072  return 0;
2073  }
2074 
2075  state = get_state(registration_name);
2076  if (!state) {
2077  astman_send_error(s, m, "Unable to retrieve registration entry\n");
2078  return 0;
2079  }
2080 
2081  if (queue_unregister(state)) {
2082  astman_send_ack(s, m, "Failed to queue unregistration");
2083  } else {
2084  astman_send_ack(s, m, "Unregistration sent");
2085  }
2086 
2087  ao2_ref(state, -1);
2088  return 0;
2089 }
2090 
2091 static int ami_register(struct mansession *s, const struct message *m)
2092 {
2093  const char *registration_name = astman_get_header(m, "Registration");
2095 
2096  if (ast_strlen_zero(registration_name)) {
2097  astman_send_error(s, m, "Registration parameter missing.");
2098  return 0;
2099  }
2100 
2101  if (strcmp(registration_name, "*all") == 0) {
2102  reregister_all();
2103  astman_send_ack(s, m, "Reregistrations queued.");
2104  return 0;
2105  }
2106 
2107  state = get_state(registration_name);
2108  if (!state) {
2109  astman_send_error(s, m, "Unable to retrieve registration entry\n");
2110  return 0;
2111  }
2112 
2113  /* We need to serialize the unregister and register so they need
2114  * to be queued as separate tasks.
2115  */
2116  if (queue_unregister(state)) {
2117  astman_send_ack(s, m, "Failed to queue unregistration");
2118  } else if (queue_register(state)) {
2119  astman_send_ack(s, m, "Failed to queue unregistration");
2120  } else {
2121  astman_send_ack(s, m, "Reregistration sent");
2122  }
2123 
2124  ao2_ref(state, -1);
2125  return 0;
2126 }
2127 
2129  struct ast_sip_ami *ami;
2133 };
2134 
2135 static int ami_outbound_registration_task(void *obj)
2136 {
2137  struct sip_ami_outbound *ami = obj;
2138  struct ast_str *buf;
2140 
2141  buf = ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami);
2142  if (!buf) {
2143  return -1;
2144  }
2145 
2147 
2148  if ((state = get_state(ast_sorcery_object_get_id(ami->registration)))) {
2149  pjsip_regc_info info;
2150 
2152  ++ami->registered;
2153  } else {
2154  ++ami->not_registered;
2155  }
2156 
2157  ast_str_append(&buf, 0, "Status: %s\r\n",
2159 
2160  pjsip_regc_get_info(state->client_state->client, &info);
2161  ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg);
2162  ao2_ref(state, -1);
2163  }
2164 
2165  astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
2166  ast_free(buf);
2167 
2169 }
2170 
2171 static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
2172 {
2173  struct sip_ami_outbound *ami = arg;
2174 
2175  ami->registration = obj;
2177 }
2178 
2180  const struct message *m)
2181 {
2182  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2183  struct sip_ami_outbound ami_outbound = { .ami = &ami };
2184  struct ao2_container *regs;
2185 
2186  regs = get_registrations();
2187  if (!regs) {
2188  astman_send_error(s, m, "Unable to retrieve "
2189  "outbound registrations\n");
2190  return -1;
2191  }
2192 
2193  astman_send_listack(s, m, "Following are Events for each Outbound registration",
2194  "start");
2195 
2197 
2198  astman_send_list_complete_start(s, m, "OutboundRegistrationDetailComplete",
2199  ami_outbound.registered + ami_outbound.not_registered);
2200  astman_append(s,
2201  "Registered: %d\r\n"
2202  "NotRegistered: %d\r\n",
2203  ami_outbound.registered,
2204  ami_outbound.not_registered);
2206 
2207  ao2_ref(regs, -1);
2208  return 0;
2209 }
2210 
2211 static struct ao2_container *cli_get_container(const char *regex)
2212 {
2214  struct ao2_container *s_container;
2215 
2216  container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "registration", regex);
2217  if (!container) {
2218  return NULL;
2219  }
2220 
2223  if (!s_container) {
2224  return NULL;
2225  }
2226 
2227  if (ao2_container_dup(s_container, container, 0)) {
2228  ao2_ref(s_container, -1);
2229  return NULL;
2230  }
2231 
2232  return s_container;
2233 }
2234 
2235 static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
2236 {
2237  ao2_callback(container, OBJ_NODATA, callback, args);
2238 
2239  return 0;
2240 }
2241 
2242 static void *cli_retrieve_by_id(const char *id)
2243 {
2244  struct ao2_container *states;
2245  void *obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
2246 
2247  if (!obj) {
2248  /* if the object no longer exists then remove its state */
2249  states = ao2_global_obj_ref(current_states);
2250  if (states) {
2251  ao2_find(states, id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
2252  ao2_ref(states, -1);
2253  }
2254  }
2255 
2256  return obj;
2257 }
2258 
2259 static int cli_print_header(void *obj, void *arg, int flags)
2260 {
2261  struct ast_sip_cli_context *context = arg;
2262 
2263  ast_assert(context->output_buffer != NULL);
2264 
2265  ast_str_append(&context->output_buffer, 0,
2266  " <Registration/ServerURI..............................> <Auth..........> <Status.......>\n");
2267 
2268  return 0;
2269 }
2270 
2271 static int cli_print_body(void *obj, void *arg, int flags)
2272 {
2273  struct sip_outbound_registration *registration = obj;
2274  struct ast_sip_cli_context *context = arg;
2275  const char *id = ast_sorcery_object_get_id(registration);
2277 #define REGISTRATION_URI_FIELD_LEN 53
2278 
2279  ast_assert(context->output_buffer != NULL);
2280 
2281  ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-16s %-16s\n",
2282  id,
2283  (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2284  (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2285  registration->server_uri,
2286  AST_VECTOR_SIZE(&registration->outbound_auths)
2287  ? AST_VECTOR_GET(&registration->outbound_auths, 0)
2288  : "n/a",
2289  (state ? sip_outbound_registration_status_str(state->client_state->status) : "Unregistered"));
2290  ao2_cleanup(state);
2291 
2292  if (context->show_details
2293  || (context->show_details_only_level_0 && context->indent_level == 0)) {
2294  ast_str_append(&context->output_buffer, 0, "\n");
2295  ast_sip_cli_print_sorcery_objectset(registration, context, 0);
2296  }
2297 
2298  return 0;
2299 }
2300 
2301 /*
2302  * A function pointer to callback needs to be within the
2303  * module in order to avoid problems with an undefined
2304  * symbol when the module is loaded.
2305  */
2306 static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2307 {
2308  return ast_sip_cli_traverse_objects(e, cmd, a);
2309 }
2310 
2312  AST_CLI_DEFINE(cli_unregister, "Unregisters outbound registration target"),
2313  AST_CLI_DEFINE(cli_register, "Registers an outbound registration target"),
2314  AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
2315  .command = "pjsip list registrations",
2316  .usage = "Usage: pjsip list registrations [ like <pattern> ]\n"
2317  " List the configured PJSIP Registrations\n"
2318  " Optional regular expression pattern is used to filter the list.\n"),
2319  AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
2320  .command = "pjsip show registrations",
2321  .usage = "Usage: pjsip show registrations [ like <pattern> ]\n"
2322  " Show the configured PJSIP Registrations\n"
2323  " Optional regular expression pattern is used to filter the list.\n"),
2324  AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
2325  .command = "pjsip show registration",
2326  .usage = "Usage: pjsip show registration <id>\n"
2327  " Show the configured PJSIP Registration\n"),
2328 };
2329 
2331 
2332 static void auth_observer(const char *type)
2333 {
2334  struct sip_outbound_registration *registration;
2336  struct ao2_container *regs;
2337  const char *registration_id;
2338  struct ao2_iterator i;
2339 
2340  ast_debug(4, "Auths updated. Checking for any outbound registrations that are in permanent rejected state so they can be retried\n");
2341 
2342  regs = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
2344  if (!regs || ao2_container_count(regs) == 0) {
2345  ao2_cleanup(regs);
2346  return;
2347  }
2348 
2349  i = ao2_iterator_init(regs, 0);
2350  for (; (registration = ao2_iterator_next(&i)); ao2_ref(registration, -1)) {
2351  registration_id = ast_sorcery_object_get_id(registration);
2352  state = get_state(registration_id);
2353  if (state && state->client_state->status == SIP_REGISTRATION_REJECTED_PERMANENT) {
2354  ast_debug(4, "Trying outbound registration '%s' again\n", registration_id);
2355 
2358  ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", registration_id);
2359  ao2_ref(state, -1);
2360  }
2361  }
2362  ao2_cleanup(state);
2363  }
2365  ao2_cleanup(regs);
2366 }
2367 
2369  .loaded = auth_observer,
2370 };
2371 
2372 static int check_state(void *obj, void *arg, int flags)
2373 {
2374  struct sip_outbound_registration_state *state = obj;
2375  struct sip_outbound_registration *registration;
2376 
2377  registration = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration",
2379  if (!registration) {
2380  /* This is a dead registration */
2381  return CMP_MATCH;
2382  }
2383 
2384  ao2_ref(registration, -1);
2385  return 0;
2386 }
2387 
2388 /*!
2389  * \internal
2390  * \brief Observer to purge dead registration states.
2391  *
2392  * \param name Module name owning the sorcery instance.
2393  * \param sorcery Instance being observed.
2394  * \param object_type Name of object being observed.
2395  * \param reloaded Non-zero if the object is being reloaded.
2396  *
2397  * \return Nothing
2398  */
2399 static void registration_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
2400 {
2401  struct ao2_container *states;
2402 
2403  if (strcmp(object_type, "registration")) {
2404  /* Not interested */
2405  return;
2406  }
2407 
2408  states = ao2_global_obj_ref(current_states);
2409  if (!states) {
2410  /* Global container has gone. Likely shutting down. */
2411  return;
2412  }
2413 
2414  /*
2415  * Refresh the current configured registrations. We don't need to hold
2416  * onto the objects, as the apply handler will cause their states to
2417  * be created appropriately.
2418  */
2420 
2421  /* Now to purge dead registrations. */
2423  ao2_ref(states, -1);
2424 }
2425 
2428 };
2429 
2430 static void registration_deleted_observer(const void *obj)
2431 {
2432  const struct sip_outbound_registration *registration = obj;
2433  struct ao2_container *states;
2434 
2435  states = ao2_global_obj_ref(current_states);
2436  if (!states) {
2437  /* Global container has gone. Likely shutting down. */
2438  return;
2439  }
2440 
2442 
2443  ao2_ref(states, -1);
2444 }
2445 
2448 };
2449 
2450 static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
2451 {
2452  /* This callback is only concerned with network change messages from the system topic. */
2453  if (stasis_message_type(message) != ast_network_change_type()) {
2454  return;
2455  }
2456  ast_debug(3, "Received network change event\n");
2457 
2458  reregister_all();
2459 }
2460 
2461 static int unload_module(void)
2462 {
2463  int remaining;
2464 
2465  network_change_sub = stasis_unsubscribe_and_join(network_change_sub);
2466 
2467  ast_manager_unregister("PJSIPShowRegistrationsOutbound");
2468  ast_manager_unregister("PJSIPUnregister");
2469  ast_manager_unregister("PJSIPRegister");
2470 
2471  ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
2472  ast_sip_unregister_cli_formatter(cli_formatter);
2473  cli_formatter = NULL;
2474 
2475  ast_sip_unregister_endpoint_identifier(&line_identifier);
2476 
2477  ast_sorcery_observer_remove(ast_sip_get_sorcery(), "auth", &observer_callbacks_auth);
2478  ast_sorcery_instance_observer_remove(ast_sip_get_sorcery(), &observer_callbacks_registrations);
2479 
2481 
2482  ao2_global_obj_release(current_states);
2483 
2485 
2486  /* Wait for registration serializers to get destroyed. */
2487  ast_debug(2, "Waiting for registration transactions to complete for unload.\n");
2488  remaining = ast_serializer_shutdown_group_join(shutdown_group, MAX_UNLOAD_TIMEOUT_TIME);
2489  if (remaining) {
2490  /*
2491  * NOTE: We probably have a sip_outbound_registration_client_state
2492  * ref leak if the remaining count cannot reach zero after a few
2493  * minutes of trying to unload.
2494  */
2495  ast_log(LOG_WARNING, "Unload incomplete. Could not stop %d outbound registrations. Try again later.\n",
2496  remaining);
2497  return -1;
2498  }
2499 
2500  ast_debug(2, "Successful shutdown.\n");
2501 
2502  ao2_cleanup(shutdown_group);
2503  shutdown_group = NULL;
2504 
2505  return 0;
2506 }
2507 
2508 static int load_module(void)
2509 {
2510  struct ao2_container *new_states;
2511 
2512  shutdown_group = ast_serializer_shutdown_group_alloc();
2513  if (!shutdown_group) {
2514  return AST_MODULE_LOAD_DECLINE;
2515  }
2516 
2517  /* Create outbound registration states container. */
2520  if (!new_states) {
2521  ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
2522  unload_module();
2523  return AST_MODULE_LOAD_DECLINE;
2524  }
2525  ao2_global_obj_replace_unref(current_states, new_states);
2526  ao2_ref(new_states, -1);
2527 
2528  /*
2529  * Register sorcery object descriptions.
2530  */
2531  ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_registration");
2532  ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
2533 
2535  unload_module();
2536  return AST_MODULE_LOAD_DECLINE;
2537  }
2538 
2539  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
2546  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
2548  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));
2549  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));
2551  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));
2557 
2558  /*
2559  * Register sorcery observers.
2560  */
2562  &observer_callbacks_registrations)
2564  &observer_callbacks_auth)
2565  || ast_sorcery_observer_add(ast_sip_get_sorcery(), "registration",
2566  &registration_observer)) {
2567  ast_log(LOG_ERROR, "Unable to register observers.\n");
2568  unload_module();
2569  return AST_MODULE_LOAD_DECLINE;
2570  }
2571 
2572  /* Register how this module identifies endpoints. */
2573  ast_sip_register_endpoint_identifier(&line_identifier);
2574 
2575  /* Register CLI commands. */
2576  cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
2577  if (!cli_formatter) {
2578  ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
2579  unload_module();
2580  return AST_MODULE_LOAD_DECLINE;
2581  }
2582  cli_formatter->name = "registration";
2583  cli_formatter->print_header = cli_print_header;
2584  cli_formatter->print_body = cli_print_body;
2585  cli_formatter->get_container = cli_get_container;
2586  cli_formatter->iterate = cli_iterator;
2587  cli_formatter->get_id = ast_sorcery_object_get_id;
2588  cli_formatter->retrieve_by_id = cli_retrieve_by_id;
2589  ast_sip_register_cli_formatter(cli_formatter);
2590  ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
2591 
2592  /* Register AMI actions. */
2596 
2597  /* Clear any previous statsd gauges in case we weren't shutdown cleanly */
2598  ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GAUGE, 0);
2599  ast_statsd_log("PJSIP.registrations.state.Registered", AST_STATSD_GAUGE, 0);
2600  ast_statsd_log("PJSIP.registrations.state.Unregistered", AST_STATSD_GAUGE, 0);
2601  ast_statsd_log("PJSIP.registrations.state.Rejected", AST_STATSD_GAUGE, 0);
2602 
2603  /* Load configuration objects */
2604  ast_sorcery_load_object(ast_sip_get_sorcery(), "registration");
2605 
2606  network_change_sub = stasis_subscribe(ast_system_topic(),
2610 
2611  return AST_MODULE_LOAD_SUCCESS;
2612 }
2613 
2614 static int reload_module(void)
2615 {
2617  return 0;
2618 }
2619 
2620 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
2621  .support_level = AST_MODULE_SUPPORT_CORE,
2622  .load = load_module,
2623  .reload = reload_module,
2624  .unload = unload_module,
2625  .load_pri = AST_MODPRI_APP_DEPEND,
2626  .requires = "res_pjsip",
2627  .optional_modules = "res_statsd",
2628 );
struct ast_str * output_buffer
Definition: res_pjsip_cli.h:36
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:84
unsigned int support_path
Whether Path support is enabled.
static const char type[]
Definition: chan_ooh323.c:109
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
enum sip_cc_notify_state state
Definition: chan_sip.c:963
unsigned int auth_attempted
Non-zero if we have attempted sending a REGISTER with authentication.
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
static void update_client_state_status(struct sip_outbound_registration_client_state *client_state, enum sip_outbound_registration_status status)
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name)
static void * cli_retrieve_by_id(const char *id)
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
int ast_sip_auth_vector_init(struct ast_sip_auth_vector *vector, const char *auth_names)
Initialize an auth vector with the configured values.
static const char name[]
Definition: format_mp3.c:68
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
Asterisk main include file. File version handling, generic pbx functions.
static struct sip_outbound_registration_state * sip_outbound_registration_state_alloc(struct sip_outbound_registration *registration)
Allocator function for registration state.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
#define MAX_UNLOAD_TIMEOUT_TIME
Definition: res_pjsip_cli.h:52
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
void(* deleted)(const void *object)
Callback for when an object is deleted.
Definition: sorcery.h:340
static const char * fetch_google_access_token(const struct ast_sip_auth *auth)
static char * cli_complete_registration(const char *line, const char *word, int pos, int state)
unsigned int max_retries
Maximum number of retries permitted.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
const ast_string_field oauth_secret
Definition: res_pjsip.h:460
char text[AST_JSON_ERROR_TEXT_LENGTH]
Definition: json.h:837
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.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
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
static int reload(void)
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
unsigned int support_outbound
Determines whether SIP Outbound support should be advertised.
static char * my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
const struct message * m
Definition: res_pjsip.h:2741
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
pjsip_tx_data * old_request
Request for which the response was received.
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:3237
void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *vector)
Free contents of an auth vector.
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
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.
enum sip_outbound_registration_status status
Current state of this registration.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static struct ast_sip_endpoint_identifier line_identifier
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
struct ast_serializer_shutdown_group * ast_serializer_shutdown_group_alloc(void)
Create a serializer group shutdown control object.
Definition: threadpool.c:1229
struct stasis_message_type * ast_network_change_type(void)
A stasis_message_type for network changes.
static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
Apply function which finds or allocates a state structure.
AMI variable container.
Definition: res_pjsip.h:2737
static int tmp()
Definition: bt_open.c:389
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
Structure for variables, used for configurations and for channel variables.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define var
Definition: ast_expr2f.c:614
const ast_string_field client_uri
URI for the AOR.
int ast_sip_transport_state_set_preferred_identity(const char *transport_name, const char *identity)
Sets the P-Preferred-Identity on a child transport.
static void registration_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
Perform no matching, return all objects.
Definition: sorcery.h:123
unsigned int forbidden_retry_interval
Interval at which retries should occur for permanent responses.
static void save_response_fields_to_transport(struct registration_response *response)
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2459
static struct stasis_subscription * network_change_sub
pj_timer_entry timer
Timer entry for retrying on temporal responses.
Definition: cli.h:152
Full structure for sorcery.
Definition: sorcery.c:230
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
static int ami_outbound_registration_task(void *obj)
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Definition: res_pjsip_cli.h:66
Type for a default handler that should do nothing.
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
const ast_string_field server_uri
URI for the registrar.
static const struct ast_sorcery_observer observer_callbacks_auth
static int registration_state_hash(const void *obj, const int flags)
hashing function for state objects
Outbound registration state information (persists for lifetime that registration should exist) ...
static int handle_client_state_destruction(void *data)
Callback function for unregistering (potentially) and destroying state.
static int queue_unregister(struct sip_outbound_registration_state *state)
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:1091
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define ao2_global_obj_ref(holder)
Definition: astobj2.h:925
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
unsigned int expiration
Requested expiration time.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
#define ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:456
Return all matching objects.
Definition: sorcery.h:120
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 ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:710
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
Outbound registration client state information (persists for lifetime of regc)
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
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:5240
const char * str
Definition: app_jack.c:147
static struct ast_sip_endpoint * line_identify(pjsip_rx_data *rdata)
Endpoint identifier which uses the &#39;line&#39; parameter to establish a relationship to an outgoing regist...
const char * args
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:998
#define NULL
Definition: resample.c:96
static pj_str_t OUTBOUND_NAME
Definitions to aid in the use of thread local storage.
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
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static struct ast_threadstorage register_callback_invoked
static char * cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:60
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
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:5204
#define LOG_DEBUG
Definition: logger.h:241
static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
#define REGISTRATION_URI_FIELD_LEN
char line[LINE_PARAMETER_SIZE]
Optional line parameter placed into Contact.
Structure for registration response.
unsigned int max_retries
Maximum number of retries permitted.
JSON parsing error information.
Definition: json.h:829
static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
Callback function for outbound registration client.
char * ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pjsip_cli.c:109
unsigned int support_outbound
Whether Outbound support is enabled.
const char * line
Definition: cli.h:162
static struct ao2_container * get_registrations(void)
const ast_string_field contact_user
Optional user for contact header.
static struct pjsip_param * get_uri_option_line(const void *uri)
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
sip_outbound_registration_status
Various states that an outbound registration may be in.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
const ast_string_field oauth_clientid
Definition: res_pjsip.h:458
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
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_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
static pj_str_t PATH_NAME
int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Registers a CLI formatter.
Definition: pjsip_cli.c:310
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:4871
static void sip_outbound_registration_destroy(void *obj)
Destructor function for registration information.
#define ao2_bump(obj)
Definition: astobj2.h:491
unsigned int retry_interval
Interval at which retries should occur for temporal responses.
static const struct ast_sorcery_observer registration_observer
static void unregister_all(void)
Type for default option handler for bools (ast_true/ast_false)
static void registration_transport_shutdown_cb(void *obj)
static int sip_outbound_registration_perform(void *data)
Helper function which performs a single registration.
int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
Retrieve relevant SIP auth structures from sorcery.
static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
static const char * sip_outbound_registration_status_str(enum sip_outbound_registration_status state)
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
int() ao2_callback_fn(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1230
#define ast_log
Definition: astobj2.c:42
struct sip_outbound_registration_client_state * client_state
Client state information.
#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
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
struct ast_sip_auth_vector outbound_auths
Configured authentication credentials.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Register a SIP endpoint identifier.
Definition: res_pjsip.c:3508
unsigned int forbidden_retry_interval
Interval at which retries should occur for permanent responses.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
static int load_module(void)
const ast_string_field outbound_proxy
Outbound proxy to use.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
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_sorcery_object_unregister(struct ast_sorcery *sorcery, const char *type)
Unregister an object type.
Definition: sorcery.c:1061
#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:911
Type for default option handler for unsigned integers.
const int fd
Definition: cli.h:159
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
static int unload_module(void)
Interface for the sorcery instance observer.
Definition: sorcery.h:237
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
const int n
Definition: cli.h:165
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:5218
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.
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
static int ami_register(struct mansession *s, const struct message *m)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
In case you didn&#39;t read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1625
long int ast_random(void)
Definition: main/utils.c:2064
#define DEFAULT_STATE_BUCKETS
Default number of state container buckets.
#define ao2_lock(a)
Definition: astobj2.h:718
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
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
unsigned int support_path
Determines whether SIP Path support should be advertised.
const ast_string_field transport
Explicit transport to use for registration.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
pjsip_tx_data * last_tdata
Last tdata sent We need the original tdata to resend a request on auth failure or timeout...
struct mansession * s
Definition: res_pjsip.h:2739
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
struct ao2_container * container
Definition: res_fax.c:502
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:5128
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:3412
#define ast_variable_new(name, value, filename)
char * registration_name
The name of the registration sorcery object.
int ast_sip_unregister_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Unregisters a CLI formatter.
Definition: pjsip_cli.c:326
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
static void registration_deleted_observer(const void *obj)
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:838
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
#define ARRAY_LEN(a)
Definition: utils.h:639
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
Core PBX routines and definitions.
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
struct ast_sip_service_route_vector * ast_sip_service_route_vector_alloc(void)
Allocate a vector of service routes.
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:652
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
static int set_outbound_initial_authentication_credentials(pjsip_regc *regc, const struct ast_sip_auth_vector *auth_vector)
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.
const char *const * argv
Definition: cli.h:161
static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
static struct ast_cli_entry cli_outbound_registration[]
struct sip_outbound_registration * registration
Outbound registration configuration object.
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
#define REREGISTER_BUFFER_TIME
Amount of buffer time (in seconds) before expiration that we re-register at.
int code
Response code for the registration attempt.
Outbound registration information.
static int ami_show_outbound_registrations(struct mansession *s, const struct message *m)
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
void ast_sip_service_route_vector_destroy(struct ast_sip_service_route_vector *service_routes)
Destroy a vector of service routes.
int expiration
Expiration time for registration.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
char * usage
Definition: utils/frame.c:37
Registration was rejected, permanently.
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
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 CLI_SHOWUSAGE
Definition: cli.h:45
const ast_string_field realm
Definition: res_pjsip.h:448
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:5138
int column
Definition: json.h:833
static struct sip_outbound_registration_state * get_state(const char *id)
Interface for a sorcery object type observer.
Definition: sorcery.h:332
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
Type for default option handler for bools (ast_true/ast_false)
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
Definition: strings.c:227
def info(msg)
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:477
#define LINE_PARAMETER_SIZE
Size of the buffer for creating a unique string for the line.
static int add_to_supported_header(pjsip_tx_data *tdata, pj_str_t *name)
Helper function to add string to Supported header.
SORCERY_OBJECT(details)
Sorcery object details.
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static int monitor_matcher(void *a, void *b)
struct stasis_topic * ast_system_topic(void)
A Stasis Message Bus API topic which publishes messages regarding system changes. ...
void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
Clean up retrieved auth structures from memory.
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1136
unsigned int auth_rejection_permanent
Treat authentication challenges that we cannot handle as permanent failures.
struct ast_taskprocessor * serializer
Serializer for stuff and things.
#define CLI_FAILURE
Definition: cli.h:46
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static AO2_GLOBAL_OBJ_STATIC(current_states)
static int reload_module(void)
const ast_string_field auth_pass
Definition: res_pjsip.h:452
const char * word
Definition: cli.h:163
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
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
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static void * sip_outbound_registration_alloc(const char *name)
Allocator function for registration information.
Vector container support.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
An API for managing task processing threads that can be shared across modules.
static int queue_register(struct sip_outbound_registration_state *state)
An entity responsible for identifying the source of a SIP message.
Definition: res_pjsip.h:993
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
int ast_sip_transport_state_set_transport(const char *transport_name, pjsip_transport *transport)
Sets the PJSIP transport on a child transport.
static struct registrations registrations
structure to hold users read from users.conf
const ast_string_field refresh_token
Definition: res_pjsip.h:456
static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
Definition: sorcery.h:343
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.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
char * transport_name
The name of the transport to be used for the registration.
static int handle_registration_response(void *data)
Callback function for handling a response to a registration attempt.
static int line_identify_relationship(void *obj, void *arg, int flags)
Callback function for matching an outbound registration based on line.
const char * usage
Definition: cli.h:177
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
static int registration_state_cmp(void *obj, void *arg, int flags)
comparator function for state objects
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.
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
static int unregister_task(void *obj)
#define EVENT_FLAG_REPORTING
Definition: manager.h:80
#define CLI_SUCCESS
Definition: cli.h:44
#define AST_STATSD_GAUGE
Support for publishing to a statsd server.
Definition: statsd.h:32
static struct ao2_container * cli_get_container(const char *regex)
#define ao2_global_obj_replace_unref(holder, obj)
Definition: astobj2.h:908
unsigned int retry_interval
Interval at which retries should occur for temporal responses.
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
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
unsigned int retries
Current number of retries.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
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
static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
int ast_sip_validate_uri_length(const char *uri)
Definition: location.c:525
#define ao2_replace(dst, src)
Definition: astobj2.h:517
static struct ast_sorcery * sorcery
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
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
struct ast_sip_auth_vector outbound_auths
Configured authentication credentials.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const ast_string_field endpoint
Endpoint to use for related incoming calls.
Standard Command Line Interface.
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
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
const int pos
Definition: cli.h:164
struct sip_outbound_registration_client_state * client_state
Outbound registration client state.
static struct ao2_container * new_states
Used on [re]loads to hold new state data.
static struct ast_sip_cli_formatter_entry * cli_formatter
static int ami_unregister(struct mansession *s, const struct message *m)
static PGresult * result
Definition: cel_pgsql.c:88
static int cli_print_body(void *obj, void *arg, int flags)
unsigned int auth_rejection_permanent
Treat authentication challenges that we cannot handle as permanent failures.
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
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
static int check_state(void *obj, void *arg, int flags)
struct stasis_forward * sub
Definition: res_corosync.c:240
static void sip_outbound_registration_state_destroy(void *obj)
Destructor function for registration state.
static void auth_observer(const char *type)
static int cli_print_header(void *obj, void *arg, int flags)
void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Unregister a SIP endpoint identifier.
Definition: res_pjsip.c:3513
Abstract JSON element (object, array, string, int, ...).
Type for default option handler for stringfields.
static void schedule_retry(struct registration_response *response, unsigned int interval, const char *server_uri, const char *client_uri)
ao2_callback_fn * print_header
Definition: res_pjsip_cli.h:60
static struct test_val b
static void registration_response_destroy(void *obj)
Registration response structure destructor.
static int handle_client_registration(void *data)
Callback function for registering.
Definition: search.h:40
static void sip_outbound_registration_client_state_destroy(void *obj)
Destructor function for client registration state.
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 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.
unsigned int fatal_retry_interval
Interval at which retries should occur for all permanent responses.
unsigned int fatal_retry_interval
Interval at which retries should occur for all permanent responses.
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 sip_outbound_registration * registration
unsigned int destroy
Registration should be destroyed after completion of transaction.
int line
Definition: json.h:831
Generic container type.
Search option field mask.
Definition: astobj2.h:1076
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
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
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
void ast_sip_tpselector_unref(pjsip_tpselector *selector)
Unreference a pjsip_tpselector.
Definition: res_pjsip.c:3987
static char url[512]
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186
ao2_callback_fn * print_body
Definition: res_pjsip_cli.h:62
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define DEBUG_ATLEAST(level)
Definition: logger.h:433
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
Asterisk module definitions.
int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
Prints a sorcery object&#39;s ast_variable list.
Definition: pjsip_cli.c:36
const char * name
Definition: res_pjsip_cli.h:58
static struct ast_serializer_shutdown_group * shutdown_group
static const struct ast_sorcery_instance_observer observer_callbacks_registrations
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 reregister_immediately_cb(void *obj)
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
static void reregister_all(void)
static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
pjsip_rx_data * rdata
The response message.
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.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
const ast_string_field auth_user
Definition: res_pjsip.h:450
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
#define ast_variable_list_append(head, new_var)
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
Registration was rejected, but response was temporal.
static int sip_outbound_registration_regc_alloc(void *data)
Helper function that allocates a pjsip registration client and configures it.
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.
jack_status_t status
Definition: app_jack.c:146
pjsip_regc * client
Outbound registration client.
short word
static char * cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206
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:3201
unsigned show_details_only_level_0
Definition: res_pjsip_cli.h:46
static struct test_val a
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:3957
Registration has been stopped.
static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
Helper function which cancels the timer on a client.
unsigned int line
Whether to add a line parameter to the outbound Contact or not.
#define ao2_link(container, obj)
Definition: astobj2.h:1549