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