Asterisk - The Open Source Telephony Project  21.4.1
pjsip_transport_events.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2017, Digium Inc.
5  *
6  * Richard Mudgett <rmudgett@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 /*!
20  * \file
21  * \brief Manages the global transport event notification callbacks.
22  *
23  * \author Richard Mudgett <rmudgett@digium.com>
24  * See Also:
25  *
26  * \arg \ref AstCREDITS
27  */
28 
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/res_pjsip.h"
33 #include "asterisk/res_pjsip_cli.h"
34 #include "include/res_pjsip_private.h"
35 #include "asterisk/linkedlists.h"
36 #include "asterisk/vector.h"
37 
38 /* ------------------------------------------------------------------- */
39 
40 /*! \brief Number of buckets for monitored active transports */
41 #define ACTIVE_TRANSPORTS_BUCKETS 127
42 
43 /*! Who to notify when transport shuts down. */
45  /*! Who to call when transport shuts down. */
46  ast_transport_monitor_shutdown_cb cb;
47  /*! ao2 data object to pass to callback. */
48  void *data;
49 };
50 
51 /*! \brief Structure for transport to be monitored */
53  /*! \brief Key <ipaddr>:<port> */
54  char key[IP6ADDR_COLON_PORT_BUFLEN];
55  /*! \brief The underlying PJSIP transport */
56  pjsip_transport *transport;
57  /*! For debugging purposes, we save the obj_name
58  * in case the transport goes away.
59  */
61  /*! Who is interested in when this transport shuts down. */
63 };
64 
65 /*! \brief Global container of active reliable transports */
66 static AO2_GLOBAL_OBJ_STATIC(active_transports);
67 
68 /*! \brief Existing transport events callback that we need to invoke */
69 static pjsip_tp_state_callback tpmgr_state_callback;
70 
71 /*! List of registered transport state callbacks. */
73 
74 /*! \brief Hashing function for struct transport_monitor */
76 
77 /*! \brief Comparison function for struct transport_monitor */
78 AO2_STRING_FIELD_CMP_FN(transport_monitor, key);
79 
80 /*! \brief Sort function for struct transport_monitor */
81 AO2_STRING_FIELD_SORT_FN(transport_monitor, key);
82 
83 static const char *transport_state2str(pjsip_transport_state state)
84 {
85  const char *name;
86 
87  switch (state) {
88  case PJSIP_TP_STATE_CONNECTED:
89  name = "CONNECTED";
90  break;
91  case PJSIP_TP_STATE_DISCONNECTED:
92  name = "DISCONNECTED";
93  break;
94  case PJSIP_TP_STATE_SHUTDOWN:
95  name = "SHUTDOWN";
96  break;
97  case PJSIP_TP_STATE_DESTROY:
98  name = "DESTROY";
99  break;
100  default:
101  /*
102  * We have to have a default case because the enum is
103  * defined by a third-party library.
104  */
105  ast_assert(0);
106  name = "<unknown>";
107  break;
108  }
109  return name;
110 }
111 
112 static void transport_monitor_dtor(void *vdoomed)
113 {
114  struct transport_monitor *monitored = vdoomed;
115  int idx;
116 
117  for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {
118  struct transport_monitor_notifier *notifier;
119 
120  notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);
121  ao2_cleanup(notifier->data);
122  }
123  AST_VECTOR_FREE(&monitored->monitors);
124  ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : state:MONITOR_DESTROYED\n",
125  monitored->key, monitored->transport->obj_name,
126  monitored->transport->type_name,pj_atomic_get(monitored->transport->ref_cnt));
127  ast_free(monitored->transport_obj_name);
128  pjsip_transport_dec_ref(monitored->transport);
129 }
130 
131 /*!
132  * \internal
133  * \brief Do registered callbacks for the transport.
134  * \since 13.21.0
135  *
136  * \param transports Active transports container
137  * \param transport Which transport to do callbacks for.
138  */
139 static void transport_state_do_reg_callbacks(struct ao2_container *transports, pjsip_transport *transport)
140 {
141  struct transport_monitor *monitored;
142  char key[IP6ADDR_COLON_PORT_BUFLEN];
143 
144  AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key);
145 
146  monitored = ao2_find(transports, key, OBJ_SEARCH_KEY | OBJ_UNLINK);
147  if (monitored) {
148  int idx;
149 
150  for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {
151  struct transport_monitor_notifier *notifier;
152 
153  notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);
154  ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : running callback %p(%p)\n",
155  monitored->key, monitored->transport->obj_name,
156  monitored->transport->type_name,
157  pj_atomic_get(monitored->transport->ref_cnt), notifier->cb, notifier->data);
158  notifier->cb(notifier->data);
159  }
160  ao2_ref(monitored, -1);
161  }
162 }
163 
164 static void verify_log_result(int log_level, const pjsip_transport *transport,
165  pj_uint32_t verify_status)
166 {
167  const char *status[32];
168  unsigned int count;
169  unsigned int i;
170 
171  count = ARRAY_LEN(status);
172 
173  if (pj_ssl_cert_get_verify_status_strings(verify_status, status, &count) != PJ_SUCCESS) {
174  ast_log(LOG_ERROR, "Error retrieving certificate verification result(s)\n");
175  return;
176  }
177 
178  for (i = 0; i < count; ++i) {
179  ast_log(log_level, _A_, "Transport '%s' to remote '%.*s' - %s\n", transport->factory->info,
180  (int)pj_strlen(&transport->remote_name.host), pj_strbuf(&transport->remote_name.host),
181  status[i]);
182  }
183 }
184 
185 static int verify_cert_name(const pj_str_t *local, const pj_str_t *remote)
186 {
187  const char *p;
188  pj_ssize_t size;
189 
190  ast_debug(3, "Verify certificate name: local = %.*s, remote = %.*s\n",
191  (unsigned int)pj_strlen(local), pj_strbuf(local),
192  (unsigned int)pj_strlen(remote), pj_strbuf(remote));
193 
194  if (!pj_stricmp(remote, local)) {
195  return 1;
196  }
197 
198  if (pj_strnicmp2(remote, "*.", 2)) {
199  return 0;
200  }
201 
202  p = pj_strchr(local, '.');
203  if (!p) {
204  return 0;
205  }
206 
207  size = pj_strbuf(local) + pj_strlen(local) - ++p;
208 
209  return size == pj_strlen(remote) - 2 ?
210  !pj_memcmp(pj_strbuf(remote) + 2, p, size) : 0;
211 }
212 
213 static int verify_cert_names(const pj_str_t *host, const pj_ssl_cert_info *remote)
214 {
215  unsigned int i;
216 
217  for (i = 0; i < remote->subj_alt_name.cnt; ++i) {
218  /*
219  * DNS is the only type we're matching wildcards against,
220  * so only recheck those.
221  */
222  if (remote->subj_alt_name.entry[i].type == PJ_SSL_CERT_NAME_DNS
223  && verify_cert_name(host, &remote->subj_alt_name.entry[i].name)) {
224  return 1;
225  }
226  }
227 
228  return verify_cert_name(host, &remote->subject.cn);
229 }
230 
231 static int transport_tls_verify(const pjsip_transport *transport,
232  const pjsip_tls_state_info *state_info)
233 {
234  pj_uint32_t verify_status;
235  const struct ast_sip_transport_state *state;
236 
237  if (transport->dir == PJSIP_TP_DIR_INCOMING) {
238  return 1;
239  }
240 
241  /* transport_id should always be in factory info (see config_transport) */
242  ast_assert(!ast_strlen_zero(transport->factory->info));
243 
244  state = ast_sip_get_transport_state(transport->factory->info);
245  if (!state) {
246  /*
247  * There should always be an associated state, but if for some
248  * reason there is not then fail verification
249  */
250  ast_log(LOG_ERROR, "Transport state not found for '%s'\n", transport->factory->info);
251  return 0;
252  }
253 
254  verify_status = state_info->ssl_sock_info->verify_status;
255 
256  /*
257  * By this point pjsip has already completed its verification process. If
258  * there was a name matching error it could be because they disallow wildcards.
259  * If this transport has been configured to allow wildcards then we'll need
260  * to re-check the name(s) for such.
261  */
262  if (state->allow_wildcard_certs &&
263  (verify_status & PJ_SSL_CERT_EIDENTITY_NOT_MATCH)) {
264  if (verify_cert_names(&transport->remote_name.host,
265  state_info->ssl_sock_info->remote_cert_info)) {
266  /* A name matched a wildcard, so clear the error */
267  verify_status &= ~PJ_SSL_CERT_EIDENTITY_NOT_MATCH;
268  }
269  }
270 
271  if (state->verify_server && verify_status != PJ_SSL_CERT_ESUCCESS) {
272  verify_log_result(__LOG_ERROR, transport, verify_status);
273  return 0;
274  }
275 
276  verify_log_result(__LOG_NOTICE, transport, verify_status);
277  return 1;
278 }
279 
280 /*! \brief Callback invoked when transport state changes occur */
281 static void transport_state_callback(pjsip_transport *transport,
282  pjsip_transport_state state, const pjsip_transport_state_info *info)
283 {
284  struct ao2_container *transports;
285 
286  /* We only care about monitoring reliable transports */
287  if (PJSIP_TRANSPORT_IS_RELIABLE(transport)
288  && (transports = ao2_global_obj_ref(active_transports))) {
289  struct transport_monitor *monitored;
290 
291  ast_debug(3, "Transport " PJSTR_PRINTF_SPEC ":%d(%s,%s): RefCnt: %ld state:%s\n",
292  PJSTR_PRINTF_VAR(transport->remote_name.host),
293  transport->remote_name.port, transport->obj_name,
294  transport->type_name,
295  pj_atomic_get(transport->ref_cnt), transport_state2str(state));
296  switch (state) {
297  case PJSIP_TP_STATE_CONNECTED:
298  if (PJSIP_TRANSPORT_IS_SECURE(transport) &&
299  !transport_tls_verify(transport, info->ext_info)) {
300  pjsip_transport_shutdown(transport);
301  return;
302  }
303 
304  monitored = ao2_alloc_options(sizeof(*monitored),
305  transport_monitor_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
306  if (!monitored) {
307  break;
308  }
309  monitored->transport = transport;
310  AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, monitored->key);
311  monitored->transport_obj_name = ast_strdup(transport->obj_name);
312 
313  if (AST_VECTOR_INIT(&monitored->monitors, 5)) {
314  ao2_ref(monitored, -1);
315  break;
316  }
317  pjsip_transport_add_ref(monitored->transport);
318  ast_debug(3, "Transport %s(%s,%s): RefCnt: %ld state:MONITOR_CREATED\n",
319  monitored->key, monitored->transport_obj_name,
320  monitored->transport->type_name,
321  pj_atomic_get(monitored->transport->ref_cnt));
322 
323  ao2_link(transports, monitored);
324  ao2_ref(monitored, -1);
325  break;
326  case PJSIP_TP_STATE_DISCONNECTED:
327  if (!transport->is_shutdown) {
328  pjsip_transport_shutdown(transport);
329  }
330  transport_state_do_reg_callbacks(transports, transport);
331  break;
332  case PJSIP_TP_STATE_SHUTDOWN:
333  /*
334  * Set shutdown flag early so we can force a new transport to be
335  * created if a monitor callback needs to reestablish a link.
336  * PJPROJECT sets the flag after this routine returns even though
337  * it has already called the transport's shutdown routine.
338  */
339  transport->is_shutdown = PJ_TRUE;
340 
341  transport_state_do_reg_callbacks(transports, transport);
342  break;
343  case PJSIP_TP_STATE_DESTROY:
344  transport_state_do_reg_callbacks(transports, transport);
345  break;
346  default:
347  /*
348  * We have to have a default case because the enum is
349  * defined by a third-party library.
350  */
351  ast_assert(0);
352  break;
353  }
354 
355  ao2_ref(transports, -1);
356  }
357 
358  /* Loop over other transport state callbacks registered with us. */
360  struct ast_sip_tpmgr_state_callback *tpmgr_notifier;
361 
363  AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) {
364  tpmgr_notifier->cb(transport, state, info);
365  }
367  }
368 
369  /* Forward to the old state callback if present */
370  if (tpmgr_state_callback) {
371  tpmgr_state_callback(transport, state, info);
372  }
373 }
374 
376  ast_transport_monitor_shutdown_cb cb;
377  void *data;
378  ast_transport_monitor_data_matcher matches;
379 };
380 
381 static int transport_monitor_unregister_cb(void *obj, void *arg, int flags)
382 {
383  struct transport_monitor *monitored = obj;
384  struct callback_data *cb_data = arg;
385  int idx;
386 
387  for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {
388  struct transport_monitor_notifier *notifier;
389 
390  notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);
391  if (notifier->cb == cb_data->cb && (!cb_data->data
392  || cb_data->matches(cb_data->data, notifier->data))) {
393  ao2_cleanup(notifier->data);
394  AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx);
395  ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : Unregistered monitor %p(%p)\n",
396  monitored->key, monitored->transport_obj_name,
397  monitored->transport->type_name,
398  pj_atomic_get(monitored->transport->ref_cnt), notifier->cb, notifier->data);
399  }
400  }
401  return 0;
402 }
403 
404 static int ptr_matcher(void *a, void *b)
405 {
406  return a == b;
407 }
408 
409 void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb,
410  void *data, ast_transport_monitor_data_matcher matches)
411 {
412  struct ao2_container *transports;
413  struct callback_data cb_data = {
414  .cb = cb,
415  .data = data,
416  .matches = matches ?: ptr_matcher,
417  };
418 
419  ast_assert(cb != NULL);
420 
421  transports = ao2_global_obj_ref(active_transports);
422  if (!transports) {
423  return;
424  }
425  ao2_callback(transports, OBJ_MULTIPLE | OBJ_NODATA, transport_monitor_unregister_cb, &cb_data);
426  ao2_ref(transports, -1);
427 }
428 
429 void ast_sip_transport_monitor_unregister(pjsip_transport *transport,
430  ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
431 {
432  char key[IP6ADDR_COLON_PORT_BUFLEN];
433  AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key);
434  ast_sip_transport_monitor_unregister_key(key, cb, data, matches);
435 }
436 
437 void ast_sip_transport_monitor_unregister_key(const char *transport_key,
438  ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
439 {
440  struct ao2_container *transports;
441  struct transport_monitor *monitored;
442 
443  ast_assert(transport_key != NULL && cb != NULL);
444 
445  transports = ao2_global_obj_ref(active_transports);
446  if (!transports) {
447  return;
448  }
449 
450  ao2_lock(transports);
451  monitored = ao2_find(transports, transport_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
452  if (monitored) {
453  struct callback_data cb_data = {
454  .cb = cb,
455  .data = data,
456  .matches = matches ?: ptr_matcher,
457  };
458 
459  transport_monitor_unregister_cb(monitored, &cb_data, 0);
460  ao2_ref(monitored, -1);
461  }
462  ao2_unlock(transports);
463  ao2_ref(transports, -1);
464 }
465 
466 enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport,
467  ast_transport_monitor_shutdown_cb cb, void *ao2_data)
468 {
469  char key[IP6ADDR_COLON_PORT_BUFLEN];
470  AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key);
471 
472  return ast_sip_transport_monitor_register_replace_key(key, cb, ao2_data, NULL);
473 }
474 
475 enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key(const char *transport_key,
476  ast_transport_monitor_shutdown_cb cb, void *ao2_data)
477 {
478  return ast_sip_transport_monitor_register_replace_key(transport_key, cb, ao2_data, NULL);
479 }
480 
481 enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_transport *transport,
482  ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches)
483 {
484  char key[IP6ADDR_COLON_PORT_BUFLEN];
485 
486  AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key);
487  return ast_sip_transport_monitor_register_replace_key(key, cb, ao2_data, NULL);
488 }
489 
490 enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace_key(const char *transport_key,
491  ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches)
492 {
493  struct ao2_container *transports;
494  struct transport_monitor *monitored;
495  enum ast_transport_monitor_reg res = AST_TRANSPORT_MONITOR_REG_NOT_FOUND;
496 
497  ast_assert(transport_key != NULL && cb != NULL);
498 
499  transports = ao2_global_obj_ref(active_transports);
500  if (!transports) {
501  return res;
502  }
503 
504  ao2_lock(transports);
505  monitored = ao2_find(transports, transport_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
506  if (monitored) {
507  struct transport_monitor_notifier new_monitor;
508  struct callback_data cb_data = {
509  .cb = cb,
510  .data = ao2_data,
511  .matches = matches ?: ptr_matcher,
512  };
513 
514  transport_monitor_unregister_cb(monitored, &cb_data, 0);
515 
516  /* Add new monitor to vector */
517  new_monitor.cb = cb;
518  new_monitor.data = ao2_bump(ao2_data);
519  if (AST_VECTOR_APPEND(&monitored->monitors, new_monitor)) {
520  ao2_cleanup(ao2_data);
521  res = AST_TRANSPORT_MONITOR_REG_FAILED;
522  ast_debug(3, "Transport %s(%s) RefCnt: %ld : Monitor registration failed %p(%p)\n",
523  monitored->key, monitored->transport_obj_name,
524  pj_atomic_get(monitored->transport->ref_cnt), cb, ao2_data);
525  } else {
526  res = AST_TRANSPORT_MONITOR_REG_SUCCESS;
527  ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : Registered monitor %p(%p)\n",
528  monitored->key, monitored->transport_obj_name,
529  monitored->transport->type_name,
530  pj_atomic_get(monitored->transport->ref_cnt), cb, ao2_data);
531  }
532 
533  ao2_ref(monitored, -1);
534  }
535  ao2_unlock(transports);
536  ao2_ref(transports, -1);
537  return res;
538 }
539 
541 {
545 }
546 
548 {
549  struct ast_sip_tpmgr_state_callback *tpmgr_notifier;
550 
552  AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) {
553  if (element == tpmgr_notifier) {
554  /* Already registered. */
556  return;
557  }
558  }
561 }
562 
563 static char *cli_show_monitors(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
564 {
565  char *cli_rc = CLI_FAILURE;
566  int rc = 0;
567  int using_regex = 0;
568  regex_t regex = { 0, };
569  int container_count;
570  struct ao2_iterator iter;
571  struct ao2_container *sorted_monitors = NULL;
572  struct ao2_container *transports;
573  struct transport_monitor *monitored;
574 
575  switch (cmd) {
576  case CLI_INIT:
577  e->command = "pjsip show transport-monitors";
578  e->usage = "Usage: pjsip show transport-monitors [ like <pattern> ]\n"
579  " Show pjsip transport monitors\n";
580  return NULL;
581  case CLI_GENERATE:
582  return NULL;
583  }
584 
585  if (a->argc != 3 && a->argc != 5) {
586  return CLI_SHOWUSAGE;
587  }
588 
589  if (a->argc == 5) {
590  int regrc;
591  if (strcasecmp(a->argv[3], "like")) {
592  return CLI_SHOWUSAGE;
593  }
594  regrc = regcomp(&regex, a->argv[4], REG_EXTENDED | REG_ICASE | REG_NOSUB);
595  if (regrc) {
596  char err[256];
597  regerror(regrc, &regex, err, 256);
598  ast_cli(a->fd, "PJSIP Transport Monitor: Error: %s\n", err);
599  return CLI_FAILURE;
600  }
601  using_regex = 1;
602  }
603 
604  /* Get a sorted snapshot of the scheduled tasks */
606  transport_monitor_sort_fn, NULL);
607  if (!sorted_monitors) {
608  ast_cli(a->fd, "PJSIP Transport Monitor: Unable to allocate temporary container\n");
609  goto error;
610  }
611 
612  transports = ao2_global_obj_ref(active_transports);
613  if (!transports) {
614  ast_cli(a->fd, "PJSIP Transport Monitor: Unable to get transports\n");
615  goto error;
616  }
617 
618  ao2_lock(transports);
619  rc = ao2_container_dup(sorted_monitors, transports, 0);
620  ao2_unlock(transports);
621  ao2_ref(transports, -1);
622  if (rc != 0) {
623  ast_cli(a->fd, "PJSIP Transport Monitors: Unable to sort temporary container\n");
624  goto error;
625  }
626  container_count = ao2_container_count(sorted_monitors);
627 
628  ast_cli(a->fd, "PJSIP Transport Monitors:\n\n");
629 
630  ast_cli(a->fd,
631  "<Remote Host...................................> <State.....> <Direction> <RefCnt> <Monitors> <ObjName............>\n");
632 
633  iter = ao2_iterator_init(sorted_monitors, AO2_ITERATOR_UNLINK);
634  for (; (monitored = ao2_iterator_next(&iter)); ao2_ref(monitored, -1)) {
635  char *state;
636 
637  if (using_regex && regexec(&regex, monitored->key, 0, NULL, 0) == REG_NOMATCH) {
638  continue;
639  }
640 
641  if (monitored->transport->is_destroying) {
642  state = "DESTROYING";
643  } else if (monitored->transport->is_shutdown) {
644  state = "SHUTDOWN";
645  } else {
646  state = "ACTIVE";
647  }
648 
649  ast_cli(a->fd, " %-46.46s %-10s %-9s %6ld %8zu %s\n",
650  monitored->key, state,
651  monitored->transport->dir == PJSIP_TP_DIR_OUTGOING ? "Outgoing" : "Incoming",
652  pj_atomic_get(monitored->transport->ref_cnt),
653  AST_VECTOR_SIZE(&monitored->monitors), monitored->transport->obj_name);
654  }
655  ao2_iterator_destroy(&iter);
656  ast_cli(a->fd, "\nTotal Transport Monitors: %d\n\n", container_count);
657  cli_rc = CLI_SUCCESS;
658 error:
659  if (using_regex) {
660  regfree(&regex);
661  }
662  ao2_cleanup(sorted_monitors);
663 
664  return cli_rc;
665 }
666 
667 static struct ast_cli_entry cli_commands[] = {
668  AST_CLI_DEFINE(cli_show_monitors, "Show pjsip transport monitors"),
669 };
670 
671 void ast_sip_destroy_transport_events(void)
672 {
673  pjsip_tpmgr *tpmgr;
674 
675  ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
676 
677  tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());
678  if (tpmgr) {
679  pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback);
680  }
681 
682  ao2_global_obj_release(active_transports);
683 }
684 
685 int ast_sip_initialize_transport_events(void)
686 {
687  pjsip_tpmgr *tpmgr;
688  struct ao2_container *transports;
689 
690  tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());
691  if (!tpmgr) {
692  return -1;
693  }
694 
696  ACTIVE_TRANSPORTS_BUCKETS, transport_monitor_hash_fn, transport_monitor_sort_fn,
697  transport_monitor_cmp_fn);
698  if (!transports) {
699  return -1;
700  }
701  ao2_global_obj_replace_unref(active_transports, transports);
702  ao2_ref(transports, -1);
703 
704  tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr);
705  pjsip_tpmgr_set_state_cb(tpmgr, &transport_state_callback);
706 
707  ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
708 
709 
710  return 0;
711 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
Definition: test_heap.c:38
Asterisk main include file. File version handling, generic pbx functions.
AO2_STRING_FIELD_HASH_FN(transport_monitor, key)
Hashing function for struct transport_monitor.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
static pjsip_tp_state_callback tpmgr_state_callback
Existing transport events callback that we need to invoke.
descriptor for a cli entry.
Definition: cli.h:171
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1693
static struct @461 transport_state_list
#define ACTIVE_TRANSPORTS_BUCKETS
Number of buckets for monitored active transports.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
AO2_STRING_FIELD_CMP_FN(transport_monitor, key)
Comparison function for struct transport_monitor.
#define AST_VECTOR_REMOVE_UNORDERED(vec, idx)
Remove an element from an unordered vector by index.
Definition: vector.h:438
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
struct transport_monitor::@462 monitors
void ast_sip_transport_monitor_unregister_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
static int log_level
Log level for history output.
static void transport_state_callback(pjsip_transport *transport, pjsip_transport_state state, const pjsip_transport_state_info *info)
Callback invoked when transport state changes occur.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *ao2_data)
Register a reliable transport shutdown monitor callback.
Structure for transport to be monitored.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
Structure for SIP transport information.
Definition: res_pjsip.h:119
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition: vector.h:668
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
A set of macros to manage forward-linked lists.
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.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches)
Register a reliable transport shutdown monitor callback replacing any duplicate.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
pjsip_transport * transport
The underlying PJSIP transport.
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches)
Register a reliable transport shutdown monitor callback replacing any duplicate.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
char * command
Definition: cli.h:186
static AO2_GLOBAL_OBJ_STATIC(active_transports)
Global container of active reliable transports.
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.
pjsip_tp_state_callback cb
Definition: res_pjsip.h:4074
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.
Vector container support.
ast_transport_monitor_shutdown_cb cb
#define AST_RWLIST_HEAD(name, type)
Defines a structure to be used to hold a read/write list of specified type.
Definition: linkedlists.h:199
const char * usage
Definition: cli.h:177
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
Generic container type.
AO2_STRING_FIELD_SORT_FN(transport_monitor, key)
Sort function for struct transport_monitor.
void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element)
Unregister a transport state notification callback element.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
char key[IP6ADDR_COLON_PORT_BUFLEN]
Key :
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *element)
Register a transport state notification callback element.
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532