mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-16 23:08:32 +00:00
res_rtp_asterisk.c: Fix TURN deadlock by using ICE session group lock.
When a message is received on the TURN socket, the code processing the
message needs to call into the ICE/STUN session for further processing.
This code path locks the TURN group lock then the ICE/STUN group lock. In
another thread an ICE/STUN timer can fire off to send a keep alive message
over the TURN socket. In this code path, the ICE/STUN group lock is
obtained then the TURN group lock is obtained to send the packet. A
classic deadlock case if the group locks are not the same.
* Made TURN get created using the ICE/STUN session's group lock.
NOTE: I was originally concerned that the ICE/STUN session can get
recreated by ice_reset_session() for an event like RTCP multiplexing
causing a change during SDP negotiation. In this case the TURN group lock
would become different. However, TURN is also recreated as part of the
ICE/STUN recreation in ice_create() when all known ICE candidates are
added to the new ICE session. While the ICE/STUN and TURN sessions are
being recreated there is a period where the group locks could be
different.
ASTERISK-27023 #close
Patches:
res_rtp_asterisk-turn-deadlock-fix.patch (license #6502)
patch uploaded by Michael Walton (modified)
Change-Id: Ic870edb99ce4988a8c8eb6e678ca7f19da1432b9
This commit is contained in:
@@ -1293,6 +1293,8 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast
|
||||
pj_turn_session_info info;
|
||||
struct ast_sockaddr local, loop;
|
||||
pj_status_t status;
|
||||
pj_turn_sock_cfg turn_sock_cfg;
|
||||
struct ice_wrap *ice;
|
||||
|
||||
ast_rtp_instance_get_local_address(instance, &local);
|
||||
if (ast_sockaddr_is_ipv4(&local)) {
|
||||
@@ -1355,11 +1357,20 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast
|
||||
|
||||
pj_stun_config_init(&stun_config, &cachingpool.factory, 0, rtp->ioqueue->ioqueue, rtp->ioqueue->timerheap);
|
||||
|
||||
/* Use ICE session group lock for TURN session to avoid deadlock */
|
||||
pj_turn_sock_cfg_default(&turn_sock_cfg);
|
||||
ice = rtp->ice;
|
||||
if (ice) {
|
||||
turn_sock_cfg.grp_lock = ice->real_ice->grp_lock;
|
||||
ao2_ref(ice, +1);
|
||||
}
|
||||
|
||||
/* Release the instance lock to avoid deadlock with PJPROJECT group lock */
|
||||
ao2_unlock(instance);
|
||||
status = pj_turn_sock_create(&stun_config,
|
||||
ast_sockaddr_is_ipv4(&addr) ? pj_AF_INET() : pj_AF_INET6(), conn_type,
|
||||
turn_cb, NULL, instance, turn_sock);
|
||||
turn_cb, &turn_sock_cfg, instance, turn_sock);
|
||||
ao2_cleanup(ice);
|
||||
if (status != PJ_SUCCESS) {
|
||||
ast_log(LOG_WARNING, "Could not create a TURN client socket\n");
|
||||
ao2_lock(instance);
|
||||
|
||||
Reference in New Issue
Block a user