From a86376fe6824b59876f8dde4dd2348532bc5d6bc Mon Sep 17 00:00:00 2001 From: Tinet-mucw Date: Wed, 13 Sep 2023 17:12:12 +0800 Subject: [PATCH] res_pjsip_transport_websocket: Prevent transport from being destroyed before message finishes. From the gdb information, ast_websocket_read reads a message successfully, then transport_read is called in the serializer. During execution of pjsip_transport_down, ws_session->stream->fd is closed; ast_websocket_read encounters an error and exits the while loop. After executing transport_shutdown, the transport's reference count becomes 0, causing a crash when sending SIP messages. This was due to pjsip_transport_dec_ref executing earlier than pjsip_rx_data_clone, leading to this issue. In websocket_cb executeing pjsip_transport_add_ref, this we now ensure the transport is not destroyed while in the loop. Resolves: asterisk#299 (cherry picked from commit edc674a6cadea9ab9d8eaf82c962eaa9f92a08a5) --- res/res_pjsip_transport_websocket.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index 3772097d3d..d76c1536c0 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -83,6 +83,20 @@ static pj_status_t ws_send_msg(pjsip_transport *transport, * Called by pjsip transport manager. */ static pj_status_t ws_destroy(pjsip_transport *transport) +{ + struct ws_transport *wstransport = (struct ws_transport *)transport; + + ao2_ref(wstransport, -1); + + return PJ_SUCCESS; +} + +/*! + * \brief Shut down the pjsip transport. + * + * Called by pjsip transport manager. + */ +static pj_status_t ws_shutdown(pjsip_transport *transport) { struct ws_transport *wstransport = (struct ws_transport *)transport; int fd = ast_websocket_fd(wstransport->ws_session); @@ -92,8 +106,6 @@ static pj_status_t ws_destroy(pjsip_transport *transport) shutdown(fd, SHUT_RDWR); } - ao2_ref(wstransport, -1); - return PJ_SUCCESS; } @@ -232,6 +244,7 @@ static int transport_create(void *data) newtransport->transport.dir = PJSIP_TP_DIR_INCOMING; newtransport->transport.tpmgr = tpmgr; newtransport->transport.send_msg = &ws_send_msg; + newtransport->transport.do_shutdown = &ws_shutdown; newtransport->transport.destroy = &ws_destroy; status = pjsip_transport_register(newtransport->transport.tpmgr, @@ -394,6 +407,7 @@ static void websocket_cb(struct ast_websocket *session, struct ast_variable *par transport = create_data.transport; read_data.transport = transport; + pjsip_transport_add_ref(&transport->transport); while (ast_websocket_wait_for_input(session, -1) > 0) { enum ast_websocket_opcode opcode; int fragmented; @@ -410,6 +424,7 @@ static void websocket_cb(struct ast_websocket *session, struct ast_variable *par break; } } + pjsip_transport_dec_ref(&transport->transport); ast_sip_push_task_wait_serializer(serializer, transport_shutdown, transport);