Bug 1335262: read and emit datachannel max-message-size. r?jesup draft
authorNils Ohlmeier [:drno] <drno@ohlmeier.org>
Wed, 31 May 2017 20:58:53 -0700
changeset 588312 ff8289341fae55324442c145d3206d11fefe1ebf
parent 587256 94906c37940c6b1c371dc7c22ed2098face96d8b
child 631541 51a4c11f0b01e6714f8b28e08644a6e00634f3dc
push id61998
push userdrno@ohlmeier.org
push dateFri, 02 Jun 2017 17:13:46 +0000
reviewersjesup
bugs1335262
milestone55.0a1
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
@@ -2357,17 +2357,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