res_pjsip_session: properly handle SDP from a forked call with early media
authorlvl <digium@lvlconsultancy.nl>
Tue, 20 Feb 2018 17:48:50 +0000 (18:48 +0100)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 6 Mar 2018 19:35:22 +0000 (13:35 -0600)
In handle_negotiated_sdp(), use session->active_media_state when
session->pending_media_state is empty.  The 200's SDP should be fed into
handle_negotiated_sdp_session_media() together with the already negotiated
state, which is now in session->active_media_state instead.  Only if both
the session's pending and active media are empty should
handle_negotiated_sdp() abort.

ASTERISK-27441

Change-Id: If0d5150ffe6f38d8a854831fef37942258d4629c

res/res_pjsip_session.c

index fcd190b..f252017 100644 (file)
@@ -876,15 +876,30 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_
        struct ast_stream_topology *topology;
        unsigned int changed = 0;
 
-       /* This situation can legitimately happen when an SDP is received in a
-        * 183 Session Progress message.  In that case, everything's been done
-        * by the time this function is called and there are no more pending
-        * streams.
-        */
        if (!session->pending_media_state->topology) {
-               ast_debug(1, "Pending topology was NULL for channel '%s'\n",
-                       session->channel ? ast_channel_name(session->channel) : "unknown");
-               return 0;
+               if (session->active_media_state->topology) {
+                       /*
+                        * This happens when we have negotiated media after receiving a 183,
+                        * and we're now receiving a 200 with a new SDP.  In this case, there
+                        * is active_media_state, but the pending_media_state has been reset.
+                        */
+                       struct ast_sip_session_media_state *active_media_state_clone;
+
+                       active_media_state_clone =
+                               ast_sip_session_media_state_clone(session->active_media_state);
+                       if (!active_media_state_clone) {
+                               ast_log(LOG_WARNING, "Unable to clone active media state for channel '%s'\n",
+                                       session->channel ? ast_channel_name(session->channel) : "unknown");
+                               return -1;
+                       }
+
+                       ast_sip_session_media_state_free(session->pending_media_state);
+                       session->pending_media_state = active_media_state_clone;
+               } else {
+                       ast_log(LOG_WARNING, "No pending or active media state for channel '%s'\n",
+                               session->channel ? ast_channel_name(session->channel) : "unknown");
+                       return -1;
+               }
        }
 
        /* If we're handling negotiated streams, then we should already have set