pjsip_transport_events.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2017, Digium Inc.
  5. *
  6. * Richard Mudgett <rmudgett@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. * \file
  20. * \brief Manages the global transport event notification callbacks.
  21. *
  22. * \author Richard Mudgett <rmudgett@digium.com>
  23. * See Also:
  24. *
  25. * \arg \ref AstCREDITS
  26. */
  27. #include "asterisk.h"
  28. #include "asterisk/res_pjsip.h"
  29. #include "include/res_pjsip_private.h"
  30. #include "asterisk/linkedlists.h"
  31. #include "asterisk/vector.h"
  32. /* ------------------------------------------------------------------- */
  33. /*! \brief Number of buckets for monitored active transports */
  34. #define ACTIVE_TRANSPORTS_BUCKETS 127
  35. /*! Who to notify when transport shuts down. */
  36. struct transport_monitor_notifier {
  37. /*! Who to call when transport shuts down. */
  38. ast_transport_monitor_shutdown_cb cb;
  39. /*! ao2 data object to pass to callback. */
  40. void *data;
  41. };
  42. /*! \brief Structure for transport to be monitored */
  43. struct transport_monitor {
  44. /*! \brief The underlying PJSIP transport */
  45. pjsip_transport *transport;
  46. /*! Who is interested in when this transport shuts down. */
  47. AST_VECTOR(, struct transport_monitor_notifier) monitors;
  48. };
  49. /*! \brief Global container of active reliable transports */
  50. static AO2_GLOBAL_OBJ_STATIC(active_transports);
  51. /*! \brief Existing transport events callback that we need to invoke */
  52. static pjsip_tp_state_callback tpmgr_state_callback;
  53. /*! List of registered transport state callbacks. */
  54. static AST_RWLIST_HEAD(, ast_sip_tpmgr_state_callback) transport_state_list;
  55. /*! \brief Hashing function for struct transport_monitor */
  56. AO2_STRING_FIELD_HASH_FN(transport_monitor, transport->obj_name);
  57. /*! \brief Comparison function for struct transport_monitor */
  58. AO2_STRING_FIELD_CMP_FN(transport_monitor, transport->obj_name);
  59. static const char *transport_state2str(pjsip_transport_state state)
  60. {
  61. const char *name;
  62. switch (state) {
  63. case PJSIP_TP_STATE_CONNECTED:
  64. name = "CONNECTED";
  65. break;
  66. case PJSIP_TP_STATE_DISCONNECTED:
  67. name = "DISCONNECTED";
  68. break;
  69. case PJSIP_TP_STATE_SHUTDOWN:
  70. name = "SHUTDOWN";
  71. break;
  72. case PJSIP_TP_STATE_DESTROY:
  73. name = "DESTROY";
  74. break;
  75. default:
  76. /*
  77. * We have to have a default case because the enum is
  78. * defined by a third-party library.
  79. */
  80. ast_assert(0);
  81. name = "<unknown>";
  82. break;
  83. }
  84. return name;
  85. }
  86. static void transport_monitor_dtor(void *vdoomed)
  87. {
  88. struct transport_monitor *monitored = vdoomed;
  89. int idx;
  90. for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {
  91. struct transport_monitor_notifier *notifier;
  92. notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);
  93. ao2_cleanup(notifier->data);
  94. }
  95. AST_VECTOR_FREE(&monitored->monitors);
  96. }
  97. /*!
  98. * \internal
  99. * \brief Do registered callbacks for the transport.
  100. * \since 13.21.0
  101. *
  102. * \param transports Active transports container
  103. * \param transport Which transport to do callbacks for.
  104. *
  105. * \return Nothing
  106. */
  107. static void transport_state_do_reg_callbacks(struct ao2_container *transports, pjsip_transport *transport)
  108. {
  109. struct transport_monitor *monitored;
  110. monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_UNLINK);
  111. if (monitored) {
  112. int idx;
  113. for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {
  114. struct transport_monitor_notifier *notifier;
  115. notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);
  116. ast_debug(3, "running callback %p(%p) for transport %s\n",
  117. notifier->cb, notifier->data, transport->obj_name);
  118. notifier->cb(notifier->data);
  119. }
  120. ao2_ref(monitored, -1);
  121. }
  122. }
  123. /*! \brief Callback invoked when transport state changes occur */
  124. static void transport_state_callback(pjsip_transport *transport,
  125. pjsip_transport_state state, const pjsip_transport_state_info *info)
  126. {
  127. struct ao2_container *transports;
  128. /* We only care about monitoring reliable transports */
  129. if (PJSIP_TRANSPORT_IS_RELIABLE(transport)
  130. && (transports = ao2_global_obj_ref(active_transports))) {
  131. struct transport_monitor *monitored;
  132. ast_debug(3, "Reliable transport '%s' state:%s\n",
  133. transport->obj_name, transport_state2str(state));
  134. switch (state) {
  135. case PJSIP_TP_STATE_CONNECTED:
  136. monitored = ao2_alloc_options(sizeof(*monitored),
  137. transport_monitor_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
  138. if (!monitored) {
  139. break;
  140. }
  141. monitored->transport = transport;
  142. if (AST_VECTOR_INIT(&monitored->monitors, 5)) {
  143. ao2_ref(monitored, -1);
  144. break;
  145. }
  146. ao2_link(transports, monitored);
  147. ao2_ref(monitored, -1);
  148. break;
  149. case PJSIP_TP_STATE_DISCONNECTED:
  150. if (!transport->is_shutdown) {
  151. pjsip_transport_shutdown(transport);
  152. }
  153. transport_state_do_reg_callbacks(transports, transport);
  154. break;
  155. case PJSIP_TP_STATE_SHUTDOWN:
  156. /*
  157. * Set shutdown flag early so we can force a new transport to be
  158. * created if a monitor callback needs to reestablish a link.
  159. * PJPROJECT sets the flag after this routine returns even though
  160. * it has already called the transport's shutdown routine.
  161. */
  162. transport->is_shutdown = PJ_TRUE;
  163. transport_state_do_reg_callbacks(transports, transport);
  164. break;
  165. case PJSIP_TP_STATE_DESTROY:
  166. transport_state_do_reg_callbacks(transports, transport);
  167. break;
  168. default:
  169. /*
  170. * We have to have a default case because the enum is
  171. * defined by a third-party library.
  172. */
  173. ast_assert(0);
  174. break;
  175. }
  176. ao2_ref(transports, -1);
  177. }
  178. /* Loop over other transport state callbacks registered with us. */
  179. if (!AST_LIST_EMPTY(&transport_state_list)) {
  180. struct ast_sip_tpmgr_state_callback *tpmgr_notifier;
  181. AST_RWLIST_RDLOCK(&transport_state_list);
  182. AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) {
  183. tpmgr_notifier->cb(transport, state, info);
  184. }
  185. AST_RWLIST_UNLOCK(&transport_state_list);
  186. }
  187. /* Forward to the old state callback if present */
  188. if (tpmgr_state_callback) {
  189. tpmgr_state_callback(transport, state, info);
  190. }
  191. }
  192. struct callback_data {
  193. ast_transport_monitor_shutdown_cb cb;
  194. void *data;
  195. ast_transport_monitor_data_matcher matches;
  196. };
  197. static int transport_monitor_unregister_cb(void *obj, void *arg, int flags)
  198. {
  199. struct transport_monitor *monitored = obj;
  200. struct callback_data *cb_data = arg;
  201. int idx;
  202. for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {
  203. struct transport_monitor_notifier *notifier;
  204. notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);
  205. if (notifier->cb == cb_data->cb && (!cb_data->data
  206. || cb_data->matches(cb_data->data, notifier->data))) {
  207. ao2_cleanup(notifier->data);
  208. AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx);
  209. ast_debug(3, "Unregistered monitor %p(%p) from transport %s\n",
  210. notifier->cb, notifier->data, monitored->transport->obj_name);
  211. }
  212. }
  213. return 0;
  214. }
  215. static int ptr_matcher(void *a, void *b)
  216. {
  217. return a == b;
  218. }
  219. void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb,
  220. void *data, ast_transport_monitor_data_matcher matches)
  221. {
  222. struct ao2_container *transports;
  223. struct callback_data cb_data = {
  224. .cb = cb,
  225. .data = data,
  226. .matches = matches ?: ptr_matcher,
  227. };
  228. ast_assert(cb != NULL);
  229. transports = ao2_global_obj_ref(active_transports);
  230. if (!transports) {
  231. return;
  232. }
  233. ao2_callback(transports, OBJ_MULTIPLE | OBJ_NODATA, transport_monitor_unregister_cb, &cb_data);
  234. ao2_ref(transports, -1);
  235. }
  236. void ast_sip_transport_monitor_unregister(pjsip_transport *transport,
  237. ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
  238. {
  239. struct ao2_container *transports;
  240. struct transport_monitor *monitored;
  241. ast_assert(transport != NULL && cb != NULL);
  242. transports = ao2_global_obj_ref(active_transports);
  243. if (!transports) {
  244. return;
  245. }
  246. ao2_lock(transports);
  247. monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
  248. if (monitored) {
  249. struct callback_data cb_data = {
  250. .cb = cb,
  251. .data = data,
  252. .matches = matches ?: ptr_matcher,
  253. };
  254. transport_monitor_unregister_cb(monitored, &cb_data, 0);
  255. ao2_ref(monitored, -1);
  256. }
  257. ao2_unlock(transports);
  258. ao2_ref(transports, -1);
  259. }
  260. enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport,
  261. ast_transport_monitor_shutdown_cb cb, void *ao2_data)
  262. {
  263. struct ao2_container *transports;
  264. struct transport_monitor *monitored;
  265. enum ast_transport_monitor_reg res = AST_TRANSPORT_MONITOR_REG_NOT_FOUND;
  266. ast_assert(transport != NULL && cb != NULL);
  267. transports = ao2_global_obj_ref(active_transports);
  268. if (!transports) {
  269. return res;
  270. }
  271. ao2_lock(transports);
  272. monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
  273. if (monitored) {
  274. struct transport_monitor_notifier new_monitor;
  275. /* Add new monitor to vector */
  276. new_monitor.cb = cb;
  277. new_monitor.data = ao2_bump(ao2_data);
  278. if (AST_VECTOR_APPEND(&monitored->monitors, new_monitor)) {
  279. ao2_cleanup(ao2_data);
  280. res = AST_TRANSPORT_MONITOR_REG_FAILED;
  281. ast_debug(3, "Register monitor %p(%p) to transport %s FAILED\n",
  282. cb, ao2_data, transport->obj_name);
  283. } else {
  284. res = AST_TRANSPORT_MONITOR_REG_SUCCESS;
  285. ast_debug(3, "Registered monitor %p(%p) to transport %s\n",
  286. cb, ao2_data, transport->obj_name);
  287. }
  288. ao2_ref(monitored, -1);
  289. }
  290. ao2_unlock(transports);
  291. ao2_ref(transports, -1);
  292. return res;
  293. }
  294. void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element)
  295. {
  296. AST_RWLIST_WRLOCK(&transport_state_list);
  297. AST_LIST_REMOVE(&transport_state_list, element, node);
  298. AST_RWLIST_UNLOCK(&transport_state_list);
  299. }
  300. void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *element)
  301. {
  302. struct ast_sip_tpmgr_state_callback *tpmgr_notifier;
  303. AST_RWLIST_WRLOCK(&transport_state_list);
  304. AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) {
  305. if (element == tpmgr_notifier) {
  306. /* Already registered. */
  307. AST_RWLIST_UNLOCK(&transport_state_list);
  308. return;
  309. }
  310. }
  311. AST_LIST_INSERT_HEAD(&transport_state_list, element, node);
  312. AST_RWLIST_UNLOCK(&transport_state_list);
  313. }
  314. void ast_sip_destroy_transport_events(void)
  315. {
  316. pjsip_tpmgr *tpmgr;
  317. tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());
  318. if (tpmgr) {
  319. pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback);
  320. }
  321. ao2_global_obj_release(active_transports);
  322. }
  323. int ast_sip_initialize_transport_events(void)
  324. {
  325. pjsip_tpmgr *tpmgr;
  326. struct ao2_container *transports;
  327. tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());
  328. if (!tpmgr) {
  329. return -1;
  330. }
  331. transports = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
  332. ACTIVE_TRANSPORTS_BUCKETS, transport_monitor_hash_fn, NULL,
  333. transport_monitor_cmp_fn);
  334. if (!transports) {
  335. return -1;
  336. }
  337. ao2_global_obj_replace_unref(active_transports, transports);
  338. ao2_ref(transports, -1);
  339. tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr);
  340. pjsip_tpmgr_set_state_cb(tpmgr, &transport_state_callback);
  341. return 0;
  342. }