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
This commit is contained in:
Tinet-mucw 2023-09-13 17:12:12 +08:00 committed by asterisk-org-access-app[bot]
parent e06448353d
commit 671eeeca24
1 changed files with 17 additions and 2 deletions

View File

@ -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);