32 #include "asterisk/res_pjsip.h"
33 #include "asterisk/res_pjsip_cli.h"
34 #include "include/res_pjsip_private.h"
41 #define ACTIVE_TRANSPORTS_BUCKETS 127
46 ast_transport_monitor_shutdown_cb
cb;
54 char key[IP6ADDR_COLON_PORT_BUFLEN];
83 static const
char *transport_state2str(pjsip_transport_state
state)
88 case PJSIP_TP_STATE_CONNECTED:
91 case PJSIP_TP_STATE_DISCONNECTED:
92 name =
"DISCONNECTED";
94 case PJSIP_TP_STATE_SHUTDOWN:
97 case PJSIP_TP_STATE_DESTROY:
112 static void transport_monitor_dtor(
void *vdoomed)
121 ao2_cleanup(notifier->
data);
124 ast_debug(3,
"Transport %s(%s,%s) RefCnt: %ld : state:MONITOR_DESTROYED\n",
128 pjsip_transport_dec_ref(monitored->
transport);
139 static void transport_state_do_reg_callbacks(
struct ao2_container *transports, pjsip_transport *transport)
142 char key[IP6ADDR_COLON_PORT_BUFLEN];
144 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key);
154 ast_debug(3,
"Transport %s(%s,%s) RefCnt: %ld : running callback %p(%p)\n",
157 pj_atomic_get(monitored->
transport->ref_cnt), notifier->
cb, notifier->
data);
158 notifier->
cb(notifier->
data);
164 static void verify_log_result(
int log_level,
const pjsip_transport *transport,
165 pj_uint32_t verify_status)
167 const char *status[32];
171 count = ARRAY_LEN(status);
173 if (pj_ssl_cert_get_verify_status_strings(verify_status, status, &count) != PJ_SUCCESS) {
174 ast_log(LOG_ERROR,
"Error retrieving certificate verification result(s)\n");
178 for (i = 0; i < count; ++i) {
179 ast_log(log_level, _A_,
"Transport '%s' to remote '%.*s' - %s\n", transport->factory->info,
180 (
int)pj_strlen(&transport->remote_name.host), pj_strbuf(&transport->remote_name.host),
185 static int verify_cert_name(
const pj_str_t *local,
const pj_str_t *remote)
190 ast_debug(3,
"Verify certificate name: local = %.*s, remote = %.*s\n",
191 (
unsigned int)pj_strlen(local), pj_strbuf(local),
192 (
unsigned int)pj_strlen(remote), pj_strbuf(remote));
194 if (!pj_stricmp(remote, local)) {
198 if (pj_strnicmp2(remote,
"*.", 2)) {
202 p = pj_strchr(local,
'.');
207 size = pj_strbuf(local) + pj_strlen(local) - ++p;
209 return size == pj_strlen(remote) - 2 ?
210 !pj_memcmp(pj_strbuf(remote) + 2, p, size) : 0;
213 static int verify_cert_names(
const pj_str_t *host,
const pj_ssl_cert_info *remote)
217 for (i = 0; i < remote->subj_alt_name.cnt; ++i) {
222 if (remote->subj_alt_name.entry[i].type == PJ_SSL_CERT_NAME_DNS
223 && verify_cert_name(host, &remote->subj_alt_name.entry[i].name)) {
228 return verify_cert_name(host, &remote->subject.cn);
231 static int transport_tls_verify(
const pjsip_transport *transport,
232 const pjsip_tls_state_info *state_info)
234 pj_uint32_t verify_status;
237 if (transport->dir == PJSIP_TP_DIR_INCOMING) {
242 ast_assert(!ast_strlen_zero(transport->factory->info));
244 state = ast_sip_get_transport_state(transport->factory->info);
250 ast_log(LOG_ERROR,
"Transport state not found for '%s'\n", transport->factory->info);
254 verify_status = state_info->ssl_sock_info->verify_status;
263 (verify_status & PJ_SSL_CERT_EIDENTITY_NOT_MATCH)) {
264 if (verify_cert_names(&transport->remote_name.host,
265 state_info->ssl_sock_info->remote_cert_info)) {
267 verify_status &= ~PJ_SSL_CERT_EIDENTITY_NOT_MATCH;
271 if (state->
verify_server && verify_status != PJ_SSL_CERT_ESUCCESS) {
272 verify_log_result(__LOG_ERROR, transport, verify_status);
276 verify_log_result(__LOG_NOTICE, transport, verify_status);
282 pjsip_transport_state state,
const pjsip_transport_state_info *info)
287 if (PJSIP_TRANSPORT_IS_RELIABLE(transport)
291 ast_debug(3,
"Transport " PJSTR_PRINTF_SPEC
":%d(%s,%s): RefCnt: %ld state:%s\n",
292 PJSTR_PRINTF_VAR(transport->remote_name.host),
293 transport->remote_name.port, transport->obj_name,
294 transport->type_name,
295 pj_atomic_get(transport->ref_cnt), transport_state2str(state));
297 case PJSIP_TP_STATE_CONNECTED:
298 if (PJSIP_TRANSPORT_IS_SECURE(transport) &&
299 !transport_tls_verify(transport, info->ext_info)) {
300 pjsip_transport_shutdown(transport);
304 monitored = ao2_alloc_options(
sizeof(*monitored),
310 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, monitored->
key);
317 pjsip_transport_add_ref(monitored->
transport);
318 ast_debug(3,
"Transport %s(%s,%s): RefCnt: %ld state:MONITOR_CREATED\n",
321 pj_atomic_get(monitored->
transport->ref_cnt));
326 case PJSIP_TP_STATE_DISCONNECTED:
327 if (!transport->is_shutdown) {
328 pjsip_transport_shutdown(transport);
330 transport_state_do_reg_callbacks(transports, transport);
332 case PJSIP_TP_STATE_SHUTDOWN:
339 transport->is_shutdown = PJ_TRUE;
341 transport_state_do_reg_callbacks(transports, transport);
343 case PJSIP_TP_STATE_DESTROY:
344 transport_state_do_reg_callbacks(transports, transport);
364 tpmgr_notifier->
cb(transport, state, info);
376 ast_transport_monitor_shutdown_cb cb;
378 ast_transport_monitor_data_matcher matches;
381 static int transport_monitor_unregister_cb(
void *obj,
void *arg,
int flags)
391 if (notifier->
cb == cb_data->cb && (!cb_data->data
392 || cb_data->matches(cb_data->data, notifier->
data))) {
393 ao2_cleanup(notifier->
data);
395 ast_debug(3,
"Transport %s(%s,%s) RefCnt: %ld : Unregistered monitor %p(%p)\n",
398 pj_atomic_get(monitored->
transport->ref_cnt), notifier->
cb, notifier->
data);
404 static int ptr_matcher(
void *a,
void *b)
410 void *
data, ast_transport_monitor_data_matcher matches)
416 .matches = matches ?: ptr_matcher,
419 ast_assert(cb != NULL);
430 ast_transport_monitor_shutdown_cb cb,
void *data, ast_transport_monitor_data_matcher matches)
432 char key[IP6ADDR_COLON_PORT_BUFLEN];
433 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key);
438 ast_transport_monitor_shutdown_cb cb,
void *data, ast_transport_monitor_data_matcher matches)
443 ast_assert(transport_key != NULL && cb != NULL);
450 ao2_lock(transports);
456 .matches = matches ?: ptr_matcher,
459 transport_monitor_unregister_cb(monitored, &cb_data, 0);
462 ao2_unlock(transports);
467 ast_transport_monitor_shutdown_cb cb,
void *ao2_data)
469 char key[IP6ADDR_COLON_PORT_BUFLEN];
470 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key);
476 ast_transport_monitor_shutdown_cb cb,
void *ao2_data)
482 ast_transport_monitor_shutdown_cb cb,
void *ao2_data, ast_transport_monitor_data_matcher matches)
484 char key[IP6ADDR_COLON_PORT_BUFLEN];
486 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key);
491 ast_transport_monitor_shutdown_cb cb,
void *ao2_data, ast_transport_monitor_data_matcher matches)
495 enum ast_transport_monitor_reg res = AST_TRANSPORT_MONITOR_REG_NOT_FOUND;
497 ast_assert(transport_key != NULL && cb != NULL);
504 ao2_lock(transports);
511 .matches = matches ?: ptr_matcher,
514 transport_monitor_unregister_cb(monitored, &cb_data, 0);
520 ao2_cleanup(ao2_data);
521 res = AST_TRANSPORT_MONITOR_REG_FAILED;
522 ast_debug(3,
"Transport %s(%s) RefCnt: %ld : Monitor registration failed %p(%p)\n",
524 pj_atomic_get(monitored->
transport->ref_cnt), cb, ao2_data);
526 res = AST_TRANSPORT_MONITOR_REG_SUCCESS;
527 ast_debug(3,
"Transport %s(%s,%s) RefCnt: %ld : Registered monitor %p(%p)\n",
530 pj_atomic_get(monitored->
transport->ref_cnt), cb, ao2_data);
535 ao2_unlock(transports);
553 if (element == tpmgr_notifier) {
565 char *cli_rc = CLI_FAILURE;
568 regex_t regex = { 0, };
577 e->
command =
"pjsip show transport-monitors";
578 e->
usage =
"Usage: pjsip show transport-monitors [ like <pattern> ]\n"
579 " Show pjsip transport monitors\n";
585 if (a->argc != 3 && a->argc != 5) {
586 return CLI_SHOWUSAGE;
591 if (strcasecmp(a->argv[3],
"like")) {
592 return CLI_SHOWUSAGE;
594 regrc = regcomp(®ex, a->argv[4], REG_EXTENDED | REG_ICASE | REG_NOSUB);
597 regerror(regrc, ®ex, err, 256);
598 ast_cli(a->fd,
"PJSIP Transport Monitor: Error: %s\n", err);
606 transport_monitor_sort_fn, NULL);
607 if (!sorted_monitors) {
608 ast_cli(a->fd,
"PJSIP Transport Monitor: Unable to allocate temporary container\n");
614 ast_cli(a->fd,
"PJSIP Transport Monitor: Unable to get transports\n");
618 ao2_lock(transports);
620 ao2_unlock(transports);
623 ast_cli(a->fd,
"PJSIP Transport Monitors: Unable to sort temporary container\n");
628 ast_cli(a->fd,
"PJSIP Transport Monitors:\n\n");
631 "<Remote Host...................................> <State.....> <Direction> <RefCnt> <Monitors> <ObjName............>\n");
634 for (; (monitored = ao2_iterator_next(&iter));
ao2_ref(monitored, -1)) {
637 if (using_regex && regexec(®ex, monitored->
key, 0, NULL, 0) == REG_NOMATCH) {
641 if (monitored->
transport->is_destroying) {
642 state =
"DESTROYING";
643 }
else if (monitored->
transport->is_shutdown) {
649 ast_cli(a->fd,
" %-46.46s %-10s %-9s %6ld %8zu %s\n",
650 monitored->
key, state,
651 monitored->
transport->dir == PJSIP_TP_DIR_OUTGOING ?
"Outgoing" :
"Incoming",
652 pj_atomic_get(monitored->
transport->ref_cnt),
656 ast_cli(a->fd,
"\nTotal Transport Monitors: %d\n\n", container_count);
657 cli_rc = CLI_SUCCESS;
662 ao2_cleanup(sorted_monitors);
668 AST_CLI_DEFINE(cli_show_monitors,
"Show pjsip transport monitors"),
671 void ast_sip_destroy_transport_events(
void)
677 tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());
685 int ast_sip_initialize_transport_events(
void)
690 tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());
697 transport_monitor_cmp_fn);
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Asterisk main include file. File version handling, generic pbx functions.
AO2_STRING_FIELD_HASH_FN(transport_monitor, key)
Hashing function for struct transport_monitor.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
The arg parameter is a search key, but is not an object.
static pjsip_tp_state_callback tpmgr_state_callback
Existing transport events callback that we need to invoke.
descriptor for a cli entry.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
static struct @461 transport_state_list
#define ACTIVE_TRANSPORTS_BUCKETS
Number of buckets for monitored active transports.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Assume that the ao2_container is already locked.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
AO2_STRING_FIELD_CMP_FN(transport_monitor, key)
Comparison function for struct transport_monitor.
#define AST_VECTOR_REMOVE_UNORDERED(vec, idx)
Remove an element from an unordered vector by index.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define ast_strdup(str)
A wrapper for strdup()
struct transport_monitor::@462 monitors
void ast_sip_transport_monitor_unregister_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
static int log_level
Log level for history output.
static void transport_state_callback(pjsip_transport *transport, pjsip_transport_state state, const pjsip_transport_state_info *info)
Callback invoked when transport state changes occur.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *ao2_data)
Register a reliable transport shutdown monitor callback.
Structure for transport to be monitored.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Structure for SIP transport information.
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
A set of macros to manage forward-linked lists.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *ao2_data)
Register a reliable transport shutdown monitor callback.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches)
Register a reliable transport shutdown monitor callback replacing any duplicate.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
pjsip_transport * transport
The underlying PJSIP transport.
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches)
Register a reliable transport shutdown monitor callback replacing any duplicate.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
static AO2_GLOBAL_OBJ_STATIC(active_transports)
Global container of active reliable transports.
void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a transport shutdown monitor from all reliable transports.
pjsip_tp_state_callback cb
void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
Vector container support.
ast_transport_monitor_shutdown_cb cb
#define AST_RWLIST_HEAD(name, type)
Defines a structure to be used to hold a read/write list of specified type.
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
AO2_STRING_FIELD_SORT_FN(transport_monitor, key)
Sort function for struct transport_monitor.
void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element)
Unregister a transport state notification callback element.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
char * transport_obj_name
char key[IP6ADDR_COLON_PORT_BUFLEN]
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *element)
Register a transport state notification callback element.
#define ao2_link(container, obj)
Add an object to a container.