]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[core, mod_sofia] Fix codec set deadlock
authorJakub Karolczyk <jakub.karolczyk@signalwire.com>
Fri, 11 Oct 2024 13:16:02 +0000 (14:16 +0100)
committerGitHub <noreply@github.com>
Fri, 11 Oct 2024 13:16:02 +0000 (16:16 +0300)
src/include/switch_core.h
src/mod/endpoints/mod_sofia/mod_sofia.c
src/switch_core_codec.c
src/switch_core_media.c
src/switch_core_session.c

index e4c615941d96b9a5274479501efba32830d6e2ef..ff04fa0954c03814b7470f93cbc4d300d4642e32 100644 (file)
@@ -1822,6 +1822,17 @@ SWITCH_DECLARE(void) switch_core_session_unlock_codec_write(_In_ switch_core_ses
 SWITCH_DECLARE(void) switch_core_session_lock_codec_read(_In_ switch_core_session_t *session);
 SWITCH_DECLARE(void) switch_core_session_unlock_codec_read(_In_ switch_core_session_t *session);
 
+/*!
+  \brief Lock codec read mutex and codec write mutex using trylock in an infinite loop
+  \param session session to lock the codec in
+*/
+SWITCH_DECLARE(void) switch_core_codec_lock_full(switch_core_session_t *session);
+
+/*!
+  \brief Unlock codec read mutex and codec write mutex
+  \param session session to unlock the codec in
+*/
+SWITCH_DECLARE(void) switch_core_codec_unlock_full(switch_core_session_t *session);
 
 SWITCH_DECLARE(switch_status_t) switch_core_session_get_read_impl(switch_core_session_t *session, switch_codec_implementation_t *impp);
 SWITCH_DECLARE(switch_status_t) switch_core_session_get_real_read_impl(switch_core_session_t *session, switch_codec_implementation_t *impp);
index c5ce6e38555e96da4a48dfac7ac688cc184ede6b..c41ed9b2e38c37bff9e36fd5447f8a1c1ad866b3 100644 (file)
@@ -1339,6 +1339,8 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 
        if (msg->message_id == SWITCH_MESSAGE_INDICATE_SIGNAL_DATA) {
                sofia_dispatch_event_t *de = (sofia_dispatch_event_t *) msg->pointer_arg;
+
+               switch_core_session_lock_codec_write(session);
                switch_mutex_lock(tech_pvt->sofia_mutex);
                if (switch_core_session_in_thread(session)) {
                        de->session = session;
@@ -1346,8 +1348,8 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 
                sofia_process_dispatch_event(&de);
 
-
                switch_mutex_unlock(tech_pvt->sofia_mutex);
+               switch_core_session_unlock_codec_write(session);
                goto end;
        }
 
@@ -1363,6 +1365,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 
        /* ones that do not need to lock sofia mutex */
        switch (msg->message_id) {
+       case SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY:
+       case SWITCH_MESSAGE_RESAMPLE_EVENT:
+               goto end;
        case SWITCH_MESSAGE_INDICATE_KEEPALIVE:
                {
                        if (msg->numeric_arg) {
@@ -1523,6 +1528,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
        }
 
        /* ones that do need to lock sofia mutex */
+       switch_core_session_lock_codec_write(session);
        switch_mutex_lock(tech_pvt->sofia_mutex);
 
        if (switch_channel_down(channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
@@ -1557,7 +1563,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
                        tech_pvt->proxy_refer_uuid = (char *)msg->string_array_arg[0];
                } else if (!switch_channel_var_true(tech_pvt->channel, "sip_refer_continue_after_reply")) {
                        switch_mutex_unlock(tech_pvt->sofia_mutex);
+                       switch_core_session_unlock_codec_write(session);
                        sofia_wait_for_reply(tech_pvt, 9999, 10);
+                       switch_core_session_lock_codec_write(session);
                        switch_mutex_lock(tech_pvt->sofia_mutex);
 
                        if ((var = switch_channel_get_variable(tech_pvt->channel, "sip_refer_reply"))) {
@@ -2391,6 +2399,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
                                                                /* Unlock the session signal to allow the ack to make it in */
                                                                // Maybe we should timeout?
                                                                switch_mutex_unlock(tech_pvt->sofia_mutex);
+                                                               switch_core_session_unlock_codec_write(session);
 
                                                                while (switch_channel_ready(channel) && !sofia_test_flag(tech_pvt, TFLAG_3PCC_HAS_ACK)) {
                                                                        switch_ivr_parse_all_events(session);
@@ -2398,6 +2407,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
                                                                }
 
                                                                /*  Regain lock on sofia */
+                                                               switch_core_session_lock_codec_write(session);
                                                                switch_mutex_lock(tech_pvt->sofia_mutex);
 
                                                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Done waiting for ACK\n");
@@ -2706,6 +2716,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
        //}
 
        switch_mutex_unlock(tech_pvt->sofia_mutex);
+       switch_core_session_unlock_codec_write(session);
 
   end:
 
index e5c22cd610e073657f25e34c11e790683e81af54..5cedbed6e065d8f777bee5e4f76adede6d9c0e7e 100644 (file)
@@ -59,6 +59,27 @@ SWITCH_DECLARE(void) switch_core_session_unset_read_codec(switch_core_session_t
        switch_mutex_unlock(session->codec_read_mutex);
 }
 
+SWITCH_DECLARE(void) switch_core_codec_lock_full(switch_core_session_t *session)
+{
+       do {
+               if (switch_mutex_trylock(session->codec_write_mutex) == SWITCH_STATUS_SUCCESS) {
+                       if (switch_mutex_trylock(session->codec_read_mutex) == SWITCH_STATUS_SUCCESS) {
+                               return;
+                       }
+
+                       switch_mutex_unlock(session->codec_write_mutex);
+               }
+
+               switch_cond_next();
+       } while (1);
+}
+
+SWITCH_DECLARE(void) switch_core_codec_unlock_full(switch_core_session_t *session)
+{
+       switch_mutex_unlock(session->codec_read_mutex);
+       switch_mutex_unlock(session->codec_write_mutex);
+}
+
 SWITCH_DECLARE(void) switch_core_session_lock_codec_write(switch_core_session_t *session)
 {
        switch_mutex_lock(session->codec_write_mutex);
index 58ef94a53edea76b2bcd3211de54d979b2076df9..de5d0eff74c395eb39fa2315e3332d0d144abd1e 100644 (file)
@@ -3601,8 +3601,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_
 
        switch_assert(session);
 
-       switch_core_session_lock_codec_write(session);
-       switch_core_session_lock_codec_read(session);
+       switch_core_codec_lock_full(session);
 
        switch_mutex_lock(session->codec_init_mutex);
 
@@ -3756,8 +3755,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_
 
        switch_mutex_unlock(session->codec_init_mutex);
 
-       switch_core_session_unlock_codec_read(session);
-       switch_core_session_unlock_codec_write(session);
+       switch_core_codec_unlock_full(session);
 
        return status;
 }
index 61aa50007057791473480cd5ddb41c523070c358..94944faa2fb4b3391bcb1d58d0023f46b6f776ec 100644 (file)
@@ -1392,6 +1392,8 @@ SWITCH_DECLARE(void) switch_core_session_reset(switch_core_session_t *session, s
 {
        switch_channel_t *channel = switch_core_session_get_channel(session);
 
+       switch_core_codec_lock_full(session);
+
        if (reset_read_codec) {
                switch_core_session_set_read_codec(session, NULL);
                if (session->sdata && switch_core_codec_ready(&session->sdata->codec)) {
@@ -1425,6 +1427,8 @@ SWITCH_DECLARE(void) switch_core_session_reset(switch_core_session_t *session, s
        switch_clear_flag(session, SSF_WARN_TRANSCODE);
        switch_ivr_deactivate_unicast(session);
        switch_channel_clear_flag(channel, CF_BREAK);
+
+       switch_core_codec_unlock_full(session);
 }