Asterisk - The Open Source Telephony Project GIT-master-7921072
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#include "asterisk/res_pjsip.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"
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
41
43 char *id;
44 /*! Set if there was a change detected */
46 /*! \brief Transport configuration object */
48 /*! \brief Transport state information */
50};
51
52static 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
61
62/*! \brief hashing function for state objects */
63static 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;
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 */
84static 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) {
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 */
113static 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;
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 */
134static 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) {
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
163 struct ast_str **buf)
164{
166}
167
168static 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);
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
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
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
204};
205
206int 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
242int 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
271{
272 struct ast_sip_transport_state *transport_state;
273
274 if (ast_strlen_zero(transport_name)) {
276 return 0;
277 }
278
279 transport_state = ast_sip_get_transport_state(transport_name);
280 if (!transport_state) {
282 return -1;
283 }
284
285 if (!transport_state->flow) {
286 ao2_ref(transport_state, -1);
288 return 0;
289 }
290
291 ao2_lock(transport_state);
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
301void 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
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
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
376static 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 */
391static void sip_transport_destroy(void *obj)
392{
393 struct ast_sip_transport *transport = obj;
394
396}
397
398/*! \brief Allocator for transport */
399static 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
415static 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 */
436static void sip_transport_state_destroy(void *obj)
437{
438 struct ast_sip_transport_state *state = obj;
439
441}
442
443/*! \brief Destructor for ast_sip_transport state information */
444static 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
454{
455 const char *key = ast_sorcery_object_get_id(transport);
456
458}
459
461{
462 struct internal_state *state;
463 struct ast_sip_transport_state *trans_state;
464
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
476{
478
480 if (!state) {
481 return -1;
482 }
483
485 *state = NULL;
486 return 0;
487}
488
490{
492
494 if (state && *state) {
495 ao2_ref(*state, +1);
496 return *state;
497 }
498
499 return NULL;
500}
501
503{
505
507 if (!internal_state) {
508 return NULL;
509 }
510
512 if (!internal_state->id) {
514 return NULL;
515 }
516
517 /* We're transferring the reference from find_temporary_state */
519 if (!internal_state->state) {
521 return NULL;
522 }
526
527 return internal_state;
528}
529
530/*!
531 * \internal
532 * \brief Should only be called by the individual field handlers
533 */
535{
537 struct ast_sip_transport_state *new_state;
538
539 if ((new_state = find_temporary_state(transport))) {
540 return new_state;
541 }
542
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 }
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
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;
576 transport->external_address_refresher = transport->state->external_signaling_address_refresher;
577 memcpy(&transport->external_address, &transport->state->external_signaling_address, sizeof(transport->external_signaling_address));
578}
579
580#ifdef HAVE_PJSIP_TLS_TRANSPORT_RESTART
581static 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
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
614 if (ast_sockaddr_cmp(&a->external_signaling_address, &b->external_signaling_address)) {
615 return -1;
616 }
617
618 if (ast_sockaddr_cmp(&a->external_media_address, &b->external_media_address)) {
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
646static void states_cleanup(void *states)
647{
648 if (states) {
649 ao2_unlock(states);
650 }
651}
652
653/*! \brief Apply handler for transports */
654static 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);
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 */
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 */
1006static int transport_state_init(const struct aco_option *opt, struct ast_variable *var, void *obj)
1007{
1008 struct ast_sip_transport *transport = obj;
1010
1012
1013 return 0;
1014}
1015
1016/*! \brief Custom handler for TLS method setting */
1017static int transport_tls_file_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1018{
1019 struct ast_sip_transport *transport = obj;
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
1075static 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
1084static 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
1093static 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
1102static 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 */
1112static int transport_protocol_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1113{
1114 struct ast_sip_transport *transport = obj;
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
1145static 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
1153static 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 */
1167static 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;
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
1183static int transport_bind_to_str(const void *obj, const intptr_t *args, char **buf)
1184{
1185 const struct ast_sip_transport *transport = obj;
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 */
1203static int transport_tls_bool_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1204{
1205 struct ast_sip_transport *transport = obj;
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
1227static int verify_server_to_str(const void *obj, const intptr_t *args, char **buf)
1228{
1229 const struct ast_sip_transport *transport = obj;
1231
1232 if (!state) {
1233 return -1;
1234 }
1235
1236 *buf = ast_strdup(AST_YESNO(state->verify_server));
1237
1238 return 0;
1239}
1240
1241static int verify_client_to_str(const void *obj, const intptr_t *args, char **buf)
1242{
1243 const struct ast_sip_transport *transport = obj;
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
1255static int require_client_cert_to_str(const void *obj, const intptr_t *args, char **buf)
1256{
1257 const struct ast_sip_transport *transport = obj;
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
1269static int allow_wildcard_certs_to_str(const void *obj, const intptr_t *args, char **buf)
1270{
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 */
1284static int transport_tls_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1285{
1286 struct ast_sip_transport *transport = obj;
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
1324static 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
1341static int tls_method_to_str(const void *obj, const intptr_t *args, char **buf)
1342{
1343 const struct ast_sip_transport *transport = obj;
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 */
1359static 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 */
1391static 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 */
1425static 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;
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
1454static 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
1473 ast_free(str);
1474}
1475#endif
1476
1477#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
1478static int transport_tls_cipher_to_str(const void *obj, const intptr_t *args, char **buf)
1479{
1480 const struct ast_sip_transport *transport = obj;
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
1493static 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 */
1526static 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;
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
1551static 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 ? "!" : "",
1557
1558 ast_variable_list_append(head, ast_variable_new("local_net", str, ""));
1559}
1560
1561static 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;
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
1583static int localnet_to_str(const void *obj, const intptr_t *args, char **buf)
1584{
1586 const struct ast_sip_transport *transport = obj;
1588
1589 if (!state) {
1590 return -1;
1591 }
1592
1593 ast_ha_join(state->localnet, &str);
1595 return 0;
1596}
1597
1598/*! \brief Custom handler for TOS setting */
1599static 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;
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
1624static 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
1634static struct ao2_container *cli_get_container(const char *regex)
1635{
1637 struct ao2_container *s_container;
1638
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
1659static int cli_iterate(void *container, ao2_callback_fn callback, void *args)
1660{
1661 const struct ast_sip_endpoint *endpoint = container;
1663 "transport", endpoint->transport);
1664
1665 if (!transport) {
1666 return -1;
1667 }
1668
1669 return callback(transport, args, 0);
1670}
1671
1672static void *cli_retrieve_by_id(const char *id)
1673{
1674 return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", id);
1675}
1676
1677static 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
1692static 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];
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");
1717 }
1718
1719 return 0;
1720}
1721
1722static 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
1743
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
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
1774static 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
1785{
1788
1789 if (!states) {
1790 return NULL;
1791 }
1792
1794 return states;
1795}
1796
1797/*! \brief Initialize sorcery with transport support */
1799{
1801 struct ao2_container *transports = NULL;
1802
1803 /* Create outbound registration states container. */
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
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 */
1821 ast_sorcery_object_field_register(sorcery, "transport", "async_operations", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, async_operations));
1822
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));
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
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
1853
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";
1866
1869
1870 /* trigger load of transports from realtime by trying to revrieve them all */
1872 ao2_cleanup(transports);
1873
1874 return 0;
1875}
1876
1878{
1881
1883
1886
1887 return 0;
1888}
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:966
@ 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
const char * str
Definition: app_jack.c:147
#define var
Definition: ast_expr2f.c:605
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
enum cc_state state
Definition: ccss.c:393
static struct @116 qos
unsigned int cos
Definition: chan_iax2.c:356
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define 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_threadstorage temp_state_store
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:3386
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3302
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
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)
char * strsep(char **str, const char *delims)
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
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:501
#define AST_SIP_X_AST_TXP
Definition: res_pjsip.h:1078
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
#define SIP_TLS_MAX_CIPHERS
Maximum number of ciphers supported for a TLS transport.
Definition: res_pjsip.h:107
void ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Register an endpoint formatter.
Definition: res_pjsip.c:481
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
Definition: res_pjsip.c:487
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:2008
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:1079
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
Definition: res_pjsip_cli.h:24
#define CLI_MAX_WIDTH
Definition: res_pjsip_cli.h:26
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)
Definition: res_pjsip_cli.h:29
int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Registers a CLI formatter.
Definition: pjsip_cli.c:310
static struct ast_sorcery * sorcery
#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:2312
@ 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:2379
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
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
#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:1949
#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:1728
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2459
#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:2435
#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:1897
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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:2199
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 * 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:3047
struct mansession * s
Definition: res_pjsip.h:3049
const struct message * m
Definition: res_pjsip.h:3051
CLI Formatter Context passed to all formatters.
Definition: res_pjsip_cli.h:34
CLI Formatter Registry Entry.
Definition: res_pjsip_cli.h:52
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Definition: res_pjsip_cli.h:66
ao2_callback_fn * print_header
Definition: res_pjsip_cli.h:60
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
const char * name
Definition: res_pjsip_cli.h:58
ao2_callback_fn * print_body
Definition: res_pjsip_cli.h:62
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
An entity responsible formatting endpoint information.
Definition: res_pjsip.h:3073
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:3077
An entity with which Asterisk communicates.
Definition: res_pjsip.h:963
const ast_string_field transport
Definition: res_pjsip.h:992
Structure for SIP transport information.
Definition: res_pjsip.h:119
pjsip_tls_setting tls
Definition: res_pjsip.h:143
struct ast_dnsmgr_entry * external_media_address_refresher
Definition: res_pjsip.h:171
enum ast_transport type
Definition: res_pjsip.h:133
struct ast_sip_service_route_vector * service_routes
Definition: res_pjsip.h:191
struct pjsip_transport * transport
Transport itself.
Definition: res_pjsip.h:121
struct ast_ha * localnet
Definition: res_pjsip.h:156
struct ast_dnsmgr_entry * external_signaling_address_refresher
Definition: res_pjsip.h:161
pj_ssl_cipher ciphers[SIP_TLS_MAX_CIPHERS]
Definition: res_pjsip.h:148
Transport to bind to.
Definition: res_pjsip.h:221
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
unsigned int async_operations
Definition: res_pjsip.h:251
int tcp_keepalive_enable
Definition: res_pjsip.h:303
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:230
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
const char * args
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,...)
Definition: utils/frame.c:999
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:941
#define ast_assert(a)
Definition: utils.h:739
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
Definition: utils.c:3107
int ast_compare_versions(const char *version1, const char *version2)
Compare 2 major.minor.patch.extra version strings.
Definition: utils.c:3124
#define ARRAY_IN_BOUNDS(v, a)
Checks to see if value is within the bounds of the given array.
Definition: utils.h:687
#define ARRAY_LEN(a)
Definition: utils.h:666
#define MAX(a, b)
Definition: utils.h:233
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680