| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2017, Digium Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Richard Mudgett <rmudgett@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \file | 
					
						
							|  |  |  |  * \brief Manages the global transport event notification callbacks. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \author Richard Mudgett <rmudgett@digium.com> | 
					
						
							|  |  |  |  * 	See Also: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \arg \ref AstCREDITS | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/res_pjsip.h"
 | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | #include "asterisk/res_pjsip_cli.h"
 | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | #include "include/res_pjsip_private.h"
 | 
					
						
							|  |  |  | #include "asterisk/linkedlists.h"
 | 
					
						
							|  |  |  | #include "asterisk/vector.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Number of buckets for monitored active transports */ | 
					
						
							|  |  |  | #define ACTIVE_TRANSPORTS_BUCKETS 127
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! Who to notify when transport shuts down. */ | 
					
						
							|  |  |  | struct transport_monitor_notifier { | 
					
						
							|  |  |  | 	/*! Who to call when transport shuts down. */ | 
					
						
							|  |  |  | 	ast_transport_monitor_shutdown_cb cb; | 
					
						
							|  |  |  | 	/*! ao2 data object to pass to callback. */ | 
					
						
							|  |  |  | 	void *data; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Structure for transport to be monitored */ | 
					
						
							|  |  |  | struct transport_monitor { | 
					
						
							| 
									
										
										
										
											2023-01-30 16:17:08 -05:00
										 |  |  | 	/*! \brief Key \<ipaddr>:\<port> */ | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	char key[IP6ADDR_COLON_PORT_BUFLEN]; | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	/*! \brief The underlying PJSIP transport */ | 
					
						
							|  |  |  | 	pjsip_transport *transport; | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	/*! For debugging purposes, we save the obj_name
 | 
					
						
							|  |  |  | 	 * in case the transport goes away. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	char *transport_obj_name; | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	/*! Who is interested in when this transport shuts down. */ | 
					
						
							|  |  |  | 	AST_VECTOR(, struct transport_monitor_notifier) monitors; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Global container of active reliable transports */ | 
					
						
							|  |  |  | static AO2_GLOBAL_OBJ_STATIC(active_transports); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Existing transport events callback that we need to invoke */ | 
					
						
							|  |  |  | static pjsip_tp_state_callback tpmgr_state_callback; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! List of registered transport state callbacks. */ | 
					
						
							|  |  |  | static AST_RWLIST_HEAD(, ast_sip_tpmgr_state_callback) transport_state_list; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Hashing function for struct transport_monitor */ | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | AO2_STRING_FIELD_HASH_FN(transport_monitor, key); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Comparison function for struct transport_monitor */ | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | AO2_STRING_FIELD_CMP_FN(transport_monitor, key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Sort function for struct transport_monitor */ | 
					
						
							|  |  |  | AO2_STRING_FIELD_SORT_FN(transport_monitor, key); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | static const char *transport_state2str(pjsip_transport_state state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char *name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (state) { | 
					
						
							|  |  |  | 	case PJSIP_TP_STATE_CONNECTED: | 
					
						
							|  |  |  | 		name = "CONNECTED"; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case PJSIP_TP_STATE_DISCONNECTED: | 
					
						
							|  |  |  | 		name = "DISCONNECTED"; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case PJSIP_TP_STATE_SHUTDOWN: | 
					
						
							|  |  |  | 		name = "SHUTDOWN"; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case PJSIP_TP_STATE_DESTROY: | 
					
						
							|  |  |  | 		name = "DESTROY"; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * We have to have a default case because the enum is | 
					
						
							|  |  |  | 		 * defined by a third-party library. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ast_assert(0); | 
					
						
							|  |  |  | 		name = "<unknown>"; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void transport_monitor_dtor(void *vdoomed) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct transport_monitor *monitored = vdoomed; | 
					
						
							|  |  |  | 	int idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { | 
					
						
							|  |  |  | 		struct transport_monitor_notifier *notifier; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); | 
					
						
							|  |  |  | 		ao2_cleanup(notifier->data); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_VECTOR_FREE(&monitored->monitors); | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : state:MONITOR_DESTROYED\n", | 
					
						
							|  |  |  | 		monitored->key, monitored->transport->obj_name, | 
					
						
							|  |  |  | 		monitored->transport->type_name,pj_atomic_get(monitored->transport->ref_cnt)); | 
					
						
							|  |  |  | 	ast_free(monitored->transport_obj_name); | 
					
						
							|  |  |  | 	pjsip_transport_dec_ref(monitored->transport); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-07 12:15:05 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Do registered callbacks for the transport. | 
					
						
							|  |  |  |  * \since 13.21.0 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param transports Active transports container | 
					
						
							|  |  |  |  * \param transport Which transport to do callbacks for. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void transport_state_do_reg_callbacks(struct ao2_container *transports, pjsip_transport *transport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct transport_monitor *monitored; | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	char key[IP6ADDR_COLON_PORT_BUFLEN]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key); | 
					
						
							| 
									
										
										
										
											2018-03-07 12:15:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	monitored = ao2_find(transports, key, OBJ_SEARCH_KEY | OBJ_UNLINK); | 
					
						
							| 
									
										
										
										
											2018-03-07 12:15:05 +00:00
										 |  |  | 	if (monitored) { | 
					
						
							|  |  |  | 		int idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { | 
					
						
							|  |  |  | 			struct transport_monitor_notifier *notifier; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 			ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : running callback %p(%p)\n", | 
					
						
							|  |  |  | 				monitored->key, monitored->transport->obj_name, | 
					
						
							|  |  |  | 				monitored->transport->type_name, | 
					
						
							|  |  |  | 				pj_atomic_get(monitored->transport->ref_cnt), notifier->cb, notifier->data); | 
					
						
							| 
									
										
										
										
											2018-03-07 12:15:05 +00:00
										 |  |  | 			notifier->cb(notifier->data); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ao2_ref(monitored, -1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-08 18:32:33 -05:00
										 |  |  | static void verify_log_result(int log_level, const pjsip_transport *transport, | 
					
						
							|  |  |  | 	pj_uint32_t verify_status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char *status[32]; | 
					
						
							|  |  |  | 	unsigned int count; | 
					
						
							|  |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	count = ARRAY_LEN(status); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pj_ssl_cert_get_verify_status_strings(verify_status, status, &count) != PJ_SUCCESS) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Error retrieving certificate verification result(s)\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < count; ++i) { | 
					
						
							|  |  |  | 		ast_log(log_level, _A_, "Transport '%s' to remote '%.*s' - %s\n", transport->factory->info, | 
					
						
							|  |  |  | 			(int)pj_strlen(&transport->remote_name.host), pj_strbuf(&transport->remote_name.host), | 
					
						
							|  |  |  | 			status[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int verify_cert_name(const pj_str_t *local, const pj_str_t *remote) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char *p; | 
					
						
							|  |  |  | 	pj_ssize_t size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(3, "Verify certificate name: local = %.*s, remote = %.*s\n", | 
					
						
							|  |  |  | 		(unsigned int)pj_strlen(local), pj_strbuf(local), | 
					
						
							|  |  |  | 		(unsigned int)pj_strlen(remote), pj_strbuf(remote)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!pj_stricmp(remote, local)) { | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pj_strnicmp2(remote, "*.", 2)) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p = pj_strchr(local, '.'); | 
					
						
							|  |  |  | 	if (!p) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size = pj_strbuf(local) + pj_strlen(local) - ++p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return size == pj_strlen(remote) - 2 ? | 
					
						
							|  |  |  | 		!pj_memcmp(pj_strbuf(remote) + 2,  p, size) : 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int verify_cert_names(const pj_str_t *host, const pj_ssl_cert_info *remote) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < remote->subj_alt_name.cnt; ++i) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * DNS is the only type we're matching wildcards against, | 
					
						
							|  |  |  | 		 * so only recheck those. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (remote->subj_alt_name.entry[i].type == PJ_SSL_CERT_NAME_DNS | 
					
						
							|  |  |  | 			&& verify_cert_name(host, &remote->subj_alt_name.entry[i].name)) { | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return verify_cert_name(host, &remote->subject.cn); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int transport_tls_verify(const pjsip_transport *transport, | 
					
						
							|  |  |  | 	const pjsip_tls_state_info *state_info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pj_uint32_t verify_status; | 
					
						
							|  |  |  | 	const struct ast_sip_transport_state *state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (transport->dir == PJSIP_TP_DIR_INCOMING) { | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* transport_id should always be in factory info (see config_transport) */ | 
					
						
							|  |  |  | 	ast_assert(!ast_strlen_zero(transport->factory->info)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	state = ast_sip_get_transport_state(transport->factory->info); | 
					
						
							|  |  |  | 	if (!state) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * There should always be an associated state, but if for some | 
					
						
							|  |  |  | 		 * reason there is not then fail verification | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Transport state not found for '%s'\n", transport->factory->info); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	verify_status = state_info->ssl_sock_info->verify_status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * By this point pjsip has already completed its verification process. If | 
					
						
							|  |  |  | 	 * there was a name matching error it could be because they disallow wildcards. | 
					
						
							|  |  |  | 	 * If this transport has been configured to allow wildcards then we'll need | 
					
						
							|  |  |  | 	 * to re-check the name(s) for such. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (state->allow_wildcard_certs && | 
					
						
							|  |  |  | 			(verify_status & PJ_SSL_CERT_EIDENTITY_NOT_MATCH)) { | 
					
						
							|  |  |  | 		if (verify_cert_names(&transport->remote_name.host, | 
					
						
							|  |  |  | 			state_info->ssl_sock_info->remote_cert_info)) { | 
					
						
							|  |  |  | 			/* A name matched a wildcard, so clear the error */ | 
					
						
							|  |  |  | 			verify_status &= ~PJ_SSL_CERT_EIDENTITY_NOT_MATCH; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (state->verify_server && verify_status != PJ_SSL_CERT_ESUCCESS) { | 
					
						
							|  |  |  | 		verify_log_result(__LOG_ERROR, transport, verify_status); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	verify_log_result(__LOG_NOTICE, transport, verify_status); | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | /*! \brief Callback invoked when transport state changes occur */ | 
					
						
							|  |  |  | static void transport_state_callback(pjsip_transport *transport, | 
					
						
							|  |  |  | 	pjsip_transport_state state, const pjsip_transport_state_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ao2_container *transports; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We only care about monitoring reliable transports */ | 
					
						
							|  |  |  | 	if (PJSIP_TRANSPORT_IS_RELIABLE(transport) | 
					
						
							|  |  |  | 		&& (transports = ao2_global_obj_ref(active_transports))) { | 
					
						
							|  |  |  | 		struct transport_monitor *monitored; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 		ast_debug(3, "Transport " PJSTR_PRINTF_SPEC ":%d(%s,%s): RefCnt: %ld state:%s\n", | 
					
						
							|  |  |  | 			PJSTR_PRINTF_VAR(transport->remote_name.host), | 
					
						
							|  |  |  | 			transport->remote_name.port, transport->obj_name, | 
					
						
							|  |  |  | 			transport->type_name, | 
					
						
							|  |  |  | 			pj_atomic_get(transport->ref_cnt), transport_state2str(state)); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 		switch (state) { | 
					
						
							|  |  |  | 		case PJSIP_TP_STATE_CONNECTED: | 
					
						
							| 
									
										
										
										
											2022-06-08 18:32:33 -05:00
										 |  |  | 			if (PJSIP_TRANSPORT_IS_SECURE(transport) && | 
					
						
							|  |  |  | 				!transport_tls_verify(transport, info->ext_info)) { | 
					
						
							|  |  |  | 				pjsip_transport_shutdown(transport); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 			monitored = ao2_alloc_options(sizeof(*monitored), | 
					
						
							|  |  |  | 				transport_monitor_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); | 
					
						
							|  |  |  | 			if (!monitored) { | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			monitored->transport = transport; | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 			AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, monitored->key); | 
					
						
							|  |  |  | 			monitored->transport_obj_name = ast_strdup(transport->obj_name); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 			if (AST_VECTOR_INIT(&monitored->monitors, 5)) { | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 				ao2_ref(monitored, -1); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 			pjsip_transport_add_ref(monitored->transport); | 
					
						
							|  |  |  | 			ast_debug(3, "Transport %s(%s,%s): RefCnt: %ld state:MONITOR_CREATED\n", | 
					
						
							|  |  |  | 				monitored->key,	monitored->transport_obj_name, | 
					
						
							|  |  |  | 				monitored->transport->type_name, | 
					
						
							|  |  |  | 				pj_atomic_get(monitored->transport->ref_cnt)); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			ao2_link(transports, monitored); | 
					
						
							|  |  |  | 			ao2_ref(monitored, -1); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case PJSIP_TP_STATE_DISCONNECTED: | 
					
						
							|  |  |  | 			if (!transport->is_shutdown) { | 
					
						
							|  |  |  | 				pjsip_transport_shutdown(transport); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-07 12:15:05 +00:00
										 |  |  | 			transport_state_do_reg_callbacks(transports, transport); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case PJSIP_TP_STATE_SHUTDOWN: | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Set shutdown flag early so we can force a new transport to be | 
					
						
							|  |  |  | 			 * created if a monitor callback needs to reestablish a link. | 
					
						
							|  |  |  | 			 * PJPROJECT sets the flag after this routine returns even though | 
					
						
							|  |  |  | 			 * it has already called the transport's shutdown routine. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			transport->is_shutdown = PJ_TRUE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-07 12:15:05 +00:00
										 |  |  | 			transport_state_do_reg_callbacks(transports, transport); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case PJSIP_TP_STATE_DESTROY: | 
					
						
							|  |  |  | 			transport_state_do_reg_callbacks(transports, transport); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2018-03-07 12:15:05 +00:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * We have to have a default case because the enum is | 
					
						
							|  |  |  | 			 * defined by a third-party library. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			ast_assert(0); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ao2_ref(transports, -1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Loop over other transport state callbacks registered with us. */ | 
					
						
							|  |  |  | 	if (!AST_LIST_EMPTY(&transport_state_list)) { | 
					
						
							|  |  |  | 		struct ast_sip_tpmgr_state_callback *tpmgr_notifier; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		AST_RWLIST_RDLOCK(&transport_state_list); | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) { | 
					
						
							|  |  |  | 			tpmgr_notifier->cb(transport, state, info); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		AST_RWLIST_UNLOCK(&transport_state_list); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Forward to the old state callback if present */ | 
					
						
							|  |  |  | 	if (tpmgr_state_callback) { | 
					
						
							|  |  |  | 		tpmgr_state_callback(transport, state, info); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | struct callback_data { | 
					
						
							|  |  |  | 	ast_transport_monitor_shutdown_cb cb; | 
					
						
							|  |  |  | 	void *data; | 
					
						
							|  |  |  | 	ast_transport_monitor_data_matcher matches; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int transport_monitor_unregister_cb(void *obj, void *arg, int flags) | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct transport_monitor *monitored = obj; | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 	struct callback_data *cb_data = arg; | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	int idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { | 
					
						
							|  |  |  | 		struct transport_monitor_notifier *notifier; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 		if (notifier->cb == cb_data->cb && (!cb_data->data | 
					
						
							|  |  |  | 			|| cb_data->matches(cb_data->data, notifier->data))) { | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 			ao2_cleanup(notifier->data); | 
					
						
							|  |  |  | 			AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx); | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 			ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : Unregistered monitor %p(%p)\n", | 
					
						
							|  |  |  | 				monitored->key, monitored->transport_obj_name, | 
					
						
							|  |  |  | 				monitored->transport->type_name, | 
					
						
							|  |  |  | 				pj_atomic_get(monitored->transport->ref_cnt), notifier->cb, notifier->data); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | static int ptr_matcher(void *a, void *b) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return a == b; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, | 
					
						
							|  |  |  | 	void *data, ast_transport_monitor_data_matcher matches) | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ao2_container *transports; | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 	struct callback_data cb_data = { | 
					
						
							|  |  |  | 		.cb = cb, | 
					
						
							|  |  |  | 		.data = data, | 
					
						
							|  |  |  | 		.matches = matches ?: ptr_matcher, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_assert(cb != NULL); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	transports = ao2_global_obj_ref(active_transports); | 
					
						
							|  |  |  | 	if (!transports) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 	ao2_callback(transports, OBJ_MULTIPLE | OBJ_NODATA, transport_monitor_unregister_cb, &cb_data); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	ao2_ref(transports, -1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | void ast_sip_transport_monitor_unregister(pjsip_transport *transport, | 
					
						
							|  |  |  | 	ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches) | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | { | 
					
						
							|  |  |  | 	char key[IP6ADDR_COLON_PORT_BUFLEN]; | 
					
						
							|  |  |  | 	AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key); | 
					
						
							|  |  |  | 	ast_sip_transport_monitor_unregister_key(key, cb, data, matches); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ao2_container *transports; | 
					
						
							|  |  |  | 	struct transport_monitor *monitored; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	ast_assert(transport_key != NULL && cb != NULL); | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	transports = ao2_global_obj_ref(active_transports); | 
					
						
							|  |  |  | 	if (!transports) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ao2_lock(transports); | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	monitored = ao2_find(transports, transport_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	if (monitored) { | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 		struct callback_data cb_data = { | 
					
						
							|  |  |  | 			.cb = cb, | 
					
						
							|  |  |  | 			.data = data, | 
					
						
							|  |  |  | 			.matches = matches ?: ptr_matcher, | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 		transport_monitor_unregister_cb(monitored, &cb_data, 0); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 		ao2_ref(monitored, -1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ao2_unlock(transports); | 
					
						
							|  |  |  | 	ao2_ref(transports, -1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport, | 
					
						
							|  |  |  | 	ast_transport_monitor_shutdown_cb cb, void *ao2_data) | 
					
						
							| 
									
										
										
										
											2019-02-20 11:03:01 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	char key[IP6ADDR_COLON_PORT_BUFLEN]; | 
					
						
							|  |  |  | 	AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ast_sip_transport_monitor_register_replace_key(key, cb, ao2_data, NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key(const char *transport_key, | 
					
						
							|  |  |  | 	ast_transport_monitor_shutdown_cb cb, void *ao2_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ast_sip_transport_monitor_register_replace_key(transport_key, cb, ao2_data, NULL); | 
					
						
							| 
									
										
										
										
											2019-02-20 11:03:01 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | { | 
					
						
							|  |  |  | 	char key[IP6ADDR_COLON_PORT_BUFLEN]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key); | 
					
						
							|  |  |  | 	return ast_sip_transport_monitor_register_replace_key(key, cb, ao2_data, NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ao2_container *transports; | 
					
						
							|  |  |  | 	struct transport_monitor *monitored; | 
					
						
							|  |  |  | 	enum ast_transport_monitor_reg res = AST_TRANSPORT_MONITOR_REG_NOT_FOUND; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	ast_assert(transport_key != NULL && cb != NULL); | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	transports = ao2_global_obj_ref(active_transports); | 
					
						
							|  |  |  | 	if (!transports) { | 
					
						
							|  |  |  | 		return res; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ao2_lock(transports); | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	monitored = ao2_find(transports, transport_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	if (monitored) { | 
					
						
							|  |  |  | 		struct transport_monitor_notifier new_monitor; | 
					
						
							| 
									
										
										
										
											2019-02-20 11:03:01 -06:00
										 |  |  | 		struct callback_data cb_data = { | 
					
						
							|  |  |  | 			.cb = cb, | 
					
						
							|  |  |  | 			.data = ao2_data, | 
					
						
							|  |  |  | 			.matches = matches ?: ptr_matcher, | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		transport_monitor_unregister_cb(monitored, &cb_data, 0); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Add new monitor to vector */ | 
					
						
							|  |  |  | 		new_monitor.cb = cb; | 
					
						
							|  |  |  | 		new_monitor.data = ao2_bump(ao2_data); | 
					
						
							|  |  |  | 		if (AST_VECTOR_APPEND(&monitored->monitors, new_monitor)) { | 
					
						
							|  |  |  | 			ao2_cleanup(ao2_data); | 
					
						
							|  |  |  | 			res = AST_TRANSPORT_MONITOR_REG_FAILED; | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 			ast_debug(3, "Transport %s(%s) RefCnt: %ld : Monitor registration failed %p(%p)\n", | 
					
						
							|  |  |  | 				monitored->key, monitored->transport_obj_name, | 
					
						
							|  |  |  | 				pj_atomic_get(monitored->transport->ref_cnt), cb, ao2_data); | 
					
						
							| 
									
										
										
										
											2018-01-28 09:10:00 -07:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			res = AST_TRANSPORT_MONITOR_REG_SUCCESS; | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 			ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : Registered monitor %p(%p)\n", | 
					
						
							|  |  |  | 				monitored->key, monitored->transport_obj_name, | 
					
						
							|  |  |  | 				monitored->transport->type_name, | 
					
						
							|  |  |  | 				pj_atomic_get(monitored->transport->ref_cnt), cb, ao2_data); | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ao2_ref(monitored, -1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ao2_unlock(transports); | 
					
						
							|  |  |  | 	ao2_ref(transports, -1); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	AST_RWLIST_WRLOCK(&transport_state_list); | 
					
						
							|  |  |  | 	AST_LIST_REMOVE(&transport_state_list, element, node); | 
					
						
							|  |  |  | 	AST_RWLIST_UNLOCK(&transport_state_list); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *element) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_sip_tpmgr_state_callback *tpmgr_notifier; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_RWLIST_WRLOCK(&transport_state_list); | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) { | 
					
						
							|  |  |  | 		if (element == tpmgr_notifier) { | 
					
						
							|  |  |  | 			/* Already registered. */ | 
					
						
							|  |  |  | 			AST_RWLIST_UNLOCK(&transport_state_list); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_INSERT_HEAD(&transport_state_list, element, node); | 
					
						
							|  |  |  | 	AST_RWLIST_UNLOCK(&transport_state_list); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | static char *cli_show_monitors(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *cli_rc = CLI_FAILURE; | 
					
						
							|  |  |  | 	int rc = 0; | 
					
						
							|  |  |  | 	int using_regex = 0; | 
					
						
							|  |  |  | 	regex_t regex = { 0, }; | 
					
						
							|  |  |  | 	int container_count; | 
					
						
							|  |  |  | 	struct ao2_iterator iter; | 
					
						
							|  |  |  | 	struct ao2_container *sorted_monitors = NULL; | 
					
						
							|  |  |  | 	struct ao2_container *transports; | 
					
						
							|  |  |  | 	struct transport_monitor *monitored; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case CLI_INIT: | 
					
						
							|  |  |  | 		e->command = "pjsip show transport-monitors"; | 
					
						
							|  |  |  | 		e->usage = "Usage: pjsip show transport-monitors [ like <pattern> ]\n" | 
					
						
							|  |  |  | 		            "      Show pjsip transport monitors\n"; | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	case CLI_GENERATE: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (a->argc != 3 && a->argc != 5) { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (a->argc == 5) { | 
					
						
							|  |  |  | 		int regrc; | 
					
						
							|  |  |  | 		if (strcasecmp(a->argv[3], "like")) { | 
					
						
							|  |  |  | 			return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		regrc = regcomp(®ex, a->argv[4], REG_EXTENDED | REG_ICASE | REG_NOSUB); | 
					
						
							|  |  |  | 		if (regrc) { | 
					
						
							|  |  |  | 			char err[256]; | 
					
						
							|  |  |  | 			regerror(regrc, ®ex, err, 256); | 
					
						
							|  |  |  | 			ast_cli(a->fd, "PJSIP Transport Monitor: Error: %s\n", err); | 
					
						
							|  |  |  | 			return CLI_FAILURE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		using_regex = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Get a sorted snapshot of the scheduled tasks */ | 
					
						
							|  |  |  | 	sorted_monitors = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, | 
					
						
							|  |  |  | 		transport_monitor_sort_fn, NULL); | 
					
						
							|  |  |  | 	if (!sorted_monitors) { | 
					
						
							|  |  |  | 		ast_cli(a->fd, "PJSIP Transport Monitor: Unable to allocate temporary container\n"); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	transports = ao2_global_obj_ref(active_transports); | 
					
						
							|  |  |  | 	if (!transports) { | 
					
						
							|  |  |  | 		ast_cli(a->fd, "PJSIP Transport Monitor: Unable to get transports\n"); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ao2_lock(transports); | 
					
						
							|  |  |  | 	rc = ao2_container_dup(sorted_monitors, transports, 0); | 
					
						
							|  |  |  | 	ao2_unlock(transports); | 
					
						
							|  |  |  | 	ao2_ref(transports, -1); | 
					
						
							|  |  |  | 	if (rc != 0) { | 
					
						
							|  |  |  | 		ast_cli(a->fd, "PJSIP Transport Monitors: Unable to sort temporary container\n"); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	container_count = ao2_container_count(sorted_monitors); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_cli(a->fd, "PJSIP Transport Monitors:\n\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_cli(a->fd, | 
					
						
							|  |  |  | 		"<Remote Host...................................> <State.....> <Direction> <RefCnt> <Monitors> <ObjName............>\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iter = ao2_iterator_init(sorted_monitors, AO2_ITERATOR_UNLINK); | 
					
						
							|  |  |  | 	for (; (monitored = ao2_iterator_next(&iter)); ao2_ref(monitored, -1)) { | 
					
						
							|  |  |  | 		char *state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (using_regex && regexec(®ex, monitored->key, 0, NULL, 0) == REG_NOMATCH) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (monitored->transport->is_destroying) { | 
					
						
							|  |  |  | 			state = "DESTROYING"; | 
					
						
							|  |  |  | 		} else if (monitored->transport->is_shutdown) { | 
					
						
							|  |  |  | 			state = "SHUTDOWN"; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			state = "ACTIVE"; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-05 10:50:13 -04:00
										 |  |  | 		ast_cli(a->fd, " %-46.46s   %-10s   %-9s   %6ld   %8zu   %s\n", | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 			monitored->key, state, | 
					
						
							|  |  |  | 			monitored->transport->dir == PJSIP_TP_DIR_OUTGOING ? "Outgoing" : "Incoming", | 
					
						
							|  |  |  | 			pj_atomic_get(monitored->transport->ref_cnt), | 
					
						
							|  |  |  | 			AST_VECTOR_SIZE(&monitored->monitors), monitored->transport->obj_name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ao2_iterator_destroy(&iter); | 
					
						
							|  |  |  | 	ast_cli(a->fd, "\nTotal Transport Monitors: %d\n\n", container_count); | 
					
						
							|  |  |  | 	cli_rc = CLI_SUCCESS; | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  | 	if (using_regex) { | 
					
						
							|  |  |  | 		regfree(®ex); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ao2_cleanup(sorted_monitors); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return cli_rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_cli_entry cli_commands[] = { | 
					
						
							|  |  |  | 	AST_CLI_DEFINE(cli_show_monitors, "Show pjsip transport monitors"), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | void ast_sip_destroy_transport_events(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pjsip_tpmgr *tpmgr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); | 
					
						
							|  |  |  | 	if (tpmgr) { | 
					
						
							|  |  |  | 		pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ao2_global_obj_release(active_transports); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_sip_initialize_transport_events(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pjsip_tpmgr *tpmgr; | 
					
						
							|  |  |  | 	struct ao2_container *transports; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); | 
					
						
							|  |  |  | 	if (!tpmgr) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	transports = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 		ACTIVE_TRANSPORTS_BUCKETS, transport_monitor_hash_fn, transport_monitor_sort_fn, | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 		transport_monitor_cmp_fn); | 
					
						
							|  |  |  | 	if (!transports) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ao2_global_obj_replace_unref(active_transports, transports); | 
					
						
							|  |  |  | 	ao2_ref(transports, -1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr); | 
					
						
							|  |  |  | 	pjsip_tpmgr_set_state_cb(tpmgr, &transport_state_callback); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-10 08:35:54 -06:00
										 |  |  | 	ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 18:26:17 -05:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } |