Bug 1335262: read and emit datachannel max-message-size. r=jesup
authorNils Ohlmeier [:drno] <drno@ohlmeier.org>
Wed, 31 May 2017 20:58:53 -0700
changeset 410195 9fa721e390adef999705f2acc28dc8213e467e54
parent 410194 169d5dfe505f3f519d1aa14309327ad768429a90
child 410196 74b1f6dafa0a29f4d185b3b205eef813c8936a58
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1335262
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1335262: read and emit datachannel max-message-size. r=jesup MozReview-Commit-ID: HwaoshovZIS
media/webrtc/signaling/gtest/jsep_track_unittest.cpp
media/webrtc/signaling/src/jsep/JsepCodecDescription.h
media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
media/webrtc/signaling/src/sdp/SdpAttributeList.h
media/webrtc/signaling/src/sdp/SdpHelper.cpp
media/webrtc/signaling/src/sdp/SdpMediaSection.cpp
media/webrtc/signaling/src/sdp/SdpMediaSection.h
media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp
media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h
media/webrtc/signaling/src/sdp/SipccSdpMediaSection.cpp
media/webrtc/signaling/src/sdp/SipccSdpMediaSection.h
netwerk/sctp/datachannel/DataChannelProtocol.h
--- a/media/webrtc/signaling/gtest/jsep_track_unittest.cpp
+++ b/media/webrtc/signaling/gtest/jsep_track_unittest.cpp
@@ -72,17 +72,18 @@ class JsepTrackTest : public ::testing::
             );
         results.push_back(ulpfec);
       }
 
       results.push_back(
           new JsepApplicationCodecDescription(
             "webrtc-datachannel",
             256,
-            5999
+            5999,
+            499
             ));
 
       // if we're doing something with red, it needs
       // to update the redundant encodings list
       if (red) {
         red->UpdateRedundantEncodings(results);
       }
 
@@ -1103,44 +1104,55 @@ TEST_F(JsepTrackTest, DataChannelDraft05
   OfferAnswer();
   CheckOffEncodingCount(1);
   CheckAnsEncodingCount(1);
 
   ASSERT_NE(std::string::npos,
             mOffer->ToString().find("a=sctpmap:5999 webrtc-datachannel 256"));
   ASSERT_NE(std::string::npos,
             mAnswer->ToString().find("a=sctpmap:5999 webrtc-datachannel 256"));
+  // Note: this is testing for a workaround, see bug 1335262 for details
+  ASSERT_NE(std::string::npos,
+            mOffer->ToString().find("a=max-message-size:499"));
+  ASSERT_NE(std::string::npos,
+            mAnswer->ToString().find("a=max-message-size:499"));
   ASSERT_EQ(std::string::npos, mOffer->ToString().find("a=sctp-port"));
   ASSERT_EQ(std::string::npos, mAnswer->ToString().find("a=sctp-port"));
 }
 
 TEST_F(JsepTrackTest, DataChannelDraft05AnswerWithDifferentPort)
 {
   mOffCodecs.values = MakeCodecs(false, false, false);
   mAnsCodecs.values = MakeCodecs(false, false, false);
 
   mOffCodecs.values.pop_back();
   mOffCodecs.values.push_back(
           new JsepApplicationCodecDescription(
             "webrtc-datachannel",
             256,
-            4555
+            4555,
+            10544
             ));
 
   InitTracks(SdpMediaSection::kApplication);
   InitSdp(SdpMediaSection::kApplication);
   OfferAnswer();
 
   CheckOffEncodingCount(1);
   CheckAnsEncodingCount(1);
 
   ASSERT_NE(std::string::npos,
             mOffer->ToString().find("a=sctpmap:4555 webrtc-datachannel 256"));
   ASSERT_NE(std::string::npos,
             mAnswer->ToString().find("a=sctpmap:5999 webrtc-datachannel 256"));
+  // Note: this is testing for a workaround, see bug 1335262 for details
+  ASSERT_NE(std::string::npos,
+            mOffer->ToString().find("a=max-message-size:10544"));
+  ASSERT_NE(std::string::npos,
+            mAnswer->ToString().find("a=max-message-size:499"));
   ASSERT_EQ(std::string::npos, mOffer->ToString().find("a=sctp-port"));
   ASSERT_EQ(std::string::npos, mAnswer->ToString().find("a=sctp-port"));
 }
 
 TEST_F(JsepTrackTest, DataChannelDraft21)
 {
   mOffCodecs.values = MakeCodecs(false, false, false);
   mAnsCodecs.values = MakeCodecs(false, false, false);
@@ -1164,16 +1176,18 @@ TEST_F(JsepTrackTest, DataChannelDraft21
       "0.0.0.0");
 
   OfferAnswer();
   CheckOffEncodingCount(1);
   CheckAnsEncodingCount(1);
 
   ASSERT_NE(std::string::npos, mOffer->ToString().find("a=sctp-port:5999"));
   ASSERT_NE(std::string::npos, mAnswer->ToString().find("a=sctp-port:5999"));
+  ASSERT_NE(std::string::npos, mOffer->ToString().find("a=max-message-size:499"));
+  ASSERT_NE(std::string::npos, mAnswer->ToString().find("a=max-message-size:499"));
   ASSERT_EQ(std::string::npos, mOffer->ToString().find("a=sctpmap"));
   ASSERT_EQ(std::string::npos, mAnswer->ToString().find("a=sctpmap"));
 }
 
 static JsepTrack::JsConstraints
 MakeConstraints(const std::string& rid, uint32_t maxBitrate)
 {
   JsepTrack::JsConstraints constraints;
--- a/media/webrtc/signaling/src/jsep/JsepCodecDescription.h
+++ b/media/webrtc/signaling/src/jsep/JsepCodecDescription.h
@@ -4,16 +4,17 @@
 
 #ifndef _JSEPCODECDESCRIPTION_H_
 #define _JSEPCODECDESCRIPTION_H_
 
 #include <string>
 #include "signaling/src/sdp/SdpMediaSection.h"
 #include "signaling/src/sdp/SdpHelper.h"
 #include "nsCRT.h"
+#include "mozilla/net/DataChannelProtocol.h"
 
 namespace mozilla {
 
 #define JSEP_CODEC_CLONE(T)                                                    \
   virtual JsepCodecDescription* Clone() const override                         \
   {                                                                            \
     return new T(*this);                                                       \
   }
@@ -750,21 +751,24 @@ class JsepVideoCodecDescription : public
 };
 
 class JsepApplicationCodecDescription : public JsepCodecDescription {
   // This is the new draft-21 implementation
  public:
   JsepApplicationCodecDescription(const std::string& name,
                                   uint16_t channels,
                                   uint16_t localPort,
+                                  uint32_t localMaxMessageSize,
                                   bool enabled = true)
       : JsepCodecDescription(mozilla::SdpMediaSection::kApplication, "",
                              name, 0, channels, enabled),
         mLocalPort(localPort),
-        mRemotePort(0)
+        mLocalMaxMessageSize(localMaxMessageSize),
+        mRemotePort(0),
+        mRemoteMaxMessageSize(0)
   {
   }
 
   JSEP_CODEC_CLONE(JsepApplicationCodecDescription)
 
   // Override, uses sctpport or sctpmap instead of rtpmap
   virtual bool
   Matches(const std::string& fmt,
@@ -792,44 +796,55 @@ class JsepApplicationCodecDescription : 
     return false;
   }
 
   virtual void
   AddToMediaSection(SdpMediaSection& msection) const override
   {
     if (mEnabled && msection.GetMediaType() == mType) {
       if (msection.GetFormats().empty()) {
-        msection.AddDataChannel(mName, mLocalPort, mChannels);
+        msection.AddDataChannel(mName, mLocalPort, mChannels,
+                                mLocalMaxMessageSize);
       }
 
       AddParametersToMSection(msection);
     }
   }
 
   bool
   Negotiate(const std::string& pt, const SdpMediaSection& remoteMsection) override
   {
     JsepCodecDescription::Negotiate(pt, remoteMsection);
 
+    uint32_t message_size = remoteMsection.GetMaxMessageSize();
+    if (message_size) {
+      mRemoteMaxMessageSize = message_size;
+    }
+
     int sctp_port = remoteMsection.GetSctpPort();
     if (sctp_port) {
       mRemotePort = sctp_port;
+      if (!message_size) {
+        mRemoteMaxMessageSize = WEBRTC_DATACHANELL_MAX_MESSAGE_SIZE_DEFAULT;
+      }
       return true;
     }
 
     const SdpSctpmapAttributeList::Sctpmap* sctp_map(
         remoteMsection.GetSctpmap());
     if (sctp_map) {
       mRemotePort = std::stoi(sctp_map->pt);
       return true;
     }
 
     return false;
   }
 
 
   uint16_t mLocalPort;
+  uint32_t mLocalMaxMessageSize;
   uint16_t mRemotePort;
+  uint32_t mRemoteMaxMessageSize;
 };
 
 } // namespace mozilla
 
 #endif
--- a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
+++ b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
@@ -2363,17 +2363,18 @@ JsepSessionImpl::SetupDefaultCodecs()
       "ulpfec", // codec name
       90000     // clock rate (match other video codecs)
       );
   mSupportedCodecs.values.push_back(ulpfec);
 
   mSupportedCodecs.values.push_back(new JsepApplicationCodecDescription(
       "webrtc-datachannel",
       WEBRTC_DATACHANNEL_STREAMS_DEFAULT,
-      5000
+      WEBRTC_DATACHANNEL_PORT_DEFAULT,
+      WEBRTC_DATACHANELL_MAX_MESSAGE_SIZE_DEFAULT
       ));
 
   // Update the redundant encodings for the RED codec with the supported
   // codecs.  Note: only uses the video codecs.
   red->UpdateRedundantEncodings(mSupportedCodecs.values);
 }
 
 void
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1079,42 +1079,45 @@ PeerConnectionImpl::ConfigureJsepSession
   mJsepSession->SortCodecs(comparator);
   return NS_OK;
 }
 
 // Data channels won't work without a window, so in order for the C++ unit
 // tests to work (it doesn't have a window available) we ifdef the following
 // two implementations.
 NS_IMETHODIMP
-PeerConnectionImpl::EnsureDataConnection(uint16_t aNumstreams)
+PeerConnectionImpl::EnsureDataConnection(uint16_t aLocalPort,
+                                         uint16_t aNumstreams,
+                                         uint32_t aMaxMessageSize)
 {
   PC_AUTO_ENTER_API_CALL(false);
 
   if (mDataConnection) {
     CSFLogDebug(logTag,"%s DataConnection already connected",__FUNCTION__);
     // Ignore the request to connect when already connected.  This entire
     // implementation is temporary.  Ignore aNumstreams as it's merely advisory
     // and we increase the number of streams dynamically as needed.
     return NS_OK;
   }
   mDataConnection = new DataChannelConnection(this);
-  if (!mDataConnection->Init(5000, aNumstreams, true)) {
+  if (!mDataConnection->Init(aLocalPort, aNumstreams, true)) {
     CSFLogError(logTag,"%s DataConnection Init Failed",__FUNCTION__);
     return NS_ERROR_FAILURE;
   }
   CSFLogDebug(logTag,"%s DataChannelConnection %p attached to %s",
               __FUNCTION__, (void*) mDataConnection.get(), mHandle.c_str());
   return NS_OK;
 }
 
 nsresult
 PeerConnectionImpl::GetDatachannelParameters(
     uint32_t* channels,
     uint16_t* localport,
     uint16_t* remoteport,
+    uint32_t* remotemaxmessagesize,
     uint16_t* level) const {
 
   auto trackPairs = mJsepSession->GetNegotiatedTrackPairs();
   for (auto& trackPair : trackPairs) {
     bool sendDataChannel =
       trackPair.mSending &&
       trackPair.mSending->GetMediaType() == SdpMediaSection::kApplication;
     bool recvDataChannel =
@@ -1157,29 +1160,32 @@ PeerConnectionImpl::GetDatachannelParame
           *channels = codec->mChannels;
         } else {
           *channels = WEBRTC_DATACHANNEL_STREAMS_DEFAULT;
         }
         *localport =
           static_cast<const JsepApplicationCodecDescription*>(codec)->mLocalPort;
         *remoteport =
           static_cast<const JsepApplicationCodecDescription*>(codec)->mRemotePort;
+        *remotemaxmessagesize = static_cast<const JsepApplicationCodecDescription*>
+          (codec)->mRemoteMaxMessageSize;
         if (trackPair.HasBundleLevel()) {
           *level = static_cast<uint16_t>(trackPair.BundleLevel());
         } else {
           *level = static_cast<uint16_t>(trackPair.mLevel);
         }
         return NS_OK;
       }
     }
   }
 
   *channels = 0;
   *localport = 0;
   *remoteport = 0;
+  *remotemaxmessagesize = 0;
   *level = 0;
   return NS_ERROR_FAILURE;
 }
 
 /* static */
 void
 PeerConnectionImpl::DeferredAddTrackToJsepSession(
     const std::string& pcHandle,
@@ -1229,29 +1235,31 @@ nsresult
 PeerConnectionImpl::InitializeDataChannel()
 {
   PC_AUTO_ENTER_API_CALL(false);
   CSFLogDebug(logTag, "%s", __FUNCTION__);
 
   uint32_t channels = 0;
   uint16_t localport = 0;
   uint16_t remoteport = 0;
+  uint32_t remotemaxmessagesize = 0;
   uint16_t level = 0;
-  nsresult rv = GetDatachannelParameters(&channels, &localport, &remoteport, &level);
+  nsresult rv = GetDatachannelParameters(&channels, &localport, &remoteport,
+                                         &remotemaxmessagesize, &level);
 
   if (NS_FAILED(rv)) {
     CSFLogDebug(logTag, "%s: We did not negotiate datachannel", __FUNCTION__);
     return NS_OK;
   }
 
   if (channels > MAX_NUM_STREAMS) {
     channels = MAX_NUM_STREAMS;
   }
 
-  rv = EnsureDataConnection(channels);
+  rv = EnsureDataConnection(localport, channels, remotemaxmessagesize);
   if (NS_SUCCEEDED(rv)) {
     // use the specified TransportFlow
     RefPtr<TransportFlow> flow = mMedia->GetTransportFlow(level, false).get();
     CSFLogDebug(logTag, "Transportflow[%u] = %p",
                         static_cast<unsigned>(level), flow.get());
     if (flow) {
       if (mDataConnection->ConnectViaTransportFlow(flow,
                                                    localport,
@@ -1297,17 +1305,19 @@ PeerConnectionImpl::CreateDataChannel(co
 {
   PC_AUTO_ENTER_API_CALL(false);
   MOZ_ASSERT(aRetval);
 
   RefPtr<DataChannel> dataChannel;
   DataChannelConnection::Type theType =
     static_cast<DataChannelConnection::Type>(aType);
 
-  nsresult rv = EnsureDataConnection(WEBRTC_DATACHANNEL_STREAMS_DEFAULT);
+  nsresult rv = EnsureDataConnection(WEBRTC_DATACHANNEL_PORT_DEFAULT,
+                                     WEBRTC_DATACHANNEL_STREAMS_DEFAULT,
+                                     WEBRTC_DATACHANELL_MAX_MESSAGE_SIZE_DEFAULT);
   if (NS_FAILED(rv)) {
     return rv;
   }
   dataChannel = mDataConnection->Open(
     NS_ConvertUTF16toUTF8(aLabel), NS_ConvertUTF16toUTF8(aProtocol), theType,
     ordered,
     aType == DataChannelConnection::PARTIAL_RELIABLE_REXMIT ? aMaxNum :
     (aType == DataChannelConnection::PARTIAL_RELIABLE_TIMED ? aMaxTime : 0),
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -641,17 +641,18 @@ public:
 private:
   virtual ~PeerConnectionImpl();
   PeerConnectionImpl(const PeerConnectionImpl&rhs);
   PeerConnectionImpl& operator=(PeerConnectionImpl);
   nsresult CalculateFingerprint(const std::string& algorithm,
                                 std::vector<uint8_t>* fingerprint) const;
   nsresult ConfigureJsepSessionCodecs();
 
-  NS_IMETHODIMP EnsureDataConnection(uint16_t aNumstreams);
+  NS_IMETHODIMP EnsureDataConnection(uint16_t aLocalPort, uint16_t aNumstreams,
+                                     uint32_t aMaxMessageSize);
 
   nsresult CloseInt();
   nsresult CheckApiState(bool assert_ice_ready) const;
   void CheckThread() const {
     MOZ_ASSERT(CheckThreadInt(), "Wrong thread");
   }
   bool CheckThreadInt() const {
     bool on;
@@ -674,16 +675,17 @@ private:
   void SendLocalIceCandidateToContent(uint16_t level,
                                       const std::string& mid,
                                       const std::string& candidate);
 
   nsresult GetDatachannelParameters(
       uint32_t* channels,
       uint16_t* localport,
       uint16_t* remoteport,
+      uint32_t* maxmessagesize,
       uint16_t* level) const;
 
   static void DeferredAddTrackToJsepSession(const std::string& pcHandle,
                                             SdpMediaSection::MediaType type,
                                             const std::string& streamId,
                                             const std::string& trackId);
 
   nsresult AddTrackToJsepSession(SdpMediaSection::MediaType type,
--- a/media/webrtc/signaling/src/sdp/SdpAttributeList.h
+++ b/media/webrtc/signaling/src/sdp/SdpAttributeList.h
@@ -59,17 +59,18 @@ public:
   virtual const SdpImageattrAttributeList& GetImageattr() const = 0;
   virtual const SdpSimulcastAttribute& GetSimulcast() const = 0;
   virtual const SdpMsidAttributeList& GetMsid() const = 0;
   virtual const SdpMsidSemanticAttributeList& GetMsidSemantic() const = 0;
   virtual const SdpRidAttributeList& GetRid() const = 0;
   virtual const SdpRtcpFbAttributeList& GetRtcpFb() const = 0;
   virtual const SdpRtpmapAttributeList& GetRtpmap() const = 0;
   virtual const SdpSctpmapAttributeList& GetSctpmap() const = 0;
-  virtual unsigned int GetSctpPort() const = 0;
+  virtual uint32_t GetSctpPort() const = 0;
+  virtual uint32_t GetMaxMessageSize() const = 0;
   virtual const SdpSsrcAttributeList& GetSsrc() const = 0;
   virtual const SdpSsrcGroupAttributeList& GetSsrcGroup() const = 0;
 
   // These attributes are effectively simple types, so we'll make life
   // easy by just returning their value.
   virtual const std::string& GetIcePwd() const = 0;
   virtual const std::string& GetIceUfrag() const = 0;
   virtual const std::string& GetIdentity() const = 0;
--- a/media/webrtc/signaling/src/sdp/SdpHelper.cpp
+++ b/media/webrtc/signaling/src/sdp/SdpHelper.cpp
@@ -163,17 +163,17 @@ SdpHelper::DisableMsection(Sdp* sdp, Sdp
   switch (mediaType) {
     case SdpMediaSection::kAudio:
       msection->AddCodec("0", "PCMU", 8000, 1);
       break;
     case SdpMediaSection::kVideo:
       msection->AddCodec("120", "VP8", 90000, 1);
       break;
     case SdpMediaSection::kApplication:
-      msection->AddDataChannel("rejected", 0, 0);
+      msection->AddDataChannel("rejected", 0, 0, 0);
       break;
     default:
       // We need to have something here to fit the grammar, this seems safe
       // and 19 is a reserved payload type which should not be used by anyone.
       msection->AddCodec("19", "reserved", 8000, 1);
   }
 }
 
--- a/media/webrtc/signaling/src/sdp/SdpMediaSection.cpp
+++ b/media/webrtc/signaling/src/sdp/SdpMediaSection.cpp
@@ -94,26 +94,36 @@ SdpMediaSection::GetSctpmap() const
   const SdpSctpmapAttributeList& sctpmap = attrs.GetSctpmap();
   if (!sctpmap.mSctpmaps.size()) {
     return nullptr;
   }
 
   return &sctpmap.GetFirstEntry();
 }
 
-int
+uint32_t
 SdpMediaSection::GetSctpPort() const
 {
   auto& attrs = GetAttributeList();
   if (!attrs.HasAttribute(SdpAttribute::kSctpPortAttribute)) {
     return 0;
   }
 
-  uint32_t val = attrs.GetSctpPort();
-  return val;
+  return attrs.GetSctpPort();
+}
+
+uint32_t
+SdpMediaSection::GetMaxMessageSize() const
+{
+  auto& attrs = GetAttributeList();
+  if (!attrs.HasAttribute(SdpAttribute::kMaxMessageSizeAttribute)) {
+    return 0;
+  }
+
+  return attrs.GetMaxMessageSize();
 }
 
 bool
 SdpMediaSection::HasRtcpFb(const std::string& pt,
                            SdpRtcpFbAttributeList::Type type,
                            const std::string& subType) const
 {
   const SdpAttributeList& attrs(GetAttributeList());
--- a/media/webrtc/signaling/src/sdp/SdpMediaSection.h
+++ b/media/webrtc/signaling/src/sdp/SdpMediaSection.h
@@ -91,18 +91,18 @@ public:
   virtual SdpDirectionAttribute GetDirectionAttribute() const = 0;
 
   virtual void Serialize(std::ostream&) const = 0;
 
   virtual void AddCodec(const std::string& pt, const std::string& name,
                         uint32_t clockrate, uint16_t channels) = 0;
   virtual void ClearCodecs() = 0;
 
-  virtual void AddDataChannel(const std::string& name,
-                              uint16_t port, uint16_t streams) = 0;
+  virtual void AddDataChannel(const std::string& name, uint16_t port,
+                              uint16_t streams, uint32_t message_size) = 0;
 
   size_t
   GetLevel() const
   {
     return mLevel;
   }
 
   inline bool
@@ -152,17 +152,18 @@ public:
     GetAttributeList().SetAttribute(new SdpDirectionAttribute(direction));
   }
 
   const SdpFmtpAttributeList::Parameters* FindFmtp(const std::string& pt) const;
   void SetFmtp(const SdpFmtpAttributeList::Fmtp& fmtp);
   void RemoveFmtp(const std::string& pt);
   const SdpRtpmapAttributeList::Rtpmap* FindRtpmap(const std::string& pt) const;
   const SdpSctpmapAttributeList::Sctpmap* GetSctpmap() const;
-  int GetSctpPort() const;
+  uint32_t GetSctpPort() const;
+  uint32_t GetMaxMessageSize() const;
   bool HasRtcpFb(const std::string& pt,
                  SdpRtcpFbAttributeList::Type type,
                  const std::string& subType) const;
   SdpRtcpFbAttributeList GetRtcpFbs() const;
   void SetRtcpFbs(const SdpRtcpFbAttributeList& rtcpfbs);
   bool HasFormat(const std::string& format) const
   {
     return std::find(GetFormats().begin(), GetFormats().end(), format) !=
--- a/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp
+++ b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp
@@ -1382,16 +1382,27 @@ SipccSdpAttributeList::GetSctpPort() con
   if (!HasAttribute(SdpAttribute::kSctpPortAttribute)) {
     MOZ_CRASH();
   }
 
   const SdpAttribute* attr = GetAttribute(SdpAttribute::kSctpPortAttribute);
   return static_cast<const SdpNumberAttribute*>(attr)->mValue;
 }
 
+uint32_t
+SipccSdpAttributeList::GetMaxMessageSize() const
+{
+  if (!HasAttribute(SdpAttribute::kMaxMessageSizeAttribute)) {
+    MOZ_CRASH();
+  }
+
+  const SdpAttribute* attr = GetAttribute(SdpAttribute::kMaxMessageSizeAttribute);
+  return static_cast<const SdpNumberAttribute*>(attr)->mValue;
+}
+
 const SdpSetupAttribute&
 SipccSdpAttributeList::GetSetup() const
 {
   if (!HasAttribute(SdpAttribute::kSetupAttribute)) {
     MOZ_CRASH();
   }
   const SdpAttribute* attr = GetAttribute(SdpAttribute::kSetupAttribute);
   return *static_cast<const SdpSetupAttribute*>(attr);
--- a/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h
+++ b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h
@@ -60,17 +60,18 @@ public:
   const SdpSimulcastAttribute& GetSimulcast() const override;
   virtual const SdpMsidAttributeList& GetMsid() const override;
   virtual const SdpMsidSemanticAttributeList& GetMsidSemantic()
     const override;
   const SdpRidAttributeList& GetRid() const override;
   virtual const SdpRtcpFbAttributeList& GetRtcpFb() const override;
   virtual const SdpRtpmapAttributeList& GetRtpmap() const override;
   virtual const SdpSctpmapAttributeList& GetSctpmap() const override;
-  virtual unsigned int GetSctpPort() const override;
+  virtual uint32_t GetSctpPort() const override;
+  virtual uint32_t GetMaxMessageSize() const override;
 
   // These attributes are effectively simple types, so we'll make life
   // easy by just returning their value.
   virtual const std::string& GetIcePwd() const override;
   virtual const std::string& GetIceUfrag() const override;
   virtual const std::string& GetIdentity() const override;
   virtual const std::string& GetLabel() const override;
   virtual unsigned int GetMaxptime() const override;
--- a/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.cpp
+++ b/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.cpp
@@ -393,34 +393,43 @@ SipccSdpMediaSection::ClearCodecs()
   mAttributeList.RemoveAttribute(SdpAttribute::kRtpmapAttribute);
   mAttributeList.RemoveAttribute(SdpAttribute::kFmtpAttribute);
   mAttributeList.RemoveAttribute(SdpAttribute::kSctpmapAttribute);
   mAttributeList.RemoveAttribute(SdpAttribute::kRtcpFbAttribute);
 }
 
 void
 SipccSdpMediaSection::AddDataChannel(const std::string& name, uint16_t port,
-                                     uint16_t streams)
+                                     uint16_t streams, uint32_t message_size)
 {
   // Only one allowed, for now. This may change as the specs (and deployments)
   // evolve.
   mFormats.clear();
   if ((mProtocol == kUdpDtlsSctp) ||
       (mProtocol == kTcpDtlsSctp)) {
     // new data channel format according to draft 21
     mFormats.push_back(name);
     mAttributeList.SetAttribute(new SdpNumberAttribute(
           SdpAttribute::kSctpPortAttribute, port));
+    if (message_size) {
+      mAttributeList.SetAttribute(new SdpNumberAttribute(
+            SdpAttribute::kMaxMessageSizeAttribute, message_size));
+    }
   } else {
     // old data channels format according to draft 05
     std::string port_str = std::to_string(port);
     mFormats.push_back(port_str);
     SdpSctpmapAttributeList* sctpmap = new SdpSctpmapAttributeList();
     sctpmap->PushEntry(port_str, name, streams);
     mAttributeList.SetAttribute(sctpmap);
+    if (message_size) {
+      // This is a workaround to allow detecting Firefox's w/o EOR support
+      mAttributeList.SetAttribute(new SdpNumberAttribute(
+            SdpAttribute::kMaxMessageSizeAttribute, message_size));
+    }
   }
 }
 
 void
 SipccSdpMediaSection::Serialize(std::ostream& os) const
 {
   os << "m=" << mMediaType << " " << mPort;
   if (mPortCount) {
--- a/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.h
+++ b/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.h
@@ -56,18 +56,18 @@ public:
   virtual const SdpAttributeList& GetAttributeList() const override;
   virtual SdpAttributeList& GetAttributeList() override;
   virtual SdpDirectionAttribute GetDirectionAttribute() const override;
 
   virtual void AddCodec(const std::string& pt, const std::string& name,
                         uint32_t clockrate, uint16_t channels) override;
   virtual void ClearCodecs() override;
 
-  virtual void AddDataChannel(const std::string& name,
-                              uint16_t port, uint16_t streams) override;
+  virtual void AddDataChannel(const std::string& name, uint16_t port,
+                              uint16_t streams, uint32_t message_size) override;
 
   virtual void Serialize(std::ostream&) const override;
 
 private:
   SipccSdpMediaSection(size_t level, const SipccSdpAttributeList* sessionLevel)
       : SdpMediaSection(level), mAttributeList(sessionLevel)
   {
   }
--- a/netwerk/sctp/datachannel/DataChannelProtocol.h
+++ b/netwerk/sctp/datachannel/DataChannelProtocol.h
@@ -11,18 +11,19 @@
 #define SCTP_PACKED __attribute__((packed))
 #elif defined(_MSC_VER)
 #pragma pack (push, 1)
 #define SCTP_PACKED
 #else
 #error "Unsupported compiler"
 #endif
 
-// Duplicated in fsm.def
-#define WEBRTC_DATACHANNEL_STREAMS_DEFAULT 256
+#define WEBRTC_DATACHANNEL_STREAMS_DEFAULT          256
+#define WEBRTC_DATACHANNEL_PORT_DEFAULT             5000
+#define WEBRTC_DATACHANELL_MAX_MESSAGE_SIZE_DEFAULT 65536
 
 #define DATA_CHANNEL_PPID_CONTROL        50
 #define DATA_CHANNEL_PPID_BINARY         52
 #define DATA_CHANNEL_PPID_BINARY_LAST    53
 #define DATA_CHANNEL_PPID_DOMSTRING      54
 #define DATA_CHANNEL_PPID_DOMSTRING_LAST 51
 
 #define DATA_CHANNEL_MAX_BINARY_FRAGMENT 0x4000