Index: webrtc/pc/webrtcsession.cc |
diff --git a/webrtc/pc/webrtcsession.cc b/webrtc/pc/webrtcsession.cc |
index c78dbc4da78ecf1d6e546614257e522c3bce6f3e..075308142f2677b0ae6db538b7deab601591f9a8 100644 |
--- a/webrtc/pc/webrtcsession.cc |
+++ b/webrtc/pc/webrtcsession.cc |
@@ -61,8 +61,12 @@ const char kBundleWithoutRtcpMux[] = "RTCP-MUX must be enabled when BUNDLE " |
const char kCreateChannelFailed[] = "Failed to create channels."; |
const char kInvalidCandidates[] = "Description contains invalid candidates."; |
const char kInvalidSdp[] = "Invalid session description."; |
-const char kMlineMismatch[] = |
- "Offer and answer descriptions m-lines are not matching. Rejecting answer."; |
+const char kMlineMismatchInAnswer[] = |
+ "The order of m-lines in answer doesn't match order in offer. Rejecting " |
+ "answer."; |
+const char kMlineMismatchInSubsequentOffer[] = |
+ "The order of m-lines in subsequent offer doesn't match order from " |
+ "previous offer/answer."; |
const char kPushDownTDFailed[] = |
"Failed to push down transport description:"; |
const char kSdpWithoutDtlsFingerprint[] = |
@@ -136,31 +140,39 @@ IceCandidatePairType GetIceCandidatePairCounter( |
return kIceCandidatePairMax; |
} |
-// Compares |answer| against |offer|. Comparision is done |
-// for number of m-lines in answer against offer. If matches true will be |
-// returned otherwise false. |
-static bool VerifyMediaDescriptions( |
- const SessionDescription* answer, const SessionDescription* offer) { |
- if (offer->contents().size() != answer->contents().size()) |
+// Verify that the order of media sections in |desc1| matches |desc2|. The |
+// number of m= sections could be different. |
+static bool MediaSectionsInSameOrder(const SessionDescription* desc1, |
+ const SessionDescription* desc2) { |
+ if (!desc1 || !desc2) { |
return false; |
- |
- for (size_t i = 0; i < offer->contents().size(); ++i) { |
- if ((offer->contents()[i].name) != answer->contents()[i].name) { |
+ } |
+ for (size_t i = 0; |
+ i < desc1->contents().size() && i < desc2->contents().size(); ++i) { |
+ if ((desc2->contents()[i].name) != desc1->contents()[i].name) { |
return false; |
} |
- const MediaContentDescription* offer_mdesc = |
+ const MediaContentDescription* desc2_mdesc = |
static_cast<const MediaContentDescription*>( |
- offer->contents()[i].description); |
- const MediaContentDescription* answer_mdesc = |
+ desc2->contents()[i].description); |
+ const MediaContentDescription* desc1_mdesc = |
static_cast<const MediaContentDescription*>( |
- answer->contents()[i].description); |
- if (offer_mdesc->type() != answer_mdesc->type()) { |
+ desc1->contents()[i].description); |
+ if (desc2_mdesc->type() != desc1_mdesc->type()) { |
return false; |
} |
} |
return true; |
} |
+static bool MediaSectionsHaveSameCount(const SessionDescription* desc1, |
+ const SessionDescription* desc2) { |
+ if (!desc1 || !desc2) { |
+ return false; |
+ } |
+ return desc1->contents().size() == desc2->contents().size(); |
+} |
+ |
// Checks that each non-rejected content has SDES crypto keys or a DTLS |
// fingerprint, unless it's in a BUNDLE group, in which case only the |
// BUNDLE-tag section (first media section/description in the BUNDLE group) |
@@ -2153,12 +2165,21 @@ bool WebRtcSession::ValidateSessionDescription( |
// m-lines that do not rtcp-mux enabled. |
// Verify m-lines in Answer when compared against Offer. |
- if (action == kAnswer) { |
+ if (action == kAnswer || action == kPrAnswer) { |
const cricket::SessionDescription* offer_desc = |
(source == cricket::CS_LOCAL) ? remote_description()->description() |
: local_description()->description(); |
- if (!VerifyMediaDescriptions(sdesc->description(), offer_desc)) { |
- return BadAnswerSdp(source, kMlineMismatch, err_desc); |
+ if (!MediaSectionsHaveSameCount(sdesc->description(), offer_desc) || |
+ !MediaSectionsInSameOrder(sdesc->description(), offer_desc)) { |
+ return BadAnswerSdp(source, kMlineMismatchInAnswer, err_desc); |
+ } |
+ } else { |
+ // The re-offers should respect the order of m= sections in current local |
+ // description. See RFC3264 Section 8 paragraph 4 for more details. |
+ if (local_description() && |
+ !MediaSectionsInSameOrder(sdesc->description(), |
+ local_description()->description())) { |
+ return BadOfferSdp(source, kMlineMismatchInSubsequentOffer, err_desc); |
} |
} |