Asterisk - The Open Source Telephony Project  21.4.1
config_transport.c
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 #include "asterisk.h"
20 
21 #include <math.h>
22 #include <pjsip.h>
23 #include <pjlib.h>
24 
25 #include "asterisk/res_pjsip.h"
26 #include "asterisk/res_pjsip_cli.h"
27 #include "asterisk/logger.h"
28 #include "asterisk/astobj2.h"
29 #include "asterisk/sorcery.h"
30 #include "asterisk/acl.h"
31 #include "asterisk/utils.h"
32 #include "include/res_pjsip_private.h"
33 /* We're only using a #define from http_websocket.h, no OPTIONAL_API symbols are used. */
35 
36 #define MAX_POINTER_STRING 33
37 
38 /*! \brief Default number of state container buckets */
39 #define DEFAULT_STATE_BUCKETS 53
40 static struct ao2_container *transport_states;
41 
43  char *id;
44  /*! Set if there was a change detected */
46  /*! \brief Transport configuration object */
48  /*! \brief Transport state information */
50 };
51 
52 static void temp_state_store_cleanup(void *data)
53 {
54  struct ast_sip_transport_state **temp_state = data;
55 
56  ao2_cleanup(*temp_state);
57  ast_free(data);
58 }
59 
60 AST_THREADSTORAGE_CUSTOM(temp_state_store, NULL, temp_state_store_cleanup);
61 
62 /*! \brief hashing function for state objects */
63 static int internal_state_hash(const void *obj, const int flags)
64 {
65  const struct internal_state *object;
66  const char *key;
67 
68  switch (flags & OBJ_SEARCH_MASK) {
69  case OBJ_SEARCH_KEY:
70  key = obj;
71  break;
72  case OBJ_SEARCH_OBJECT:
73  object = obj;
74  key = object->id;
75  break;
76  default:
77  ast_assert(0);
78  return 0;
79  }
80  return ast_str_hash(key);
81 }
82 
83 /*! \brief comparator function for state objects */
84 static int internal_state_cmp(void *obj, void *arg, int flags)
85 {
86  const struct internal_state *object_left = obj;
87  const struct internal_state *object_right = arg;
88  const char *right_key = arg;
89  int cmp;
90 
91  switch (flags & OBJ_SEARCH_MASK) {
92  case OBJ_SEARCH_OBJECT:
93  right_key = object_right->id;
94  /* Fall through */
95  case OBJ_SEARCH_KEY:
96  cmp = strcmp(object_left->id, right_key);
97  break;
99  /* Not supported by container. */
100  ast_assert(0);
101  return 0;
102  default:
103  cmp = 0;
104  break;
105  }
106  if (cmp) {
107  return 0;
108  }
109  return CMP_MATCH;
110 }
111 
112 /*! \brief hashing function for state objects */
113 static int transport_state_hash(const void *obj, const int flags)
114 {
115  const struct ast_sip_transport_state *object;
116  const char *key;
117 
118  switch (flags & OBJ_SEARCH_MASK) {
119  case OBJ_SEARCH_KEY:
120  key = obj;
121  break;
122  case OBJ_SEARCH_OBJECT:
123  object = obj;
124  key = object->id;
125  break;
126  default:
127  ast_assert(0);
128  return 0;
129  }
130  return ast_str_hash(key);
131 }
132 
133 /*! \brief comparator function for state objects */
134 static int transport_state_cmp(void *obj, void *arg, int flags)
135 {
136  const struct ast_sip_transport_state *object_left = obj;
137  const struct ast_sip_transport_state *object_right = arg;
138  const char *right_key = arg;
139  int cmp;
140 
141  switch (flags & OBJ_SEARCH_MASK) {
142  case OBJ_SEARCH_OBJECT:
143  right_key = object_right->id;
144  /* Fall through */
145  case OBJ_SEARCH_KEY:
146  cmp = strcmp(object_left->id, right_key);
147  break;
149  /* Not supported by container. */
150  ast_assert(0);
151  return 0;
152  default:
153  cmp = 0;
154  break;
155  }
156  if (cmp) {
157  return 0;
158  }
159  return CMP_MATCH;
160 }
161 
162 static int sip_transport_to_ami(const struct ast_sip_transport *transport,
163  struct ast_str **buf)
164 {
165  return ast_sip_sorcery_object_to_ami(transport, buf);
166 }
167 
168 static int format_ami_endpoint_transport(const struct ast_sip_endpoint *endpoint,
169  struct ast_sip_ami *ami)
170 {
171  RAII_VAR(struct ast_str *, buf, NULL, ast_free);
172  RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
173 
174  if (ast_strlen_zero(endpoint->transport)) {
175  return 0;
176  }
177 
178  buf = ast_sip_create_ami_event("TransportDetail", ami);
179  if (!buf) {
180  return -1;
181  }
182 
183  transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
184  endpoint->transport);
185  if (!transport) {
186  astman_send_error_va(ami->s, ami->m, "Unable to retrieve "
187  "transport %s\n", endpoint->transport);
188  return -1;
189  }
190 
191  sip_transport_to_ami(transport, &buf);
192 
193  ast_str_append(&buf, 0, "EndpointName: %s\r\n",
194  ast_sorcery_object_get_id(endpoint));
195 
196  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
197  ami->count++;
198 
199  return 0;
200 }
201 
202 struct ast_sip_endpoint_formatter endpoint_transport_formatter = {
203  .format_ami = format_ami_endpoint_transport
204 };
205 
206 int ast_sip_transport_state_set_transport(const char *transport_name, pjsip_transport *transport)
207 {
208  struct ast_sip_transport_state *transport_state;
209 
210  /* To make it easier on callers we allow an empty transport name */
211  if (ast_strlen_zero(transport_name)) {
212  return 0;
213  }
214 
215  transport_state = ast_sip_get_transport_state(transport_name);
216  if (!transport_state) {
217  return -1;
218  }
219 
220  if (!transport_state->flow) {
221  ao2_ref(transport_state, -1);
222  return 0;
223  }
224 
225  ao2_lock(transport_state);
226  if (transport_state->transport != transport) {
227  if (transport_state->transport) {
228  pjsip_transport_dec_ref(transport_state->transport);
229  }
230  transport_state->transport = transport;
231  if (transport_state->transport) {
232  pjsip_transport_add_ref(transport_state->transport);
233  }
234  }
235  ao2_unlock(transport_state);
236 
237  ao2_ref(transport_state, -1);
238 
239  return 0;
240 }
241 
242 int ast_sip_transport_state_set_preferred_identity(const char *transport_name, const char *identity)
243 {
244  struct ast_sip_transport_state *transport_state;
245 
246  if (ast_strlen_zero(transport_name)) {
247  return 0;
248  }
249 
250  transport_state = ast_sip_get_transport_state(transport_name);
251  if (!transport_state) {
252  return -1;
253  }
254 
255  if (!transport_state->flow) {
256  ao2_ref(transport_state, -1);
257  return 0;
258  }
259 
260  ao2_lock(transport_state);
261  ast_free(transport_state->preferred_identity);
262  transport_state->preferred_identity = ast_strdup(identity);
263  ao2_unlock(transport_state);
264 
265  ao2_ref(transport_state, -1);
266 
267  return 0;
268 }
269 
270 int ast_sip_transport_state_set_service_routes(const char *transport_name, struct ast_sip_service_route_vector *service_routes)
271 {
272  struct ast_sip_transport_state *transport_state;
273 
274  if (ast_strlen_zero(transport_name)) {
275  ast_sip_service_route_vector_destroy(service_routes);
276  return 0;
277  }
278 
279  transport_state = ast_sip_get_transport_state(transport_name);
280  if (!transport_state) {
281  ast_sip_service_route_vector_destroy(service_routes);
282  return -1;
283  }
284 
285  if (!transport_state->flow) {
286  ao2_ref(transport_state, -1);
287  ast_sip_service_route_vector_destroy(service_routes);
288  return 0;
289  }
290 
291  ao2_lock(transport_state);
292  ast_sip_service_route_vector_destroy(transport_state->service_routes);
293  transport_state->service_routes = service_routes;
294  ao2_unlock(transport_state);
295 
296  ao2_ref(transport_state, -1);
297 
298  return 0;
299 }
300 
301 void ast_sip_message_apply_transport(const char *transport_name, pjsip_tx_data *tdata)
302 {
303  struct ast_sip_transport_state *transport_state;
304 
305  if (ast_strlen_zero(transport_name)) {
306  return;
307  }
308 
309  /* We only currently care about requests that are of the INVITE, CANCEL, or OPTIONS
310  * type but in the future we could support other messages.
311  */
312  if (tdata->msg->type != PJSIP_REQUEST_MSG ||
313  (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method) &&
314  pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_cancel_method) &&
315  pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_options_method))) {
316  return;
317  }
318 
319  transport_state = ast_sip_get_transport_state(transport_name);
320  if (!transport_state) {
321  return;
322  }
323 
324  if (!transport_state->flow) {
325  ao2_ref(transport_state, -1);
326  return;
327  }
328 
329  ao2_lock(transport_state);
330 
331  /* If a Preferred Identity has been set then add it to the request */
332  if (transport_state->preferred_identity) {
333  ast_sip_add_header(tdata, "P-Preferred-Identity", transport_state->preferred_identity);
334  }
335 
336  /* If Service Routes have been set then add them to the request */
337  if (transport_state->service_routes) {
338  int idx;
339 
340  for (idx = 0; idx < AST_VECTOR_SIZE(transport_state->service_routes); ++idx) {
341  char *service_route = AST_VECTOR_GET(transport_state->service_routes, idx);
342 
343  ast_sip_add_header(tdata, "Route", service_route);
344  }
345  }
346 
347  ao2_unlock(transport_state);
348 
349  ao2_ref(transport_state, -1);
350 }
351 
352 struct ast_sip_service_route_vector *ast_sip_service_route_vector_alloc(void)
353 {
354  struct ast_sip_service_route_vector *service_routes;
355 
356  service_routes = ast_calloc(1, sizeof(*service_routes));
357  if (!service_routes) {
358  return NULL;
359  }
360 
361  AST_VECTOR_INIT(service_routes, 0);
362 
363  return service_routes;
364 }
365 
366 void ast_sip_service_route_vector_destroy(struct ast_sip_service_route_vector *service_routes)
367 {
368  if (!service_routes) {
369  return;
370  }
371 
372  AST_VECTOR_CALLBACK_VOID(service_routes, ast_free);
373  ast_free(service_routes);
374 }
375 
376 static void set_qos(struct ast_sip_transport *transport, pj_qos_params *qos)
377 {
378  int tos_as_dscp = transport->tos >> 2;
379 
380  if (transport->tos) {
381  qos->flags |= PJ_QOS_PARAM_HAS_DSCP;
382  qos->dscp_val = tos_as_dscp;
383  }
384  if (transport->cos) {
385  qos->flags |= PJ_QOS_PARAM_HAS_SO_PRIO;
386  qos->so_prio = transport->cos;
387  }
388 }
389 
390 /*! \brief Destructor for transport */
391 static void sip_transport_destroy(void *obj)
392 {
393  struct ast_sip_transport *transport = obj;
394 
395  ast_string_field_free_memory(transport);
396 }
397 
398 /*! \brief Allocator for transport */
399 static void *sip_transport_alloc(const char *name)
400 {
401  struct ast_sip_transport *transport = ast_sorcery_generic_alloc(sizeof(*transport), sip_transport_destroy);
402 
403  if (!transport) {
404  return NULL;
405  }
406 
407  if (ast_string_field_init(transport, 256)) {
408  ao2_cleanup(transport);
409  return NULL;
410  }
411 
412  return transport;
413 }
414 
415 static int destroy_sip_transport_state(void *data)
416 {
417  struct ast_sip_transport_state *transport_state = data;
418 
419  ast_free(transport_state->id);
420  ast_free_ha(transport_state->localnet);
421 
422  if (transport_state->external_signaling_address_refresher) {
424  }
425  if (transport_state->external_media_address_refresher) {
427  }
428  if (transport_state->transport) {
429  pjsip_transport_shutdown(transport_state->transport);
430  }
431 
432  return 0;
433 }
434 
435 /*! \brief Destructor for ast_sip_transport state information */
436 static void sip_transport_state_destroy(void *obj)
437 {
438  struct ast_sip_transport_state *state = obj;
439 
440  ast_sip_push_task_wait_servant(NULL, destroy_sip_transport_state, state);
441 }
442 
443 /*! \brief Destructor for ast_sip_transport state information */
444 static void internal_state_destroy(void *obj)
445 {
446  struct internal_state *state = obj;
447 
448  ast_free(state->id);
449  ao2_cleanup(state->transport);
450  ao2_cleanup(state->state);
451 }
452 
453 static struct internal_state *find_internal_state_by_transport(const struct ast_sip_transport *transport)
454 {
455  const char *key = ast_sorcery_object_get_id(transport);
456 
457  return ao2_find(transport_states, key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
458 }
459 
460 static struct ast_sip_transport_state *find_state_by_transport(const struct ast_sip_transport *transport)
461 {
462  struct internal_state *state;
463  struct ast_sip_transport_state *trans_state;
464 
465  state = find_internal_state_by_transport(transport);
466  if (!state) {
467  return NULL;
468  }
469  trans_state = ao2_bump(state->state);
470  ao2_ref(state, -1);
471 
472  return trans_state;
473 }
474 
475 static int remove_temporary_state(void)
476 {
477  struct ast_sip_transport_state **state;
478 
479  state = ast_threadstorage_get(&temp_state_store, sizeof(state));
480  if (!state) {
481  return -1;
482  }
483 
484  ao2_cleanup(*state);
485  *state = NULL;
486  return 0;
487 }
488 
489 static struct ast_sip_transport_state *find_temporary_state(struct ast_sip_transport *transport)
490 {
491  struct ast_sip_transport_state **state;
492 
493  state = ast_threadstorage_get(&temp_state_store, sizeof(state));
494  if (state && *state) {
495  ao2_ref(*state, +1);
496  return *state;
497  }
498 
499  return NULL;
500 }
501 
502 static struct internal_state *internal_state_alloc(struct ast_sip_transport *transport)
503 {
505 
506  internal_state = ao2_alloc(sizeof(*internal_state), internal_state_destroy);
507  if (!internal_state) {
508  return NULL;
509  }
510 
511  internal_state->id = ast_strdup(ast_sorcery_object_get_id(transport));
512  if (!internal_state->id) {
513  ao2_cleanup(internal_state);
514  return NULL;
515  }
516 
517  /* We're transferring the reference from find_temporary_state */
518  internal_state->state = find_temporary_state(transport);
519  if (!internal_state->state) {
520  ao2_cleanup(internal_state);
521  return NULL;
522  }
523  internal_state->transport = ao2_bump(transport);
524  internal_state->transport->state = internal_state->state;
525  remove_temporary_state();
526 
527  return internal_state;
528 }
529 
530 /*!
531  * \internal
532  * \brief Should only be called by the individual field handlers
533  */
534 static struct ast_sip_transport_state *find_or_create_temporary_state(struct ast_sip_transport *transport)
535 {
536  struct ast_sip_transport_state **state;
537  struct ast_sip_transport_state *new_state;
538 
539  if ((new_state = find_temporary_state(transport))) {
540  return new_state;
541  }
542 
543  state = ast_threadstorage_get(&temp_state_store, sizeof(state));
544  if (!state || *state) {
545  return NULL;
546  }
547 
548  new_state = ao2_alloc(sizeof(**state), sip_transport_state_destroy);
549  if (!new_state) {
550  return NULL;
551  }
552  new_state->id = ast_strdup(ast_sorcery_object_get_id(transport));
553  new_state->type = transport->type;
554 
555  pjsip_tls_setting_default(&new_state->tls);
556 #ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO
557  /* proto must be forced to 0 to enable all protocols otherwise only TLS will work */
558  new_state->tls.proto = 0;
559 #endif
560  new_state->tls.ciphers = new_state->ciphers;
561 
562  ao2_ref(new_state, +1);
563  *state = new_state;
564 
565  return new_state;
566 }
567 
568 static void copy_state_to_transport(struct ast_sip_transport *transport)
569 {
570  ast_assert(transport && transport->state);
571 
572  memcpy(&transport->host, &transport->state->host, sizeof(transport->host));
573  memcpy(&transport->tls, &transport->state->tls, sizeof(transport->tls));
574  memcpy(&transport->ciphers, &transport->state->ciphers, sizeof(transport->ciphers));
575  transport->localnet = transport->state->localnet;
577  memcpy(&transport->external_address, &transport->state->external_signaling_address, sizeof(transport->external_signaling_address));
578 }
579 
580 #ifdef HAVE_PJSIP_TLS_TRANSPORT_RESTART
581 static int file_stat_cmp(const struct stat *old_stat, const struct stat *new_stat)
582 {
583  return old_stat->st_size != new_stat->st_size
584  || old_stat->st_mtime != new_stat->st_mtime
585 #if defined(HAVE_STRUCT_STAT_ST_MTIM)
586  || old_stat->st_mtim.tv_nsec != new_stat->st_mtim.tv_nsec
587 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
588  || old_stat->st_mtimensec != new_stat->st_mtimensec
589 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
590  || old_stat->st_mtimespec.tv_nsec != new_stat->st_mtimespec.tv_nsec
591 #endif
592  ;
593 }
594 #endif
595 
596 static int has_state_changed(struct ast_sip_transport_state *a, struct ast_sip_transport_state *b)
597 {
598  if (a->type != b->type) {
599  return -1;
600  }
601 
602  if (pj_sockaddr_cmp(&a->host, &b->host)) {
603  return -1;
604  }
605 
606  if ((a->localnet || b->localnet)
607  && ((!a->localnet != !b->localnet)
608  || ast_sockaddr_cmp(&a->localnet->addr, &b->localnet->addr)
609  || ast_sockaddr_cmp(&a->localnet->netmask, &b->localnet->netmask)))
610  {
611  return -1;
612  }
613 
615  return -1;
616  }
617 
619  return -1;
620  }
621 
622  if (a->tls.method != b->tls.method
623  || a->tls.ciphers_num != b->tls.ciphers_num
624 #ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO
625  || a->tls.proto != b->tls.proto
626 #endif
627  || a->tls.verify_client != b->tls.verify_client
628  || a->tls.verify_server != b->tls.verify_server
629  || a->tls.require_client_cert != b->tls.require_client_cert) {
630  return -1;
631  }
632 
633  if (memcmp(a->ciphers, b->ciphers, sizeof(pj_ssl_cipher) * fmax(a->tls.ciphers_num, b->tls.ciphers_num))) {
634  return -1;
635  }
636 
637 #ifdef HAVE_PJSIP_TLS_TRANSPORT_RESTART
638  if (file_stat_cmp(&a->cert_file_stat, &b->cert_file_stat) || file_stat_cmp(&a->privkey_file_stat, &b->privkey_file_stat)) {
639  return -1;
640  }
641 #endif
642 
643  return 0;
644 }
645 
646 static void states_cleanup(void *states)
647 {
648  if (states) {
649  ao2_unlock(states);
650  }
651 }
652 
653 /*! \brief Apply handler for transports */
654 static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
655 {
656  struct ast_sip_transport *transport = obj;
657  const char *transport_id = ast_sorcery_object_get_id(obj);
658  RAII_VAR(struct ao2_container *, states, transport_states, states_cleanup);
659  RAII_VAR(struct internal_state *, temp_state, NULL, ao2_cleanup);
660  RAII_VAR(struct internal_state *, perm_state, NULL, ao2_cleanup);
661  RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
662  pj_status_t res = -1;
663  int i;
664 #define BIND_TRIES 3
665 #define BIND_DELAY_US 100000
666 
667  if (!states) {
668  return -1;
669  }
670 
671  /*
672  * transport_apply gets called for EVERY retrieval of a transport when using realtime.
673  * We need to prevent multiple threads from trying to mess with underlying transports
674  * at the same time. The container is the only thing we have to lock on.
675  */
676  ao2_wrlock(states);
677 
678  temp_state = internal_state_alloc(transport);
679  if (!temp_state) {
680  ast_log(LOG_ERROR, "Transport '%s' failed to allocate memory\n", transport_id);
681  return -1;
682  }
683 
684  if (transport->async_operations != 1) {
685  ast_log(LOG_WARNING, "The async_operations setting on transport '%s' has been set to '%d'. The setting can no longer be set and is always 1.\n",
686  transport_id, transport->async_operations);
687  transport->async_operations = 1;
688  }
689 
690  perm_state = find_internal_state_by_transport(transport);
691  if (perm_state) {
692  ast_sorcery_diff(sorcery, perm_state->transport, transport, &changes);
693  if (!changes && !has_state_changed(perm_state->state, temp_state->state)) {
694  /* In case someone is using the deprecated fields, reset them */
695  transport->state = perm_state->state;
696  copy_state_to_transport(transport);
697  ao2_replace(perm_state->transport, transport);
698  return 0;
699  }
700 
701  /* If we aren't allowed to reload then we copy values that can't be changed from perm_state */
702  if (!transport->allow_reload) {
703  memcpy(&temp_state->state->host, &perm_state->state->host, sizeof(temp_state->state->host));
704  memcpy(&temp_state->state->tls, &perm_state->state->tls, sizeof(temp_state->state->tls));
705  memcpy(&temp_state->state->ciphers, &perm_state->state->ciphers, sizeof(temp_state->state->ciphers));
706  }
707  }
708 
709  if (!transport->flow && (!perm_state || transport->allow_reload)) {
710  if (temp_state->state->host.addr.sa_family != PJ_AF_INET && temp_state->state->host.addr.sa_family != PJ_AF_INET6) {
711  ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", transport_id);
712  return -1;
713  }
714 
715  /* Set default port if not present */
716  if (!pj_sockaddr_get_port(&temp_state->state->host)) {
717  pj_sockaddr_set_port(&temp_state->state->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060);
718  }
719  }
720 
721  /* Now that we know what address family we can set up a dnsmgr refresh for the external addresses if present */
722  if (!ast_strlen_zero(transport->external_signaling_address)) {
723  if (temp_state->state->host.addr.sa_family == pj_AF_INET()) {
724  temp_state->state->external_signaling_address.ss.ss_family = AF_INET;
725  } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) {
726  temp_state->state->external_signaling_address.ss.ss_family = AF_INET6;
727  } else {
728  ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n",
729  transport_id);
730  return -1;
731  }
732 
733  if (ast_dnsmgr_lookup(transport->external_signaling_address, &temp_state->state->external_signaling_address, &temp_state->state->external_signaling_address_refresher, NULL) < 0) {
734  ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", transport_id);
735  return -1;
736  }
737  }
738 
739  if (!ast_strlen_zero(transport->external_media_address)) {
740  if (temp_state->state->host.addr.sa_family == pj_AF_INET()) {
741  temp_state->state->external_media_address.ss.ss_family = AF_INET;
742  } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) {
743  temp_state->state->external_media_address.ss.ss_family = AF_INET6;
744  } else {
745  ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external media address\n",
746  transport_id);
747  return -1;
748  }
749 
750  if (ast_dnsmgr_lookup(transport->external_media_address, &temp_state->state->external_media_address, &temp_state->state->external_media_address_refresher, NULL) < 0) {
751  ast_log(LOG_ERROR, "Could not create dnsmgr for external media address on '%s'\n", transport_id);
752  return -1;
753  }
754  }
755 
756  if (transport->flow) {
757  pj_str_t address;
758 
759  ast_debug(1, "Ignoring any bind configuration on transport '%s' as it is a child of another\n",
760  transport_id);
761  pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&address, "0.0.0.0"), &temp_state->state->host);
762 
763  temp_state->state->flow = 1;
764  res = PJ_SUCCESS;
765  } else if (!transport->allow_reload && perm_state) {
766  /* We inherit the transport from perm state, untouched */
767 #ifdef HAVE_PJSIP_TLS_TRANSPORT_RESTART
768  ast_log(LOG_NOTICE, "Transport '%s' is not fully reloadable, not reloading: protocol, bind, TLS (everything but certificate and private key if filename is unchanged), TCP, ToS, or CoS options.\n", transport_id);
769  /* If this is a TLS transport and the certificate or private key has changed, then restart the transport so it uses the new one */
770  if (transport->type == AST_TRANSPORT_TLS) {
771  if (strcmp(perm_state->transport->cert_file, temp_state->transport->cert_file) ||
772  strcmp(perm_state->transport->privkey_file, temp_state->transport->privkey_file)) {
773  ast_log(LOG_ERROR, "Unable to restart TLS transport '%s' as certificate or private key filename has changed\n",
774  transport_id);
775  } else if (file_stat_cmp(&perm_state->state->cert_file_stat, &temp_state->state->cert_file_stat) ||
776  file_stat_cmp(&perm_state->state->privkey_file_stat, &temp_state->state->privkey_file_stat)) {
777  if (pjsip_tls_transport_restart(perm_state->state->factory, &perm_state->state->host, NULL) != PJ_SUCCESS) {
778  ast_log(LOG_ERROR, "Failed to restart TLS transport '%s'\n", transport_id);
779  } else {
780  sprintf(perm_state->state->factory->info, "%s", transport_id);
781  }
782  }
783  }
784 #else
785  ast_log(LOG_NOTICE, "Transport '%s' is not fully reloadable, not reloading: protocol, bind, TLS, TCP, ToS, or CoS options.\n", transport_id);
786 #endif
787  temp_state->state->transport = perm_state->state->transport;
788  perm_state->state->transport = NULL;
789  temp_state->state->factory = perm_state->state->factory;
790  perm_state->state->factory = NULL;
791 
792  res = PJ_SUCCESS;
793  } else if (transport->type == AST_TRANSPORT_UDP) {
794 
795  for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) {
796  if (perm_state && perm_state->state && perm_state->state->transport) {
797  pjsip_udp_transport_pause(perm_state->state->transport,
798  PJSIP_UDP_TRANSPORT_DESTROY_SOCKET);
799  usleep(BIND_DELAY_US);
800  }
801 
802  if (temp_state->state->host.addr.sa_family == pj_AF_INET()) {
803  res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(),
804  &temp_state->state->host.ipv4, NULL, transport->async_operations,
805  &temp_state->state->transport);
806  } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) {
807  res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(),
808  &temp_state->state->host.ipv6, NULL, transport->async_operations,
809  &temp_state->state->transport);
810  }
811  }
812 
813  if (res == PJ_SUCCESS) {
814  temp_state->state->transport->info = pj_pool_alloc(temp_state->state->transport->pool,
815  (AST_SIP_X_AST_TXP_LEN + strlen(transport_id) + 2));
816 
817  sprintf(temp_state->state->transport->info, "%s:%s", AST_SIP_X_AST_TXP, transport_id);
818 
819  if (transport->tos || transport->cos) {
820  pj_sock_t sock;
821  pj_qos_params qos_params;
822  sock = pjsip_udp_transport_get_socket(temp_state->state->transport);
823  pj_sock_get_qos_params(sock, &qos_params);
824  set_qos(transport, &qos_params);
825  pj_sock_set_qos_params(sock, &qos_params);
826  }
827  }
828  } else if (transport->type == AST_TRANSPORT_TCP) {
829  pjsip_tcp_transport_cfg cfg;
830  static int option = 1;
831  int sockopt_count = 0;
832 
833  pjsip_tcp_transport_cfg_default(&cfg, temp_state->state->host.addr.sa_family);
834  cfg.bind_addr = temp_state->state->host;
835  cfg.async_cnt = transport->async_operations;
836  set_qos(transport, &cfg.qos_params);
837 
838  /* sockopt_params.options is copied to each newly connected socket */
839  cfg.sockopt_params.options[sockopt_count].level = pj_SOL_TCP();
840  cfg.sockopt_params.options[sockopt_count].optname = pj_TCP_NODELAY();
841  cfg.sockopt_params.options[sockopt_count].optval = &option;
842  cfg.sockopt_params.options[sockopt_count].optlen = sizeof(option);
843  sockopt_count++;
844 
845  if (transport->tcp_keepalive_enable) {
846 #if defined(PJ_MAX_SOCKOPT_PARAMS) && PJ_MAX_SOCKOPT_PARAMS >= 5
847  ast_log(LOG_DEBUG, "TCP Keepalive enabled for transport '%s'. Idle Time: %d, Interval: %d, Count: %d\n",
849 
850  cfg.sockopt_params.options[sockopt_count].level = pj_SOL_SOCKET();
851  cfg.sockopt_params.options[sockopt_count].optname = SO_KEEPALIVE;
852  cfg.sockopt_params.options[sockopt_count].optval = &option;
853  cfg.sockopt_params.options[sockopt_count].optlen = sizeof(option);
854  sockopt_count++;
855 
856  cfg.sockopt_params.options[sockopt_count].level = pj_SOL_TCP();
857  cfg.sockopt_params.options[sockopt_count].optname = TCP_KEEPIDLE;
858  cfg.sockopt_params.options[sockopt_count].optval = &transport->tcp_keepalive_idle_time;
859  cfg.sockopt_params.options[sockopt_count].optlen = sizeof(transport->tcp_keepalive_idle_time);
860  sockopt_count++;
861 
862  cfg.sockopt_params.options[sockopt_count].level = pj_SOL_TCP();
863  cfg.sockopt_params.options[sockopt_count].optname = TCP_KEEPINTVL;
864  cfg.sockopt_params.options[sockopt_count].optval = &transport->tcp_keepalive_interval_time;
865  cfg.sockopt_params.options[sockopt_count].optlen = sizeof(transport->tcp_keepalive_interval_time);
866  sockopt_count++;
867 
868  cfg.sockopt_params.options[sockopt_count].level = pj_SOL_TCP();
869  cfg.sockopt_params.options[sockopt_count].optname = TCP_KEEPCNT;
870  cfg.sockopt_params.options[sockopt_count].optval = &transport->tcp_keepalive_probe_count;
871  cfg.sockopt_params.options[sockopt_count].optlen = sizeof(transport->tcp_keepalive_probe_count);
872  sockopt_count++;
873 #else
874  ast_log(LOG_WARNING, "TCP keepalive settings for '%s' not set due to PJSIP built without support for setting all options. Consider using bundled PJSIP.\n",
876 #endif
877  }
878 
879  cfg.sockopt_params.cnt = sockopt_count;
880 
881  for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) {
882  if (perm_state && perm_state->state && perm_state->state->factory
883  && perm_state->state->factory->destroy) {
884  perm_state->state->factory->destroy(perm_state->state->factory);
885  usleep(BIND_DELAY_US);
886  }
887 
888  res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg,
889  &temp_state->state->factory);
890  }
891  } else if (transport->type == AST_TRANSPORT_TLS) {
892 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
893  static int option = 1;
894  int sockopt_count = 0;
895 
896  if (transport->async_operations > 1 && ast_compare_versions(pj_get_version(), "2.5.0") < 0) {
897  ast_log(LOG_ERROR, "Transport: %s: When protocol=tls and pjproject version < 2.5.0, async_operations can't be > 1\n",
899  return -1;
900  }
901 
902  temp_state->state->tls.password = pj_str((char*)transport->password);
903  set_qos(transport, &temp_state->state->tls.qos_params);
904 
905  /* sockopt_params.options is copied to each newly connected socket */
906  temp_state->state->tls.sockopt_params.options[sockopt_count].level = pj_SOL_TCP();
907  temp_state->state->tls.sockopt_params.options[sockopt_count].optname = pj_TCP_NODELAY();
908  temp_state->state->tls.sockopt_params.options[sockopt_count].optval = &option;
909  temp_state->state->tls.sockopt_params.options[sockopt_count].optlen = sizeof(option);
910  sockopt_count++;
911 
912  if (transport->tcp_keepalive_enable) {
913 #if defined(PJ_MAX_SOCKOPT_PARAMS) && PJ_MAX_SOCKOPT_PARAMS >= 5
914  ast_log(LOG_DEBUG, "TCP Keepalive enabled for transport '%s'. Idle Time: %d, Interval: %d, Count: %d\n",
916 
917  temp_state->state->tls.sockopt_params.options[sockopt_count].level = pj_SOL_SOCKET();
918  temp_state->state->tls.sockopt_params.options[sockopt_count].optname = SO_KEEPALIVE;
919  temp_state->state->tls.sockopt_params.options[sockopt_count].optval = &option;
920  temp_state->state->tls.sockopt_params.options[sockopt_count].optlen = sizeof(option);
921  sockopt_count++;
922 
923  temp_state->state->tls.sockopt_params.options[sockopt_count].level = pj_SOL_TCP();
924  temp_state->state->tls.sockopt_params.options[sockopt_count].optname = TCP_KEEPIDLE;
925  temp_state->state->tls.sockopt_params.options[sockopt_count].optval = &transport->tcp_keepalive_idle_time;
926  temp_state->state->tls.sockopt_params.options[sockopt_count].optlen = sizeof(transport->tcp_keepalive_idle_time);
927  sockopt_count++;
928 
929  temp_state->state->tls.sockopt_params.options[sockopt_count].level = pj_SOL_TCP();
930  temp_state->state->tls.sockopt_params.options[sockopt_count].optname = TCP_KEEPINTVL;
931  temp_state->state->tls.sockopt_params.options[sockopt_count].optval = &transport->tcp_keepalive_interval_time;
932  temp_state->state->tls.sockopt_params.options[sockopt_count].optlen = sizeof(transport->tcp_keepalive_interval_time);
933  sockopt_count++;
934 
935  temp_state->state->tls.sockopt_params.options[sockopt_count].level = pj_SOL_TCP();
936  temp_state->state->tls.sockopt_params.options[sockopt_count].optname = TCP_KEEPCNT;
937  temp_state->state->tls.sockopt_params.options[sockopt_count].optval = &transport->tcp_keepalive_probe_count;
938  temp_state->state->tls.sockopt_params.options[sockopt_count].optlen = sizeof(transport->tcp_keepalive_probe_count);
939  sockopt_count++;
940 #else
941  ast_log(LOG_WARNING, "TCP keepalive settings for '%s' not set due to PJSIP built without support for setting all options. Consider using bundled PJSIP.\n",
943 #endif
944  }
945 
946  temp_state->state->tls.sockopt_params.cnt = sockopt_count;
947 
948  for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) {
949  if (perm_state && perm_state->state && perm_state->state->factory
950  && perm_state->state->factory->destroy) {
951  perm_state->state->factory->destroy(perm_state->state->factory);
952  usleep(BIND_DELAY_US);
953  }
954 
955  res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &temp_state->state->tls,
956  &temp_state->state->host, NULL, transport->async_operations,
957  &temp_state->state->factory);
958  }
959 
960  if (res == PJ_SUCCESS) {
961  /*
962  * PJSIP uses 100 bytes to store information, and during a restart will repopulate
963  * the field so ensure there is sufficient space - even though we'll revert it after.
964  */
965  temp_state->state->factory->info = pj_pool_alloc(
966  temp_state->state->factory->pool, (MAX(MAX_OBJECT_FIELD, 100) + 1));
967  /*
968  * Store transport id on the factory instance so it can be used
969  * later to look up the transport state.
970  */
971  sprintf(temp_state->state->factory->info, "%s", transport_id);
972  }
973 #else
974  ast_log(LOG_ERROR, "Transport: %s: PJSIP has not been compiled with TLS transport support, ensure OpenSSL development packages are installed\n",
976  return -1;
977 #endif
978  } else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) {
979  if (transport->cos || transport->tos) {
980  ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n");
981  } else if (!ast_strlen_zero(transport->ca_list_file) || !ast_strlen_zero(transport->ca_list_path) ||
982  !ast_strlen_zero(transport->cert_file) || !ast_strlen_zero(transport->privkey_file)) {
983  ast_log(LOG_WARNING, "TLS certificate values ignored for websocket transport as they are configured in http.conf\n");
984  }
985  res = PJ_SUCCESS;
986  }
987 
988  if (res != PJ_SUCCESS) {
989  char msg[PJ_ERR_MSG_SIZE];
990 
991  pj_strerror(res, msg, sizeof(msg));
992  ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg);
993  return -1;
994  }
995 
996  copy_state_to_transport(transport);
997  if (perm_state) {
998  ao2_unlink_flags(states, perm_state, OBJ_NOLOCK);
999  }
1000  ao2_link_flags(states, temp_state, OBJ_NOLOCK);
1001 
1002  return 0;
1003 }
1004 
1005 /*! \brief Custom handler for type just makes sure the state is created */
1006 static int transport_state_init(const struct aco_option *opt, struct ast_variable *var, void *obj)
1007 {
1008  struct ast_sip_transport *transport = obj;
1009  struct ast_sip_transport_state *state = find_or_create_temporary_state(transport);
1010 
1011  ao2_cleanup(state);
1012 
1013  return 0;
1014 }
1015 
1016 /*! \brief Custom handler for TLS method setting */
1017 static int transport_tls_file_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1018 {
1019  struct ast_sip_transport *transport = obj;
1020  RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup);
1021 
1022  if (!state) {
1023  return -1;
1024  }
1025 
1026  if (ast_strlen_zero(var->value)) {
1027  /* Ignore empty options */
1028  return 0;
1029  }
1030 
1031  if (!ast_file_is_readable(var->value)) {
1032  ast_log(LOG_ERROR, "Transport: %s: %s %s is either missing or not readable\n",
1033  ast_sorcery_object_get_id(obj), var->name, var->value);
1034  return -1;
1035  }
1036 
1037  if (!strcasecmp(var->name, "ca_list_file")) {
1038  state->tls.ca_list_file = pj_str((char*)var->value);
1039  ast_string_field_set(transport, ca_list_file, var->value);
1040  } else if (!strcasecmp(var->name, "ca_list_path")) {
1041 #ifdef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2
1042  state->tls.ca_list_path = pj_str((char *)var->value);
1043  ast_string_field_set(transport, ca_list_path, var->value);
1044 #else
1045  ast_log(LOG_WARNING, "Asterisk has been built against a version of pjproject that does not "
1046  "support the 'ca_list_path' option. Please upgrade to version 2.4 or later.\n");
1047 #endif
1048  } else if (!strcasecmp(var->name, "cert_file")) {
1049  state->tls.cert_file = pj_str((char *)var->value);
1050  ast_string_field_set(transport, cert_file, var->value);
1051 #ifdef HAVE_PJSIP_TLS_TRANSPORT_RESTART
1052  if (stat(var->value, &state->cert_file_stat)) {
1053  ast_log(LOG_ERROR, "Failed to stat certificate file '%s' for transport '%s' due to '%s'\n",
1054  var->value, ast_sorcery_object_get_id(obj), strerror(errno));
1055  return -1;
1056  }
1058 #endif
1059  } else if (!strcasecmp(var->name, "priv_key_file")) {
1060  state->tls.privkey_file = pj_str((char *)var->value);
1061  ast_string_field_set(transport, privkey_file, var->value);
1062 #ifdef HAVE_PJSIP_TLS_TRANSPORT_RESTART
1063  if (stat(var->value, &state->privkey_file_stat)) {
1064  ast_log(LOG_ERROR, "Failed to stat private key file '%s' for transport '%s' due to '%s'\n",
1065  var->value, ast_sorcery_object_get_id(obj), strerror(errno));
1066  return -1;
1067  }
1069 #endif
1070  }
1071 
1072  return 0;
1073 }
1074 
1075 static int ca_list_file_to_str(const void *obj, const intptr_t *args, char **buf)
1076 {
1077  const struct ast_sip_transport *transport = obj;
1078 
1079  *buf = ast_strdup(transport->ca_list_file);
1080 
1081  return 0;
1082 }
1083 
1084 static int ca_list_path_to_str(const void *obj, const intptr_t *args, char **buf)
1085 {
1086  const struct ast_sip_transport *transport = obj;
1087 
1088  *buf = ast_strdup(transport->ca_list_path);
1089 
1090  return 0;
1091 }
1092 
1093 static int cert_file_to_str(const void *obj, const intptr_t *args, char **buf)
1094 {
1095  const struct ast_sip_transport *transport = obj;
1096 
1097  *buf = ast_strdup(transport->cert_file);
1098 
1099  return 0;
1100 }
1101 
1102 static int privkey_file_to_str(const void *obj, const intptr_t *args, char **buf)
1103 {
1104  const struct ast_sip_transport *transport = obj;
1105 
1106  *buf = ast_strdup(transport->privkey_file);
1107 
1108  return 0;
1109 }
1110 
1111 /*! \brief Custom handler for turning a string protocol into an enum */
1112 static int transport_protocol_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1113 {
1114  struct ast_sip_transport *transport = obj;
1115  RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup);
1116 
1117  if (!state) {
1118  return -1;
1119  }
1120 
1121  if (!strcasecmp(var->value, "flow")) {
1122  transport->flow = 1;
1123  } else {
1124  if (!strcasecmp(var->value, "udp")) {
1125  transport->type = AST_TRANSPORT_UDP;
1126  } else if (!strcasecmp(var->value, "tcp")) {
1127  transport->type = AST_TRANSPORT_TCP;
1128  } else if (!strcasecmp(var->value, "tls")) {
1129  transport->type = AST_TRANSPORT_TLS;
1130  } else if (!strcasecmp(var->value, "ws")) {
1131  transport->type = AST_TRANSPORT_WS;
1132  } else if (!strcasecmp(var->value, "wss")) {
1133  transport->type = AST_TRANSPORT_WSS;
1134  } else {
1135  return -1;
1136  }
1137  transport->flow = 0;
1138  }
1139 
1140  state->type = transport->type;
1141 
1142  return 0;
1143 }
1144 
1145 static const char *transport_types[] = {
1146  [AST_TRANSPORT_UDP] = "udp",
1147  [AST_TRANSPORT_TCP] = "tcp",
1148  [AST_TRANSPORT_TLS] = "tls",
1149  [AST_TRANSPORT_WS] = "ws",
1150  [AST_TRANSPORT_WSS] = "wss"
1151 };
1152 
1153 static int transport_protocol_to_str(const void *obj, const intptr_t *args, char **buf)
1154 {
1155  const struct ast_sip_transport *transport = obj;
1156 
1157  if (transport->flow) {
1158  *buf = ast_strdup("flow");
1159  } else if (ARRAY_IN_BOUNDS(transport->type, transport_types)) {
1160  *buf = ast_strdup(transport_types[transport->type]);
1161  }
1162 
1163  return 0;
1164 }
1165 
1166 /*! \brief Custom handler for turning a string bind into a pj_sockaddr */
1167 static int transport_bind_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1168 {
1169  struct ast_sip_transport *transport = obj;
1170  pj_str_t buf;
1171  int rc;
1172  RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup);
1173 
1174  if (!state) {
1175  return -1;
1176  }
1177 
1178  rc = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, var->value), &state->host);
1179 
1180  return rc != PJ_SUCCESS ? -1 : 0;
1181 }
1182 
1183 static int transport_bind_to_str(const void *obj, const intptr_t *args, char **buf)
1184 {
1185  const struct ast_sip_transport *transport = obj;
1186  RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);
1187 
1188  if (!state) {
1189  return -1;
1190  }
1191 
1192  if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
1193  return -1;
1194  }
1195 
1196  /* include port as well as brackets if IPv6 */
1197  pj_sockaddr_print(&state->host, *buf, MAX_OBJECT_FIELD, 1 | 2);
1198 
1199  return 0;
1200 }
1201 
1202 /*! \brief Custom handler for TLS boolean settings */
1203 static int transport_tls_bool_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1204 {
1205  struct ast_sip_transport *transport = obj;
1206  RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup);
1207 
1208  if (!state) {
1209  return -1;
1210  }
1211 
1212  if (!strcasecmp(var->name, "verify_server")) {
1213  state->verify_server = ast_true(var->value);
1214  } else if (!strcasecmp(var->name, "verify_client")) {
1215  state->tls.verify_client = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
1216  } else if (!strcasecmp(var->name, "require_client_cert")) {
1217  state->tls.require_client_cert = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
1218  } else if (!strcasecmp(var->name, "allow_wildcard_certs")) {
1219  state->allow_wildcard_certs = ast_true(var->value);
1220  } else {
1221  return -1;
1222  }
1223 
1224  return 0;
1225 }
1226 
1227 static int verify_server_to_str(const void *obj, const intptr_t *args, char **buf)
1228 {
1229  const struct ast_sip_transport *transport = obj;
1230  RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);
1231 
1232  if (!state) {
1233  return -1;
1234  }
1235 
1236  *buf = ast_strdup(AST_YESNO(state->verify_server));
1237 
1238  return 0;
1239 }
1240 
1241 static int verify_client_to_str(const void *obj, const intptr_t *args, char **buf)
1242 {
1243  const struct ast_sip_transport *transport = obj;
1244  RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);
1245 
1246  if (!state) {
1247  return -1;
1248  }
1249 
1250  *buf = ast_strdup(AST_YESNO(state->tls.verify_client));
1251 
1252  return 0;
1253 }
1254 
1255 static int require_client_cert_to_str(const void *obj, const intptr_t *args, char **buf)
1256 {
1257  const struct ast_sip_transport *transport = obj;
1258  RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);
1259 
1260  if (!state) {
1261  return -1;
1262  }
1263 
1264  *buf = ast_strdup(AST_YESNO(state->tls.require_client_cert));
1265 
1266  return 0;
1267 }
1268 
1269 static int allow_wildcard_certs_to_str(const void *obj, const intptr_t *args, char **buf)
1270 {
1271  struct ast_sip_transport_state *state = find_state_by_transport(obj);
1272 
1273  if (!state) {
1274  return -1;
1275  }
1276 
1277  *buf = ast_strdup(AST_YESNO(state->allow_wildcard_certs));
1278  ao2_ref(state, -1);
1279 
1280  return 0;
1281 }
1282 
1283 /*! \brief Custom handler for TLS method setting */
1284 static int transport_tls_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1285 {
1286  struct ast_sip_transport *transport = obj;
1287  RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup);
1288 
1289  if (!state) {
1290  return -1;
1291  }
1292 
1293  if (ast_strlen_zero(var->value) || !strcasecmp(var->value, "default")) {
1294  state->tls.method = PJSIP_SSL_DEFAULT_METHOD;
1295  } else if (!strcasecmp(var->value, "unspecified")) {
1296  state->tls.method = PJSIP_SSL_UNSPECIFIED_METHOD;
1297  } else if (!strcasecmp(var->value, "tlsv1")) {
1298  state->tls.method = PJSIP_TLSV1_METHOD;
1299 #ifdef HAVE_PJSIP_TLS_1_1
1300  } else if (!strcasecmp(var->value, "tlsv1_1")) {
1301  state->tls.method = PJSIP_TLSV1_1_METHOD;
1302 #endif
1303 #ifdef HAVE_PJSIP_TLS_1_2
1304  } else if (!strcasecmp(var->value, "tlsv1_2")) {
1305  state->tls.method = PJSIP_TLSV1_2_METHOD;
1306 #endif
1307 #ifdef HAVE_PJSIP_TLS_1_3
1308  } else if (!strcasecmp(var->value, "tlsv1_3")) {
1309  state->tls.method = PJSIP_TLSV1_3_METHOD;
1310 #endif
1311  } else if (!strcasecmp(var->value, "sslv2")) {
1312  state->tls.method = PJSIP_SSLV2_METHOD;
1313  } else if (!strcasecmp(var->value, "sslv3")) {
1314  state->tls.method = PJSIP_SSLV3_METHOD;
1315  } else if (!strcasecmp(var->value, "sslv23")) {
1316  state->tls.method = PJSIP_SSLV23_METHOD;
1317  } else {
1318  return -1;
1319  }
1320 
1321  return 0;
1322 }
1323 
1324 static const char *tls_method_map[] = {
1325  [PJSIP_SSL_UNSPECIFIED_METHOD] = "unspecified",
1326  [PJSIP_TLSV1_METHOD] = "tlsv1",
1327 #ifdef HAVE_PJSIP_TLS_1_1
1328  [PJSIP_TLSV1_1_METHOD] = "tlsv1_1",
1329 #endif
1330 #ifdef HAVE_PJSIP_TLS_1_2
1331  [PJSIP_TLSV1_2_METHOD] = "tlsv1_2",
1332 #endif
1333 #ifdef HAVE_PJSIP_TLS_1_3
1334  [PJSIP_TLSV1_3_METHOD] = "tlsv1_3",
1335 #endif
1336  [PJSIP_SSLV2_METHOD] = "sslv2",
1337  [PJSIP_SSLV3_METHOD] = "sslv3",
1338  [PJSIP_SSLV23_METHOD] = "sslv23",
1339 };
1340 
1341 static int tls_method_to_str(const void *obj, const intptr_t *args, char **buf)
1342 {
1343  const struct ast_sip_transport *transport = obj;
1344  RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);
1345 
1346  if (!state) {
1347  return -1;
1348  }
1349 
1350  if (ARRAY_IN_BOUNDS(state->tls.method, tls_method_map)) {
1351  *buf = ast_strdup(tls_method_map[state->tls.method]);
1352  }
1353 
1354  return 0;
1355 }
1356 
1357 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
1358 /*! \brief Helper function which turns a cipher name into an identifier */
1359 static pj_ssl_cipher cipher_name_to_id(const char *name)
1360 {
1361  pj_ssl_cipher ciphers[PJ_SSL_SOCK_MAX_CIPHERS];
1362  unsigned int cipher_num = PJ_ARRAY_SIZE(ciphers);
1363  unsigned int pos;
1364 
1365  if (pj_ssl_cipher_get_availables(ciphers, &cipher_num)) {
1366  return 0;
1367  }
1368 
1369  for (pos = 0; pos < cipher_num; ++pos) {
1370  const char *pos_name = pj_ssl_cipher_name(ciphers[pos]);
1371  if (pos_name && !strcmp(pos_name, name)) {
1372  return ciphers[pos];
1373  }
1374  }
1375 
1376  return 0;
1377 }
1378 #endif
1379 
1380 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
1381 /*!
1382  * \internal
1383  * \brief Add a new cipher to the transport's cipher list array.
1384  *
1385  * \param state Which transport to add the cipher to.
1386  * \param name Cipher identifier name.
1387  *
1388  * \retval 0 on success.
1389  * \retval -1 on error.
1390  */
1391 static int transport_cipher_add(struct ast_sip_transport_state *state, const char *name)
1392 {
1393  pj_ssl_cipher cipher;
1394  int idx;
1395 
1396  cipher = cipher_name_to_id(name);
1397  if (!cipher) {
1398  /* TODO: Check this over/tweak - it's taken from pjsua for now */
1399  if (!strnicmp(name, "0x", 2)) {
1400  pj_str_t cipher_st = pj_str((char *) name + 2);
1401  cipher = pj_strtoul2(&cipher_st, NULL, 16);
1402  } else {
1403  cipher = atoi(name);
1404  }
1405  }
1406 
1407  if (pj_ssl_cipher_is_supported(cipher)) {
1408  for (idx = state->tls.ciphers_num; idx--;) {
1409  if (state->ciphers[idx] == cipher) {
1410  /* The cipher is already in the list. */
1411  return 0;
1412  }
1413  }
1414  state->ciphers[state->tls.ciphers_num++] = cipher;
1415  return 0;
1416  } else {
1417  ast_log(LOG_ERROR, "Cipher '%s' is unsupported\n", name);
1418  return -1;
1419  }
1420 }
1421 #endif
1422 
1423 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
1424 /*! \brief Custom handler for TLS cipher setting */
1425 static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1426 {
1427  struct ast_sip_transport *transport = obj;
1428  char *parse;
1429  char *name;
1430  int res = 0;
1431  RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup);
1432 
1433  if (!state) {
1434  return -1;
1435  }
1436 
1437  parse = ast_strdupa(S_OR(var->value, ""));
1438  while ((name = ast_strip(strsep(&parse, ",")))) {
1439  if (ast_strlen_zero(name)) {
1440  continue;
1441  }
1442  if (ARRAY_LEN(state->ciphers) <= state->tls.ciphers_num) {
1443  ast_log(LOG_ERROR, "Too many ciphers specified (maximum allowed is %d)\n", SIP_TLS_MAX_CIPHERS);
1444  res = -1;
1445  break;
1446  }
1447  res |= transport_cipher_add(state, name);
1448  }
1449  return res ? -1 : 0;
1450 }
1451 #endif
1452 
1453 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
1454 static void cipher_to_str(char **buf, const pj_ssl_cipher *ciphers, unsigned int cipher_num)
1455 {
1456  struct ast_str *str;
1457  unsigned int idx;
1458 
1459  str = ast_str_create(128);
1460  if (!str) {
1461  *buf = NULL;
1462  return;
1463  }
1464 
1465  for (idx = 0; idx < cipher_num; ++idx) {
1466  ast_str_append(&str, 0, "%s", pj_ssl_cipher_name(ciphers[idx]));
1467  if (idx < cipher_num - 1) {
1468  ast_str_append(&str, 0, ", ");
1469  }
1470  }
1471 
1472  *buf = ast_strdup(ast_str_buffer(str));
1473  ast_free(str);
1474 }
1475 #endif
1476 
1477 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
1478 static int transport_tls_cipher_to_str(const void *obj, const intptr_t *args, char **buf)
1479 {
1480  const struct ast_sip_transport *transport = obj;
1481  RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);
1482 
1483  if (!state) {
1484  return -1;
1485  }
1486 
1487  cipher_to_str(buf, state->ciphers, state->tls.ciphers_num);
1488  return *buf ? 0 : -1;
1489 }
1490 #endif
1491 
1492 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
1493 static char *handle_pjsip_list_ciphers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1494 {
1495  pj_ssl_cipher ciphers[PJ_SSL_SOCK_MAX_CIPHERS];
1496  unsigned int cipher_num = PJ_ARRAY_SIZE(ciphers);
1497  char *buf;
1498 
1499  switch (cmd) {
1500  case CLI_INIT:
1501  e->command = "pjsip list ciphers";
1502  e->usage = "Usage: pjsip list ciphers\n"
1503  " List available OpenSSL cipher names.\n";
1504  return NULL;
1505  case CLI_GENERATE:
1506  return NULL;
1507  }
1508 
1509  if (pj_ssl_cipher_get_availables(ciphers, &cipher_num) || !cipher_num) {
1510  buf = NULL;
1511  } else {
1512  cipher_to_str(&buf, ciphers, cipher_num);
1513  }
1514 
1515  if (!ast_strlen_zero(buf)) {
1516  ast_cli(a->fd, "Available ciphers: '%s'\n", buf);
1517  } else {
1518  ast_cli(a->fd, "No available ciphers\n");
1519  }
1520  ast_free(buf);
1521  return CLI_SUCCESS;
1522 }
1523 #endif
1524 
1525 /*! \brief Custom handler for localnet setting */
1526 static int transport_localnet_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1527 {
1528  struct ast_sip_transport *transport = obj;
1529  int error = 0;
1530  RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup);
1531 
1532  if (!state) {
1533  return -1;
1534  }
1535 
1536  if (ast_strlen_zero(var->value)) {
1537  ast_free_ha(state->localnet);
1538  state->localnet = NULL;
1539  return 0;
1540  }
1541 
1542  /* We use only the ast_apply_ha() which defaults to ALLOW
1543  * ("permit"), so we add DENY rules. */
1544  if (!(state->localnet = ast_append_ha("deny", var->value, state->localnet, &error))) {
1545  return -1;
1546  }
1547 
1548  return error;
1549 }
1550 
1551 static void localnet_to_vl_append(struct ast_variable **head, struct ast_ha *ha)
1552 {
1553  char str[MAX_OBJECT_FIELD];
1554  const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
1555  snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
1556  addr, ast_sockaddr_stringify_addr(&ha->netmask));
1557 
1558  ast_variable_list_append(head, ast_variable_new("local_net", str, ""));
1559 }
1560 
1561 static int localnet_to_vl(const void *obj, struct ast_variable **fields)
1562 {
1563  const struct ast_sip_transport *transport = obj;
1564  struct ast_variable *head = NULL;
1565  struct ast_ha *ha;
1566  RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);
1567 
1568  if (!state) {
1569  return -1;
1570  }
1571 
1572  for (ha = state->localnet; ha; ha = ha->next) {
1573  localnet_to_vl_append(&head, ha);
1574  }
1575 
1576  if (head) {
1577  *fields = head;
1578  }
1579 
1580  return 0;
1581 }
1582 
1583 static int localnet_to_str(const void *obj, const intptr_t *args, char **buf)
1584 {
1585  RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
1586  const struct ast_sip_transport *transport = obj;
1587  RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);
1588 
1589  if (!state) {
1590  return -1;
1591  }
1592 
1593  ast_ha_join(state->localnet, &str);
1594  *buf = ast_strdup(ast_str_buffer(str));
1595  return 0;
1596 }
1597 
1598 /*! \brief Custom handler for TOS setting */
1599 static int transport_tos_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1600 {
1601  struct ast_sip_transport *transport = obj;
1602  unsigned int value;
1603 
1604  if (ast_str2tos(var->value, &value)) {
1605  ast_log(LOG_ERROR, "Error configuring transport '%s' - Could not "
1606  "interpret 'tos' value '%s'\n",
1607  ast_sorcery_object_get_id(transport), var->value);
1608  return -1;
1609  }
1610 
1611  if (value % 4) {
1612  value = value >> 2;
1613  value = value << 2;
1614  ast_log(LOG_WARNING,
1615  "transport '%s' - 'tos' value '%s' uses bits that are "
1616  "discarded when converted to DSCP. Using equivalent %u instead.\n",
1617  ast_sorcery_object_get_id(transport), var->value, value);
1618  }
1619 
1620  transport->tos = value;
1621  return 0;
1622 }
1623 
1624 static int tos_to_str(const void *obj, const intptr_t *args, char **buf)
1625 {
1626  const struct ast_sip_transport *transport = obj;
1627 
1628  if (ast_asprintf(buf, "%u", transport->tos) == -1) {
1629  return -1;
1630  }
1631  return 0;
1632 }
1633 
1634 static struct ao2_container *cli_get_container(const char *regex)
1635 {
1636  RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
1637  struct ao2_container *s_container;
1638 
1639  container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "transport",
1640  regex);
1641  if (!container) {
1642  return NULL;
1643  }
1644 
1647  if (!s_container) {
1648  return NULL;
1649  }
1650 
1651  if (ao2_container_dup(s_container, container, 0)) {
1652  ao2_ref(s_container, -1);
1653  return NULL;
1654  }
1655 
1656  return s_container;
1657 }
1658 
1659 static int cli_iterate(void *container, ao2_callback_fn callback, void *args)
1660 {
1661  const struct ast_sip_endpoint *endpoint = container;
1662  struct ast_sip_transport *transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
1663  "transport", endpoint->transport);
1664 
1665  if (!transport) {
1666  return -1;
1667  }
1668 
1669  return callback(transport, args, 0);
1670 }
1671 
1672 static void *cli_retrieve_by_id(const char *id)
1673 {
1674  return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", id);
1675 }
1676 
1677 static int cli_print_header(void *obj, void *arg, int flags)
1678 {
1679  struct ast_sip_cli_context *context = arg;
1680  int indent = CLI_INDENT_TO_SPACES(context->indent_level);
1681  int filler = CLI_MAX_WIDTH - indent - 61;
1682 
1683  ast_assert(context->output_buffer != NULL);
1684 
1685  ast_str_append(&context->output_buffer, 0,
1686  "%*s: <TransportId........> <Type> <cos> <tos> <BindAddress%*.*s>\n",
1687  indent, "Transport", filler, filler, CLI_HEADER_FILLER);
1688 
1689  return 0;
1690 }
1691 
1692 static int cli_print_body(void *obj, void *arg, int flags)
1693 {
1694  struct ast_sip_transport *transport = obj;
1695  struct ast_sip_cli_context *context = arg;
1696  char hoststr[PJ_INET6_ADDRSTRLEN];
1697  RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);
1698 
1699  if (!state) {
1700  return -1;
1701  }
1702 
1703  ast_assert(context->output_buffer != NULL);
1704 
1705  pj_sockaddr_print(&state->host, hoststr, sizeof(hoststr), 3);
1706 
1707  ast_str_append(&context->output_buffer, 0, "%*s: %-21s %6s %5u %5u %s\n",
1708  CLI_INDENT_TO_SPACES(context->indent_level), "Transport",
1709  ast_sorcery_object_get_id(transport),
1710  ARRAY_IN_BOUNDS(transport->type, transport_types) ? transport_types[transport->type] : "Unknown",
1711  transport->cos, transport->tos, hoststr);
1712 
1713  if (context->show_details
1714  || (context->show_details_only_level_0 && context->indent_level == 0)) {
1715  ast_str_append(&context->output_buffer, 0, "\n");
1716  ast_sip_cli_print_sorcery_objectset(transport, context, 0);
1717  }
1718 
1719  return 0;
1720 }
1721 
1722 static struct ast_cli_entry cli_commands[] = {
1723 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
1724  AST_CLI_DEFINE(handle_pjsip_list_ciphers, "List available OpenSSL cipher names"),
1725 #endif
1726  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Transports",
1727  .command = "pjsip list transports",
1728  .usage = "Usage: pjsip list transports [ like <pattern> ]\n"
1729  " List the configured PJSIP Transports\n"
1730  " Optional regular expression pattern is used to filter the list.\n"),
1731  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Transports",
1732  .command = "pjsip show transports",
1733  .usage = "Usage: pjsip show transports [ like <pattern> ]\n"
1734  " Show the configured PJSIP Transport\n"
1735  " Optional regular expression pattern is used to filter the list.\n"),
1736  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Transport",
1737  .command = "pjsip show transport",
1738  .usage = "Usage: pjsip show transport <id>\n"
1739  " Show the configured PJSIP Transport\n"),
1740 };
1741 
1742 static struct ast_sip_cli_formatter_entry *cli_formatter;
1743 
1744 struct ast_sip_transport_state *ast_sip_get_transport_state(const char *transport_id)
1745 {
1746  struct internal_state *state = NULL;
1747  struct ast_sip_transport_state *trans_state;
1748 
1749  if (!transport_states) {
1750  return NULL;
1751  }
1752 
1753  state = ao2_find(transport_states, transport_id, OBJ_SEARCH_KEY);
1754  if (!state) {
1755  return NULL;
1756  }
1757 
1758  trans_state = ao2_bump(state->state);
1759  ao2_ref(state, -1);
1760 
1761  /* If this is a child transport see if the transport is actually dead */
1762  if (trans_state->flow) {
1763  ao2_lock(trans_state);
1764  if (trans_state->transport && trans_state->transport->is_shutdown == PJ_TRUE) {
1765  pjsip_transport_dec_ref(trans_state->transport);
1766  trans_state->transport = NULL;
1767  }
1768  ao2_unlock(trans_state);
1769  }
1770 
1771  return trans_state;
1772 }
1773 
1774 static int populate_transport_states(void *obj, void *arg, int flags)
1775 {
1776  struct internal_state *state = obj;
1777  struct ao2_container *container = arg;
1778 
1779  ao2_link(container, state->state);
1780 
1781  return CMP_MATCH;
1782 }
1783 
1784 struct ao2_container *ast_sip_get_transport_states(void)
1785 {
1787  DEFAULT_STATE_BUCKETS, transport_state_hash, NULL, transport_state_cmp);
1788 
1789  if (!states) {
1790  return NULL;
1791  }
1792 
1793  ao2_callback(transport_states, OBJ_NODATA | OBJ_MULTIPLE, populate_transport_states, states);
1794  return states;
1795 }
1796 
1797 /*! \brief Initialize sorcery with transport support */
1798 int ast_sip_initialize_sorcery_transport(void)
1799 {
1800  struct ast_sorcery *sorcery = ast_sip_get_sorcery();
1801  struct ao2_container *transports = NULL;
1802 
1803  /* Create outbound registration states container. */
1804  transport_states = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
1805  DEFAULT_STATE_BUCKETS, internal_state_hash, NULL, internal_state_cmp);
1806  if (!transport_states) {
1807  ast_log(LOG_ERROR, "Unable to allocate transport states container\n");
1808  return -1;
1809  }
1810 
1811  ast_sorcery_apply_default(sorcery, "transport", "config", "pjsip.conf,criteria=type=transport");
1812 
1813  if (ast_sorcery_object_register(sorcery, "transport", sip_transport_alloc, NULL, transport_apply)) {
1814  return -1;
1815  }
1816 
1817  /* Normally type is a OPT_NOOP_T but we're using it to make sure that state is created */
1818  ast_sorcery_object_field_register_custom(sorcery, "transport", "type", "", transport_state_init, NULL, NULL, 0, 0);
1819  ast_sorcery_object_field_register_custom(sorcery, "transport", "protocol", "udp", transport_protocol_handler, transport_protocol_to_str, NULL, 0, 0);
1820  ast_sorcery_object_field_register_custom(sorcery, "transport", "bind", "", transport_bind_handler, transport_bind_to_str, NULL, 0, 0);
1821  ast_sorcery_object_field_register(sorcery, "transport", "async_operations", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, async_operations));
1822 
1823  ast_sorcery_object_field_register_custom(sorcery, "transport", "ca_list_file", "", transport_tls_file_handler, ca_list_file_to_str, NULL, 0, 0);
1824  ast_sorcery_object_field_register_custom(sorcery, "transport", "ca_list_path", "", transport_tls_file_handler, ca_list_path_to_str, NULL, 0, 0);
1825  ast_sorcery_object_field_register_custom(sorcery, "transport", "cert_file", "", transport_tls_file_handler, cert_file_to_str, NULL, 0, 0);
1826  ast_sorcery_object_field_register_custom(sorcery, "transport", "priv_key_file", "", transport_tls_file_handler, privkey_file_to_str, NULL, 0, 0);
1827 
1828  ast_sorcery_object_field_register(sorcery, "transport", "password", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, password));
1829  ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_signaling_address));
1830  ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, external_signaling_port), 0, 65535);
1831  ast_sorcery_object_field_register(sorcery, "transport", "external_media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_media_address));
1832  ast_sorcery_object_field_register(sorcery, "transport", "domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, domain));
1833  ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, verify_server_to_str, NULL, 0, 0);
1834  ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, verify_client_to_str, NULL, 0, 0);
1835  ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, require_client_cert_to_str, NULL, 0, 0);
1836  ast_sorcery_object_field_register_custom(sorcery, "transport", "allow_wildcard_certs", "", transport_tls_bool_handler, allow_wildcard_certs_to_str, NULL, 0, 0);
1837  ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, tls_method_to_str, NULL, 0, 0);
1838  ast_sorcery_object_field_register(sorcery, "transport", "tcp_keepalive_enable", "no", OPT_BOOL_T, 0, FLDSET(struct ast_sip_transport, tcp_keepalive_enable));
1839  ast_sorcery_object_field_register(sorcery, "transport", "tcp_keepalive_idle_time", "30", OPT_INT_T, 0, FLDSET(struct ast_sip_transport, tcp_keepalive_idle_time));
1840  ast_sorcery_object_field_register(sorcery, "transport", "tcp_keepalive_interval_time", "1", OPT_INT_T, 0, FLDSET(struct ast_sip_transport, tcp_keepalive_interval_time));
1841  ast_sorcery_object_field_register(sorcery, "transport", "tcp_keepalive_probe_count", "5", OPT_INT_T, 0, FLDSET(struct ast_sip_transport, tcp_keepalive_probe_count));
1842 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
1843  ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, transport_tls_cipher_to_str, NULL, 0, 0);
1844 #endif
1845  ast_sorcery_object_field_register_custom(sorcery, "transport", "local_net", "", transport_localnet_handler, localnet_to_str, localnet_to_vl, 0, 0);
1846  ast_sorcery_object_field_register_custom(sorcery, "transport", "tos", "0", transport_tos_handler, tos_to_str, NULL, 0, 0);
1847  ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos));
1848  ast_sorcery_object_field_register(sorcery, "transport", "websocket_write_timeout", AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, write_timeout), 1, INT_MAX);
1849  ast_sorcery_object_field_register(sorcery, "transport", "allow_reload", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_transport, allow_reload));
1850  ast_sorcery_object_field_register(sorcery, "transport", "symmetric_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_transport, symmetric_transport));
1851 
1852  ast_sip_register_endpoint_formatter(&endpoint_transport_formatter);
1853 
1854  cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1855  if (!cli_formatter) {
1856  ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
1857  return -1;
1858  }
1859  cli_formatter->name = "transport";
1860  cli_formatter->print_header = cli_print_header;
1861  cli_formatter->print_body = cli_print_body;
1862  cli_formatter->get_container = cli_get_container;
1863  cli_formatter->iterate = cli_iterate;
1864  cli_formatter->get_id = ast_sorcery_object_get_id;
1865  cli_formatter->retrieve_by_id = cli_retrieve_by_id;
1866 
1867  ast_sip_register_cli_formatter(cli_formatter);
1868  ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
1869 
1870  /* trigger load of transports from realtime by trying to revrieve them all */
1871  transports = ast_sorcery_retrieve_by_fields(sorcery, "transport", AST_RETRIEVE_FLAG_ALL | AST_RETRIEVE_FLAG_MULTIPLE, NULL);
1872  ao2_cleanup(transports);
1873 
1874  return 0;
1875 }
1876 
1877 int ast_sip_destroy_sorcery_transport(void)
1878 {
1879  ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
1880  ast_sip_unregister_cli_formatter(cli_formatter);
1881 
1882  ast_sip_unregister_endpoint_formatter(&endpoint_transport_formatter);
1883 
1884  ao2_ref(transport_states, -1);
1885  transport_states = NULL;
1886 
1887  return 0;
1888 }
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:286
enum ast_transport type
Definition: res_pjsip.h:133
struct ast_str * output_buffer
Definition: res_pjsip_cli.h:36
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
#define ARRAY_IN_BOUNDS(v, a)
Checks to see if value is within the bounds of the given array.
Definition: utils.h:687
int tcp_keepalive_idle_time
Definition: res_pjsip.h:305
struct ast_ha * localnet
Definition: res_pjsip.h:156
struct stat privkey_file_stat
Definition: res_pjsip.h:208
struct ast_dnsmgr_entry * external_address_refresher
Definition: res_pjsip.h:277
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
Asterisk main include file. File version handling, generic pbx functions.
An entity responsible formatting endpoint information.
Definition: res_pjsip.h:3057
CLI Formatter Registry Entry.
Definition: res_pjsip_cli.h:52
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1226
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
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
const ast_string_field transport
Definition: res_pjsip.h:954
const struct message * m
Definition: res_pjsip.h:3035
struct ast_sip_transport_state * state
Transport state information.
descriptor for a cli entry.
Definition: cli.h:171
int tcp_keepalive_probe_count
Definition: res_pjsip.h:309
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
Definition: utils.c:3107
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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
const ast_string_field external_media_address
Definition: res_pjsip.h:241
struct ast_ha * localnet
Definition: res_pjsip.h:271
AMI variable container.
Definition: res_pjsip.h:3031
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
Structure for variables, used for configurations and for channel variables.
static struct ast_sockaddr address
Address for UDPTL.
Definition: res_pjsip_t38.c:56
Perform no matching, return all objects.
Definition: sorcery.h:123
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2464
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
Create a changeset of two objects.
Definition: sorcery.c:1805
Full structure for sorcery.
Definition: sorcery.c:230
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Definition: res_pjsip_cli.h:66
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
Return all matching objects.
Definition: sorcery.h:120
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
pj_sockaddr host
Definition: res_pjsip.h:249
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
int ast_str2tos(const char *value, unsigned int *tos)
Convert a string to the appropriate TOS value.
Definition: acl.c:966
CLI Formatter Context passed to all formatters.
Definition: res_pjsip_cli.h:34
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:388
unsigned int cos
Definition: res_pjsip.h:293
struct ast_sip_transport_state * state
Definition: res_pjsip.h:289
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:2165
int tcp_keepalive_interval_time
Definition: res_pjsip.h:307
enum ast_transport type
Definition: res_pjsip.h:243
void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt,...)
Send error in manager transaction (with va_args support)
Definition: manager.c:3394
void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf)
Convert HAs to a comma separated string value.
Definition: acl.c:722
struct ao2_container * ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
Retrieve multiple objects using a regular expression on their id.
Definition: sorcery.c:1954
Utility functions.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
struct ast_sockaddr external_address
Definition: res_pjsip.h:283
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
struct stat cert_file_stat
Definition: res_pjsip.h:204
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
internal representation of ACL entries In principle user applications would have no need for this...
Definition: acl.h:51
const ast_string_field password
Definition: res_pjsip.h:241
struct ast_sockaddr external_media_address
Definition: res_pjsip.h:176
#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
const ast_string_field ca_list_path
Definition: res_pjsip.h:241
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
Structure for SIP transport information.
Definition: res_pjsip.h:119
Type for default option handler for unsigned integers.
void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry)
Free a DNS manager entry.
Definition: dnsmgr.c:136
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
struct pjsip_transport * transport
Transport itself.
Definition: res_pjsip.h:121
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
pjsip_tls_setting tls
Definition: res_pjsip.h:143
Access Control of various sorts.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition: sorcery.c:2440
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
struct mansession * s
Definition: res_pjsip.h:3033
struct ao2_container * container
Definition: res_fax.c:501
#define ast_debug(level,...)
Log a DEBUG message.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:949
Support for WebSocket connections within the Asterisk HTTP server and client WebSocket connections to...
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
#define MAX_OBJECT_FIELD
Maximum length of an object field name.
Definition: sorcery.h:110
#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
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: utils.c:2199
const ast_string_field external_signaling_address
Definition: res_pjsip.h:241
Support for dynamic strings.
Definition: strings.h:623
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.
Type for default option handler for bools (ast_true/ast_false)
Transport to bind to.
Definition: res_pjsip.h:221
unsigned int async_operations
Definition: res_pjsip.h:251
const ast_string_field ca_list_file
Definition: res_pjsip.h:241
const ast_string_field privkey_file
Definition: res_pjsip.h:241
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
int(* format_ami)(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)
Callback used to format endpoint information over AMI.
Definition: res_pjsip.h:3061
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Support for logging to various files, console and syslog Configuration in file logger.conf.
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
struct ast_sockaddr external_signaling_address
Definition: res_pjsip.h:166
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
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
void ast_free_ha(struct ast_ha *ha)
Free a list of HAs.
Definition: acl.c:222
#define AST_YESNO(x)
return Yes or No depending on the argument.
Definition: strings.h:143
void ast_sorcery_object_set_has_dynamic_contents(const void *object)
Set the dynamic contents flag on a sorcery object.
Definition: sorcery.c:2384
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
int tcp_keepalive_enable
Definition: res_pjsip.h:303
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)
Allocate and initialize a DNS manager entry.
Definition: dnsmgr.c:191
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
#define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR
Default websocket write timeout, in ms (as a string)
pj_ssl_cipher ciphers[SIP_TLS_MAX_CIPHERS]
Definition: res_pjsip.h:265
struct ast_sip_transport * transport
Transport configuration object.
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition: astobj2.h:1600
Type for default option handler for stringfields.
ao2_callback_fn * print_header
Definition: res_pjsip_cli.h:60
unsigned int tos
Definition: res_pjsip.h:291
struct ast_ha * ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
Add a new rule to a list of HAs.
Definition: acl.c:712
int ast_compare_versions(const char *version1, const char *version2)
Compare 2 major.minor.patch.extra version strings.
Definition: utils.c:3124
struct ast_sip_service_route_vector * service_routes
Definition: res_pjsip.h:191
Generic container type.
Search option field mask.
Definition: astobj2.h:1072
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
Type for default option handler for signed integers.
ao2_callback_fn * print_body
Definition: res_pjsip_cli.h:62
struct ast_dnsmgr_entry * external_media_address_refresher
Definition: res_pjsip.h:171
const char * name
Definition: res_pjsip_cli.h:58
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
pjsip_tls_setting tls
Definition: res_pjsip.h:259
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
struct ast_dnsmgr_entry * external_signaling_address_refresher
Definition: res_pjsip.h:161
const ast_string_field cert_file
Definition: res_pjsip.h:241
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
Sorcery Data Access Layer API.
pj_ssl_cipher ciphers[SIP_TLS_MAX_CIPHERS]
Definition: res_pjsip.h:148
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
unsigned show_details_only_level_0
Definition: res_pjsip_cli.h:46
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532