Bug 1570158 - Add proxy information to candidates table in about:webrtc r=bwc,baku
authorRyan Alderete <ralderete@mozilla.com>
Wed, 21 Aug 2019 10:04:45 +0000
changeset 489238 8f803211fda5ad9694932a62e6ac4b3e417f70d0
parent 489237 d2326f350a1541624dcf8e46169a6363fa311adc
child 489239 4d3947b83ccddee2ecef1bb94d3b81b81e8cc8cd
push id93212
push userdluca@mozilla.com
push dateWed, 21 Aug 2019 16:11:12 +0000
treeherderautoland@8f803211fda5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbwc, baku
bugs1570158
milestone70.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 1570158 - Add proxy information to candidates table in about:webrtc r=bwc,baku This adds a field to about:webrtc which indicates whether an associated candidate is behind a proxy or not. Differential Revision: https://phabricator.services.mozilla.com/D39974
dom/media/tests/mochitest/test_peerConnection_stats.html
dom/media/webrtc/WebrtcGlobal.h
dom/webidl/RTCStatsReport.webidl
media/mtransport/nr_socket_proxy.h
media/mtransport/nr_socket_prsock.h
media/mtransport/nricectx.cpp
media/mtransport/nricemediastream.cpp
media/mtransport/nricemediastream.h
media/mtransport/test/dummysocket.h
media/mtransport/test_nr_socket.cpp
media/mtransport/test_nr_socket.h
media/mtransport/third_party/nICEr/src/net/transport_addr.h
media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
toolkit/content/aboutwebrtc/aboutWebrtc.js
--- a/dom/media/tests/mochitest/test_peerConnection_stats.html
+++ b/dom/media/tests/mochitest/test_peerConnection_stats.html
@@ -211,16 +211,17 @@ const statsExpectedByType = {
       "address",
       "protocol",
       "port",
       "candidateType",
       "priority",
     ],
     optional: [
       "relayProtocol",
+      "proxied",
     ],
     unimplemented: [
       "networkType",
       "url",
       "transportId"
     ],
     deprecated: [
       "candidateId",
@@ -239,16 +240,17 @@ const statsExpectedByType = {
       "address",
       "protocol",
       "port",
       "candidateType",
       "priority",
     ],
     optional: [
       "relayProtocol",
+      "proxied",
     ],
     unimplemented: [
       "networkType",
       "url",
       "transportId",
     ],
     deprecated: [
       "candidateId",
@@ -770,16 +772,22 @@ var pedanticChecks = report => {
       if (stat.type == "local-candidate" && stat.candidateType == "relay") {
         ok(stat.relayProtocol,
           `relay ${stat.type} has relayProtocol. value=${stat.relayProtocol}`);
       } else {
         is(stat.relayProtocol, undefined,
           `relayProtocol is undefined for candidates that are not relay and ` +
           `local. value=${stat.relayProtocol}`);
       }
+
+      // proxied
+      if (stat.proxied) {
+        ok(stat.proxied == "proxied" || stat.proxied == "non-proxied",
+           `${stat.type} has proxied. value=${stat.proxied}`);
+      }
     }
 
     //
     // Ensure everything was tested
     //
     [...expectations.expected, ...expectations.optional].forEach(field => {
       ok(Object.keys(tested).includes(field), stat.type + "." + field
         + " was tested.");
--- a/dom/media/webrtc/WebrtcGlobal.h
+++ b/dom/media/webrtc/WebrtcGlobal.h
@@ -209,28 +209,30 @@ struct ParamTraits<mozilla::dom::RTCIceC
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mCandidateType);
     WriteParam(aMsg, aParam.mPriority);
     WriteParam(aMsg, aParam.mTransportId);
     WriteParam(aMsg, aParam.mAddress);
     WriteParam(aMsg, aParam.mRelayProtocol);
     WriteParam(aMsg, aParam.mPort);
     WriteParam(aMsg, aParam.mProtocol);
+    WriteParam(aMsg, aParam.mProxied);
     WriteRTCStats(aMsg, aParam);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    paramType* aResult) {
     if (!ReadParam(aMsg, aIter, &(aResult->mCandidateType)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPriority)) ||
         !ReadParam(aMsg, aIter, &(aResult->mTransportId)) ||
         !ReadParam(aMsg, aIter, &(aResult->mAddress)) ||
         !ReadParam(aMsg, aIter, &(aResult->mRelayProtocol)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPort)) ||
         !ReadParam(aMsg, aIter, &(aResult->mProtocol)) ||
+        !ReadParam(aMsg, aIter, &(aResult->mProxied)) ||
         !ReadRTCStats(aMsg, aIter, aResult)) {
       return false;
     }
 
     return true;
   }
 };
 
--- a/dom/webidl/RTCStatsReport.webidl
+++ b/dom/webidl/RTCStatsReport.webidl
@@ -131,16 +131,18 @@ dictionary RTCIceCandidateStats : RTCSta
   DOMString protocol;
   RTCIceCandidateType candidateType;
   long priority;
   DOMString relayProtocol;
   // Because we use this internally but don't support RTCIceCandidateStats,
   // we need to keep the field as ChromeOnly. Bug 1225723
   [ChromeOnly]
   DOMString transportId;
+  [ChromeOnly]
+  DOMString proxied;
 };
 
 // This is the internal representation of the report in this implementation
 // to be received from c++
 
 dictionary RTCStatsReportInternal {
   DOMString                                 pcid = "";
   sequence<RTCInboundRtpStreamStats>        inboundRtpStreamStats;
--- a/media/mtransport/nr_socket_proxy.h
+++ b/media/mtransport/nr_socket_proxy.h
@@ -81,16 +81,18 @@ class NrSocketProxy : public NrSocketBas
   int getaddr(nr_transport_addr* aAddr) override;
   int sendto(const void* aBuffer, size_t aCount, int aFlags,
              nr_transport_addr* aAddr) override;
   int recvfrom(void* aBuffer, size_t aCount, size_t* aRead, int aFlags,
                nr_transport_addr* aAddr) override;
   int listen(int aBacklog) override;
   int accept(nr_transport_addr* aAddr, nr_socket** aSocket) override;
 
+  bool IsProxied() const override { return true; }
+
   // WebrtcProxyChannelCallback
   void OnClose(nsresult aReason) override;
   void OnConnected() override;
   void OnRead(nsTArray<uint8_t>&& aReadData) override;
 
   size_t CountUnreadBytes() const;
 
   // for gtests
--- a/media/mtransport/nr_socket_prsock.h
+++ b/media/mtransport/nr_socket_prsock.h
@@ -122,16 +122,18 @@ class NrSocketBase {
   virtual int getaddr(nr_transport_addr* addrp) = 0;
   virtual void close() = 0;
   virtual int connect(nr_transport_addr* addr) = 0;
   virtual int write(const void* msg, size_t len, size_t* written) = 0;
   virtual int read(void* buf, size_t maxlen, size_t* len) = 0;
   virtual int listen(int backlog) = 0;
   virtual int accept(nr_transport_addr* addrp, nr_socket** sockp) = 0;
 
+  virtual bool IsProxied() const = 0;
+
   // Implementations of the async_event APIs
   virtual int async_wait(int how, NR_async_cb cb, void* cb_arg, char* function,
                          int line);
   virtual int cancel(int how);
 
   // nsISupport reference counted interface
   NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
 
@@ -184,16 +186,18 @@ class NrSocket : public NrSocketBase, pu
   virtual int getaddr(nr_transport_addr* addrp) override;
   virtual void close() override;
   virtual int connect(nr_transport_addr* addr) override;
   virtual int write(const void* msg, size_t len, size_t* written) override;
   virtual int read(void* buf, size_t maxlen, size_t* len) override;
   virtual int listen(int backlog) override;
   virtual int accept(nr_transport_addr* addrp, nr_socket** sockp) override;
 
+  virtual bool IsProxied() const override { return false; }
+
  protected:
   virtual ~NrSocket() {
     if (fd_) PR_Close(fd_);
   }
 
   DISALLOW_COPY_ASSIGN(NrSocket);
 
   PRFileDesc* fd_;
@@ -262,16 +266,18 @@ class NrUdpSocketIpc : public NrSocketIp
   virtual int getaddr(nr_transport_addr* addrp) override;
   virtual void close() override;
   virtual int connect(nr_transport_addr* addr) override;
   virtual int write(const void* msg, size_t len, size_t* written) override;
   virtual int read(void* buf, size_t maxlen, size_t* len) override;
   virtual int listen(int backlog) override;
   virtual int accept(nr_transport_addr* addrp, nr_socket** sockp) override;
 
+  virtual bool IsProxied() const override { return false; }
+
  private:
   virtual ~NrUdpSocketIpc();
 
   DISALLOW_COPY_ASSIGN(NrUdpSocketIpc);
 
   nsresult SetAddress();  // Set the local address from parent info.
 
   // Main or private thread executors of the NrSocketBase APIs
@@ -348,16 +354,18 @@ class NrTcpSocketIpc : public NrSocketIp
   virtual int getaddr(nr_transport_addr* addrp) override;
   virtual void close() override;
   virtual int connect(nr_transport_addr* addr) override;
   virtual int write(const void* msg, size_t len, size_t* written) override;
   virtual int read(void* buf, size_t maxlen, size_t* len) override;
   virtual int listen(int backlog) override;
   virtual int accept(nr_transport_addr* addrp, nr_socket** sockp) override;
 
+  virtual bool IsProxied() const override { return false; }
+
  private:
   class TcpSocketReadyRunner;
   DISALLOW_COPY_ASSIGN(NrTcpSocketIpc);
   virtual ~NrTcpSocketIpc();
 
   // Main thread executors of the NrSocketBase APIs
   void connect_i(const nsACString& remote_addr, uint16_t remote_port,
                  const nsACString& local_addr, uint16_t local_port,
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -1061,16 +1061,20 @@ int nr_socket_local_create(void* obj, nr
       ABORT(R_FAILED);
     }
   }
 
   r = NrSocketBase::CreateSocket(addr, &sock, config);
   if (r) {
     ABORT(r);
   }
+  // TODO(bug 1569183): This will start out false, and may become true once the
+  // socket class figures out whether a proxy needs to be used (this may be as
+  // late as when it establishes a connection).
+  addr->is_proxied = sock->IsProxied();
 
   r = nr_socket_create_int(static_cast<void*>(sock), sock->vtbl(), sockp);
   if (r) ABORT(r);
 
   _status = 0;
 
   {
     // We will release this reference in destroy(), not exactly the normal
--- a/media/mtransport/nricemediastream.cpp
+++ b/media/mtransport/nricemediastream.cpp
@@ -118,16 +118,18 @@ static bool ToNrIceCandidate(const nr_ic
     out->mdns_addr = cand->mdns_addr;
   }
 
   if (cand->isock) {
     nr_transport_addr addr;
     r = nr_socket_getaddr(cand->isock->sock, &addr);
     if (r) return false;
 
+    out->is_proxied = addr.is_proxied;
+
     if (!ToNrIceAddr(addr, &out->local_addr)) return false;
   }
 
   NrIceCandidate::Type type;
 
   switch (cand->type) {
     case HOST:
       type = NrIceCandidate::ICE_HOST;
--- a/media/mtransport/nricemediastream.h
+++ b/media/mtransport/nricemediastream.h
@@ -82,16 +82,17 @@ struct NrIceCandidate {
   NrIceAddr local_addr;
   std::string mdns_addr;
   Type type;
   TcpType tcp_type;
   std::string codeword;
   std::string label;
   bool trickled;
   uint32_t priority;
+  bool is_proxied = false;
 };
 
 struct NrIceCandidatePair {
   enum State {
     STATE_FROZEN,
     STATE_WAITING,
     STATE_IN_PROGRESS,
     STATE_FAILED,
--- a/media/mtransport/test/dummysocket.h
+++ b/media/mtransport/test/dummysocket.h
@@ -86,16 +86,18 @@ class DummySocket : public NrSocketBase 
   }
 
   virtual int listen(int backlog) override { return 0; }
 
   virtual int accept(nr_transport_addr* addrp, nr_socket** sockp) override {
     return 0;
   }
 
+  virtual bool IsProxied() const override { return false; }
+
   virtual int write(const void* msg, size_t len, size_t* written) override {
     size_t to_write = std::min(len, writable_);
 
     if (to_write) {
       UniquePtr<MediaPacket> msgbuf(new MediaPacket);
       msgbuf->Copy(static_cast<const uint8_t*>(msg), to_write);
       write_buffer_ = merge(std::move(write_buffer_), std::move(msgbuf));
     }
--- a/media/mtransport/test_nr_socket.cpp
+++ b/media/mtransport/test_nr_socket.cpp
@@ -277,16 +277,27 @@ int TestNrSocket::accept(nr_transport_ad
   if (nat_->enabled_ && !nat_->is_an_internal_tuple(*addrp)) {
     nr_socket_destroy(sockp);
     return R_IO_ERROR;
   }
 
   return 0;
 }
 
+bool TestNrSocket::IsProxied() const {
+  if (internal_socket_->my_addr().protocol == IPPROTO_UDP ||
+      port_mappings_.empty()) {
+    // UDP and the no-nat case
+    return internal_socket_->IsProxied();
+  }
+  // This is TCP only
+  MOZ_ASSERT(port_mappings_.size() == 1);
+  return port_mappings_.front()->external_socket_->IsProxied();
+}
+
 void TestNrSocket::process_delayed_cb(NR_SOCKET s, int how, void* cb_arg) {
   DeferredPacket* op = static_cast<DeferredPacket*>(cb_arg);
   op->socket_->timer_handle_ = nullptr;
   r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s sending delayed STUN response",
         op->internal_socket_->my_addr().as_string);
   op->internal_socket_->sendto(op->buffer_.data(), op->buffer_.len(),
                                op->flags_, &op->to_);
 
--- a/media/mtransport/test_nr_socket.h
+++ b/media/mtransport/test_nr_socket.h
@@ -220,16 +220,17 @@ class TestNrSocket : public NrSocketBase
   int getaddr(nr_transport_addr* addrp) override;
   void close() override;
   int connect(nr_transport_addr* addr) override;
   int write(const void* msg, size_t len, size_t* written) override;
   int read(void* buf, size_t maxlen, size_t* len) override;
 
   int listen(int backlog) override;
   int accept(nr_transport_addr* addrp, nr_socket** sockp) override;
+  bool IsProxied() const override;
   int async_wait(int how, NR_async_cb cb, void* cb_arg, char* function,
                  int line) override;
   int cancel(int how) override;
 
   // Need override since this is virtual in NrSocketBase
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNrSocket, override)
 
  private:
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.h
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.h
@@ -30,16 +30,17 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 
 
 #ifndef _transport_addr_h
 #define _transport_addr_h
 
+#include <stdbool.h>
 #include <sys/types.h>
 #ifdef WIN32
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #else
 #include <sys/socket.h>
 #include <netinet/in.h>
 #endif
@@ -64,16 +65,17 @@ typedef struct nr_transport_addr_ {
     struct sockaddr_in addr4;
     struct sockaddr_in6 addr6;
   } u;
   char ifname[MAXIFNAME];
   /* A string version.
      56 = 5 ("IP6:[") + 39 (ipv6 address) + 2 ("]:") + 5 (port) + 4 (/UDP) + 1 (null) */
   char as_string[56];
   char tls_host[256];
+  bool is_proxied;
 } nr_transport_addr;
 
 typedef struct nr_transport_addr_mask_ {
   UINT4 addr;
   UINT4 mask;
 } nr_transport_addr_mask;
 
 int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr);
--- a/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
@@ -1148,16 +1148,18 @@ static void ToRTCIceCandidateStats(
     cand.mProtocol.Construct(
         NS_ConvertASCIItoUTF16(candidate.cand_addr.transport.c_str()));
     if (candidateType == dom::RTCStatsType::Local_candidate &&
         dom::RTCIceCandidateType(candidate.type) ==
             dom::RTCIceCandidateType::Relay) {
       cand.mRelayProtocol.Construct(
           NS_ConvertASCIItoUTF16(candidate.local_addr.transport.c_str()));
     }
+    cand.mProxied.Construct(NS_ConvertASCIItoUTF16(
+        candidate.is_proxied ? "proxied" : "non-proxied"));
     report->mIceCandidateStats.Value().AppendElement(cand, fallible);
     if (candidate.trickled) {
       report->mTrickledIceCandidateStats.Value().AppendElement(cand, fallible);
     }
   }
 }
 
 void MediaTransportHandlerSTS::GetIceStats(
--- a/toolkit/content/aboutwebrtc/aboutWebrtc.js
+++ b/toolkit/content/aboutwebrtc/aboutWebrtc.js
@@ -906,17 +906,22 @@ ICEStats.prototype = {
     }
 
     var type = c.candidateType;
 
     if (c.type == "local-candidate" && c.candidateType == "relayed") {
       type = `${c.candidateType}-${c.relayProtocol}`;
     }
 
-    return `${c.address}:${c.port}/${c.protocol}(${type})`;
+    var proxied = "";
+    if (c.type == "local-candidate") {
+      proxied = `[${c.proxied}]`;
+    }
+
+    return `${c.address}:${c.port}/${c.protocol}(${type}) ${proxied}`;
   },
 };
 
 function FoldableSection(parentElement, options = {}) {
   this._foldableElement = document.createElement("div");
   if (parentElement) {
     let sectionCtrl = renderElement("div", null, {
       className: "section-ctrl no-print",