tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nr_socket_prsock.cpp (49259B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 /*
      7 Modified version of nr_socket_local, adapted for NSPR
      8 */
      9 
     10 /* This Source Code Form is subject to the terms of the Mozilla Public
     11 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     12 * You can obtain one at http://mozilla.org/MPL/2.0/. */
     13 
     14 /*
     15 Original code from nICEr and nrappkit.
     16 
     17 nICEr copyright:
     18 
     19 Copyright (c) 2007, Adobe Systems, Incorporated
     20 All rights reserved.
     21 
     22 Redistribution and use in source and binary forms, with or without
     23 modification, are permitted provided that the following conditions are
     24 met:
     25 
     26 * Redistributions of source code must retain the above copyright
     27  notice, this list of conditions and the following disclaimer.
     28 
     29 * Redistributions in binary form must reproduce the above copyright
     30  notice, this list of conditions and the following disclaimer in the
     31  documentation and/or other materials provided with the distribution.
     32 
     33 * Neither the name of Adobe Systems, Network Resonance nor the names of its
     34  contributors may be used to endorse or promote products derived from
     35  this software without specific prior written permission.
     36 
     37 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     38 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     39 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     40 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     41 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     42 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     43 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     45 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     46 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     47 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     48 
     49 
     50 nrappkit copyright:
     51 
     52   Copyright (C) 2001-2003, Network Resonance, Inc.
     53   Copyright (C) 2006, Network Resonance, Inc.
     54   All Rights Reserved
     55 
     56   Redistribution and use in source and binary forms, with or without
     57   modification, are permitted provided that the following conditions
     58   are met:
     59 
     60   1. Redistributions of source code must retain the above copyright
     61      notice, this list of conditions and the following disclaimer.
     62   2. Redistributions in binary form must reproduce the above copyright
     63      notice, this list of conditions and the following disclaimer in the
     64      documentation and/or other materials provided with the distribution.
     65   3. Neither the name of Network Resonance, Inc. nor the name of any
     66      contributors to this software may be used to endorse or promote
     67      products derived from this software without specific prior written
     68      permission.
     69 
     70   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
     71   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     72   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     73   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     74   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     75   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     76   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     77   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     78   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     79   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     80   POSSIBILITY OF SUCH DAMAGE.
     81 
     82 
     83   ekr@rtfm.com  Thu Dec 20 20:14:49 2001
     84 */
     85 
     86 #include <assert.h>
     87 #include <csi_platform.h>
     88 #include <errno.h>
     89 #include <stdio.h>
     90 #include <string.h>
     91 #include <sys/types.h>
     92 
     93 #include "mozilla/ProfilerBandwidthCounter.h"
     94 #include "mozilla/SyncRunnable.h"
     95 #include "mozilla/net/DNS.h"
     96 #include "nsASocketHandler.h"
     97 #include "nsCOMPtr.h"
     98 #include "nsComponentManagerUtils.h"
     99 #include "nsDebug.h"
    100 #include "nsISocketFilter.h"
    101 #include "nsISocketTransportService.h"
    102 #include "nsISupportsImpl.h"
    103 #include "nsNetCID.h"
    104 #include "nsNetUtil.h"
    105 #include "nsServiceManagerUtils.h"
    106 #include "nsTArray.h"
    107 #include "nsXPCOM.h"
    108 #include "nsXULAppAPI.h"
    109 #include "nspr.h"
    110 #include "prerror.h"
    111 #include "prio.h"
    112 #include "prnetdb.h"
    113 #include "runnable_utils.h"
    114 
    115 #if defined(MOZILLA_INTERNAL_API)
    116 // csi_platform.h deep in nrappkit defines LOG_INFO and LOG_WARNING
    117 #  ifdef LOG_INFO
    118 #    define LOG_TEMP_INFO LOG_INFO
    119 #    undef LOG_INFO
    120 #  endif
    121 #  ifdef LOG_WARNING
    122 #    define LOG_TEMP_WARNING LOG_WARNING
    123 #    undef LOG_WARNING
    124 #  endif
    125 #  if defined(LOG_DEBUG)
    126 #    define LOG_TEMP_DEBUG LOG_DEBUG
    127 #    undef LOG_DEBUG
    128 #  endif
    129 #  undef strlcpy
    130 
    131 #  include "mozilla/dom/network/UDPSocketChild.h"
    132 
    133 #  ifdef LOG_TEMP_INFO
    134 #    define LOG_INFO LOG_TEMP_INFO
    135 #  endif
    136 #  ifdef LOG_TEMP_WARNING
    137 #    define LOG_WARNING LOG_TEMP_WARNING
    138 #  endif
    139 
    140 #  ifdef LOG_TEMP_DEBUG
    141 #    define LOG_DEBUG LOG_TEMP_DEBUG
    142 #  endif
    143 #  ifdef XP_WIN
    144 #    ifdef LOG_DEBUG
    145 #      undef LOG_DEBUG
    146 #    endif
    147 // cloned from csi_platform.h.  Win32 doesn't like how we hide symbols
    148 #    define LOG_DEBUG 7
    149 #  endif
    150 #endif
    151 
    152 extern "C" {
    153 #include "async_wait.h"
    154 #include "nr_api.h"
    155 #include "nr_socket.h"
    156 #include "nr_socket_local.h"
    157 #include "stun_hint.h"
    158 }
    159 #include "nr_socket_proxy_config.h"
    160 #include "nr_socket_prsock.h"
    161 #include "nr_socket_tcp.h"
    162 #include "simpletokenbucket.h"
    163 #include "test_nr_socket.h"
    164 
    165 // Implement the nsISupports ref counting
    166 namespace mozilla {
    167 
    168 #if defined(MOZILLA_INTERNAL_API)
    169 class SingletonThreadHolder final {
    170 private:
    171  ~SingletonThreadHolder() {
    172    r_log(LOG_GENERIC, LOG_DEBUG, "Deleting SingletonThreadHolder");
    173    if (mThread) {
    174      // Likely a connection is somehow being held in CC or GC
    175      NS_WARNING(
    176          "SingletonThreads should be Released and shut down before exit!");
    177      mThread->Shutdown();
    178      mThread = nullptr;
    179    }
    180  }
    181 
    182  DISALLOW_COPY_ASSIGN(SingletonThreadHolder);
    183 
    184 public:
    185  // Must be threadsafe for StaticRefPtr/ClearOnShutdown
    186  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SingletonThreadHolder)
    187 
    188  explicit SingletonThreadHolder(const nsACString& aName) : mName(aName) {
    189    mParentThread = NS_GetCurrentThread();
    190  }
    191 
    192  nsIThread* GetThread() { return mThread; }
    193 
    194  /*
    195   * Keep track of how many instances are using a SingletonThreadHolder.
    196   * When no one is using it, shut it down
    197   */
    198  void AddUse() {
    199    MOZ_ASSERT(mParentThread == NS_GetCurrentThread());
    200    MOZ_ASSERT(int32_t(mUseCount) >= 0, "illegal refcnt");
    201    nsrefcnt count = ++mUseCount;
    202    if (count == 1) {
    203      // idle -> in-use
    204      nsresult rv = NS_NewNamedThread(mName, getter_AddRefs(mThread));
    205      MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv) && mThread,
    206                         "Should successfully create mtransport I/O thread");
    207      r_log(LOG_GENERIC, LOG_DEBUG, "Created wrapped SingletonThread %p",
    208            mThread.get());
    209    }
    210    r_log(LOG_GENERIC, LOG_DEBUG, "AddUse_i: %lu", (unsigned long)count);
    211  }
    212 
    213  void ReleaseUse() {
    214    MOZ_ASSERT(mParentThread == NS_GetCurrentThread());
    215    nsrefcnt count = --mUseCount;
    216    MOZ_ASSERT(int32_t(mUseCount) >= 0, "illegal refcnt");
    217    if (mThread && count == 0) {
    218      // in-use -> idle -- no one forcing it to remain instantiated
    219      r_log(LOG_GENERIC, LOG_DEBUG, "Shutting down wrapped SingletonThread %p",
    220            mThread.get());
    221      mThread->AsyncShutdown();
    222      mThread = nullptr;
    223      // It'd be nice to use a timer instead...  But be careful of
    224      // xpcom-shutdown-threads in that case
    225    }
    226    r_log(LOG_GENERIC, LOG_DEBUG, "ReleaseUse_i: %lu", (unsigned long)count);
    227  }
    228 
    229 private:
    230  nsCString mName;
    231  nsAutoRefCnt mUseCount;
    232  nsCOMPtr<nsIThread> mParentThread;
    233  nsCOMPtr<nsIThread> mThread;
    234 };
    235 
    236 static StaticRefPtr<SingletonThreadHolder> sThread;
    237 
    238 static void ClearSingletonOnShutdown() {
    239  // We expect everybody to have done ReleaseUse() at the latest during
    240  // xpcom-shutdown-threads. So we need to live longer than that.
    241  ClearOnShutdown(&sThread, ShutdownPhase::XPCOMShutdownFinal);
    242 }
    243 #endif
    244 
    245 static nsIThread* GetIOThreadAndAddUse_s() {
    246  // Always runs on STS thread!
    247 #if defined(MOZILLA_INTERNAL_API)
    248  // We need to safely release this on shutdown to avoid leaks
    249  if (!sThread) {
    250    sThread = new SingletonThreadHolder("mtransport"_ns);
    251    NS_DispatchToMainThread(mozilla::WrapRunnableNM(&ClearSingletonOnShutdown));
    252  }
    253  // Mark that we're using the shared thread and need it to stick around
    254  sThread->AddUse();
    255  return sThread->GetThread();
    256 #else
    257  static nsCOMPtr<nsIThread> sThread;
    258  if (!sThread) {
    259    (void)NS_NewNamedThread("mtransport", getter_AddRefs(sThread));
    260  }
    261  return sThread;
    262 #endif
    263 }
    264 
    265 NrSocketIpc::NrSocketIpc(nsIEventTarget* aThread) : io_thread_(aThread) {}
    266 
    267 static TimeStamp nr_socket_short_term_violation_time;
    268 static TimeStamp nr_socket_long_term_violation_time;
    269 
    270 TimeStamp NrSocketBase::short_term_violation_time() {
    271  return nr_socket_short_term_violation_time;
    272 }
    273 
    274 TimeStamp NrSocketBase::long_term_violation_time() {
    275  return nr_socket_long_term_violation_time;
    276 }
    277 
    278 // NrSocketBase implementation
    279 // async_event APIs
    280 int NrSocketBase::async_wait(int how, NR_async_cb cb, void* cb_arg,
    281                             char* function, int line) {
    282  uint16_t flag;
    283 
    284  switch (how) {
    285    case NR_ASYNC_WAIT_READ:
    286      flag = PR_POLL_READ;
    287      break;
    288    case NR_ASYNC_WAIT_WRITE:
    289      flag = PR_POLL_WRITE;
    290      break;
    291    default:
    292      return R_BAD_ARGS;
    293  }
    294 
    295  cbs_[how] = cb;
    296  cb_args_[how] = cb_arg;
    297  poll_flags_ |= flag;
    298 
    299  return 0;
    300 }
    301 
    302 int NrSocketBase::cancel(int how) {
    303  uint16_t flag;
    304 
    305  switch (how) {
    306    case NR_ASYNC_WAIT_READ:
    307      flag = PR_POLL_READ;
    308      break;
    309    case NR_ASYNC_WAIT_WRITE:
    310      flag = PR_POLL_WRITE;
    311      break;
    312    default:
    313      return R_BAD_ARGS;
    314  }
    315 
    316  poll_flags_ &= ~flag;
    317 
    318  return 0;
    319 }
    320 
    321 void NrSocketBase::fire_callback(int how) {
    322  // This can't happen unless we are armed because we only set
    323  // the flags if we are armed
    324  MOZ_ASSERT(cbs_[how]);
    325 
    326  // Now cancel so that we need to be re-armed. Note that
    327  // the re-arming probably happens in the callback we are
    328  // about to fire.
    329  cancel(how);
    330 
    331  cbs_[how](this, how, cb_args_[how]);
    332 }
    333 
    334 // NrSocket implementation
    335 NS_IMPL_QUERY_INTERFACE0(NrSocket)
    336 
    337 // The nsASocket callbacks
    338 void NrSocket::OnSocketReady(PRFileDesc* fd, int16_t outflags) {
    339  if (outflags & PR_POLL_READ & poll_flags()) fire_callback(NR_ASYNC_WAIT_READ);
    340  if (outflags & PR_POLL_WRITE & poll_flags())
    341    fire_callback(NR_ASYNC_WAIT_WRITE);
    342  if (outflags & (PR_POLL_ERR | PR_POLL_NVAL | PR_POLL_HUP))
    343    // TODO: Bug 946423: how do we notify the upper layers about this?
    344    close();
    345 }
    346 
    347 void NrSocket::OnSocketDetached(PRFileDesc* fd) {
    348  r_log(LOG_GENERIC, LOG_DEBUG, "Socket %p detached", fd);
    349 }
    350 
    351 void NrSocket::IsLocal(bool* aIsLocal) {
    352  // TODO(jesup): better check? Does it matter? (likely no)
    353  *aIsLocal = false;
    354 }
    355 
    356 // async_event APIs
    357 int NrSocket::async_wait(int how, NR_async_cb cb, void* cb_arg, char* function,
    358                         int line) {
    359  int r = NrSocketBase::async_wait(how, cb, cb_arg, function, line);
    360 
    361  if (!r) {
    362    mPollFlags = poll_flags();
    363  }
    364 
    365  return r;
    366 }
    367 
    368 int NrSocket::cancel(int how) {
    369  int r = NrSocketBase::cancel(how);
    370 
    371  if (!r) {
    372    mPollFlags = poll_flags();
    373  }
    374 
    375  return r;
    376 }
    377 
    378 // Helper functions for addresses
    379 static int nr_transport_addr_to_praddr(const nr_transport_addr* addr,
    380                                       PRNetAddr* naddr) {
    381  int _status;
    382 
    383  memset(naddr, 0, sizeof(*naddr));
    384 
    385  switch (addr->protocol) {
    386    case IPPROTO_TCP:
    387      break;
    388    case IPPROTO_UDP:
    389      break;
    390    default:
    391      ABORT(R_BAD_ARGS);
    392  }
    393 
    394  switch (addr->ip_version) {
    395    case NR_IPV4:
    396      naddr->inet.family = PR_AF_INET;
    397      naddr->inet.port = addr->u.addr4.sin_port;
    398      naddr->inet.ip = addr->u.addr4.sin_addr.s_addr;
    399      break;
    400    case NR_IPV6:
    401      naddr->ipv6.family = PR_AF_INET6;
    402      naddr->ipv6.port = addr->u.addr6.sin6_port;
    403      naddr->ipv6.flowinfo = addr->u.addr6.sin6_flowinfo;
    404      memcpy(&naddr->ipv6.ip, &addr->u.addr6.sin6_addr, sizeof(in6_addr));
    405      naddr->ipv6.scope_id = addr->u.addr6.sin6_scope_id;
    406      break;
    407    default:
    408      ABORT(R_BAD_ARGS);
    409  }
    410 
    411  _status = 0;
    412 abort:
    413  return (_status);
    414 }
    415 
    416 // XXX schien@mozilla.com: copy from PRNetAddrToNetAddr,
    417 // should be removed after fix the link error in signaling_unittests
    418 static int praddr_to_netaddr(const PRNetAddr* prAddr, net::NetAddr* addr) {
    419  int _status;
    420 
    421  switch (prAddr->raw.family) {
    422    case PR_AF_INET:
    423      addr->inet.family = AF_INET;
    424      addr->inet.port = prAddr->inet.port;
    425      addr->inet.ip = prAddr->inet.ip;
    426      break;
    427    case PR_AF_INET6:
    428      addr->inet6.family = AF_INET6;
    429      addr->inet6.port = prAddr->ipv6.port;
    430      addr->inet6.flowinfo = prAddr->ipv6.flowinfo;
    431      memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8));
    432      addr->inet6.scope_id = prAddr->ipv6.scope_id;
    433      break;
    434    default:
    435      MOZ_ASSERT(false);
    436      ABORT(R_BAD_ARGS);
    437  }
    438 
    439  _status = 0;
    440 abort:
    441  return (_status);
    442 }
    443 
    444 static int nr_transport_addr_to_netaddr(const nr_transport_addr* addr,
    445                                        net::NetAddr* naddr) {
    446  int r, _status;
    447  PRNetAddr praddr;
    448 
    449  if ((r = nr_transport_addr_to_praddr(addr, &praddr))) {
    450    ABORT(r);
    451  }
    452 
    453  if ((r = praddr_to_netaddr(&praddr, naddr))) {
    454    ABORT(r);
    455  }
    456 
    457  _status = 0;
    458 abort:
    459  return (_status);
    460 }
    461 
    462 int nr_netaddr_to_transport_addr(const net::NetAddr* netaddr,
    463                                 nr_transport_addr* addr, int protocol) {
    464  int _status;
    465  int r;
    466 
    467  switch (netaddr->raw.family) {
    468    case AF_INET:
    469      if ((r = nr_ip4_port_to_transport_addr(ntohl(netaddr->inet.ip),
    470                                             ntohs(netaddr->inet.port),
    471                                             protocol, addr)))
    472        ABORT(r);
    473      break;
    474    case AF_INET6:
    475      if ((r = nr_ip6_port_to_transport_addr((in6_addr*)&netaddr->inet6.ip.u8,
    476                                             ntohs(netaddr->inet6.port),
    477                                             protocol, addr)))
    478        ABORT(r);
    479      break;
    480    default:
    481      MOZ_ASSERT(false);
    482      ABORT(R_BAD_ARGS);
    483  }
    484  _status = 0;
    485 abort:
    486  return (_status);
    487 }
    488 
    489 int nr_praddr_to_transport_addr(const PRNetAddr* praddr,
    490                                nr_transport_addr* addr, int protocol,
    491                                int keep) {
    492  int _status;
    493  int r;
    494  struct sockaddr_in ip4;
    495  struct sockaddr_in6 ip6;
    496 
    497  switch (praddr->raw.family) {
    498    case PR_AF_INET:
    499      ip4.sin_family = PF_INET;
    500      ip4.sin_addr.s_addr = praddr->inet.ip;
    501      ip4.sin_port = praddr->inet.port;
    502      if ((r = nr_sockaddr_to_transport_addr((sockaddr*)&ip4, protocol, keep,
    503                                             addr)))
    504        ABORT(r);
    505      break;
    506    case PR_AF_INET6:
    507      ip6.sin6_family = PF_INET6;
    508      ip6.sin6_port = praddr->ipv6.port;
    509      ip6.sin6_flowinfo = praddr->ipv6.flowinfo;
    510      memcpy(&ip6.sin6_addr, &praddr->ipv6.ip, sizeof(in6_addr));
    511      ip6.sin6_scope_id = praddr->ipv6.scope_id;
    512      if ((r = nr_sockaddr_to_transport_addr((sockaddr*)&ip6, protocol, keep,
    513                                             addr)))
    514        ABORT(r);
    515      break;
    516    default:
    517      MOZ_ASSERT(false);
    518      ABORT(R_BAD_ARGS);
    519  }
    520 
    521  _status = 0;
    522 abort:
    523  return (_status);
    524 }
    525 
    526 /*
    527 * nr_transport_addr_get_addrstring_and_port
    528 * convert nr_transport_addr to IP address string and port number
    529 */
    530 int nr_transport_addr_get_addrstring_and_port(const nr_transport_addr* addr,
    531                                              nsACString* host, int32_t* port) {
    532  int r, _status;
    533  char addr_string[64];
    534 
    535  // We cannot directly use |nr_transport_addr.as_string| because it contains
    536  // more than ip address, therefore, we need to explicity convert it
    537  // from |nr_transport_addr_get_addrstring|.
    538  if ((r = nr_transport_addr_get_addrstring(addr, addr_string,
    539                                            sizeof(addr_string)))) {
    540    ABORT(r);
    541  }
    542 
    543  if ((r = nr_transport_addr_get_port(addr, port))) {
    544    ABORT(r);
    545  }
    546 
    547  *host = addr_string;
    548 
    549  _status = 0;
    550 abort:
    551  return (_status);
    552 }
    553 
    554 // nr_socket APIs (as member functions)
    555 int NrSocket::create(nr_transport_addr* addr) {
    556  int r, _status;
    557 
    558  PRStatus status;
    559  PRNetAddr naddr;
    560 
    561  nsresult rv;
    562  nsCOMPtr<nsISocketTransportService> stservice =
    563      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    564 
    565  if (!NS_SUCCEEDED(rv)) {
    566    ABORT(R_INTERNAL);
    567  }
    568 
    569  if ((r = nr_transport_addr_to_praddr(addr, &naddr))) ABORT(r);
    570 
    571  switch (addr->protocol) {
    572    case IPPROTO_UDP:
    573      if (!(fd_ = PR_OpenUDPSocket(naddr.raw.family))) {
    574        r_log(LOG_GENERIC, LOG_CRIT,
    575              "Couldn't create UDP socket, "
    576              "family=%d, err=%d",
    577              naddr.raw.family, PR_GetError());
    578        ABORT(R_INTERNAL);
    579      }
    580      break;
    581    case IPPROTO_TCP:
    582      // TODO: Rewrite this to use WebrtcTcpSocket.
    583      // Also use the same logic for TLS.
    584      if (my_addr_.fqdn[0] != '\0') ABORT(R_INTERNAL);
    585 
    586      if (!(fd_ = PR_OpenTCPSocket(naddr.raw.family))) {
    587        r_log(LOG_GENERIC, LOG_CRIT,
    588              "Couldn't create TCP socket, "
    589              "family=%d, err=%d",
    590              naddr.raw.family, PR_GetError());
    591        ABORT(R_INTERNAL);
    592      }
    593      // Set ReuseAddr for TCP sockets to enable having several
    594      // sockets bound to same local IP and port
    595      PRSocketOptionData opt_reuseaddr;
    596      opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
    597      opt_reuseaddr.value.reuse_addr = PR_TRUE;
    598      status = PR_SetSocketOption(fd_, &opt_reuseaddr);
    599      if (status != PR_SUCCESS) {
    600        r_log(LOG_GENERIC, LOG_CRIT,
    601              "Couldn't set reuse addr socket option: %d", status);
    602        ABORT(R_INTERNAL);
    603      }
    604      // And also set ReusePort for platforms supporting this socket option
    605      PRSocketOptionData opt_reuseport;
    606      opt_reuseport.option = PR_SockOpt_Reuseport;
    607      opt_reuseport.value.reuse_port = PR_TRUE;
    608      status = PR_SetSocketOption(fd_, &opt_reuseport);
    609      if (status != PR_SUCCESS) {
    610        if (PR_GetError() != PR_OPERATION_NOT_SUPPORTED_ERROR) {
    611          r_log(LOG_GENERIC, LOG_CRIT,
    612                "Couldn't set reuse port socket option: %d", status);
    613          ABORT(R_INTERNAL);
    614        }
    615      }
    616      // Try to speedup packet delivery by disabling TCP Nagle
    617      PRSocketOptionData opt_nodelay;
    618      opt_nodelay.option = PR_SockOpt_NoDelay;
    619      opt_nodelay.value.no_delay = PR_TRUE;
    620      status = PR_SetSocketOption(fd_, &opt_nodelay);
    621      if (status != PR_SUCCESS) {
    622        r_log(LOG_GENERIC, LOG_WARNING,
    623              "Couldn't set Nodelay socket option: %d", status);
    624      }
    625      break;
    626    default:
    627      ABORT(R_INTERNAL);
    628  }
    629 
    630  status = PR_Bind(fd_, &naddr);
    631  if (status != PR_SUCCESS) {
    632    r_log(LOG_GENERIC, LOG_CRIT, "Couldn't bind socket to address %s",
    633          addr->as_string);
    634    ABORT(R_INTERNAL);
    635  }
    636 
    637  r_log(LOG_GENERIC, LOG_DEBUG, "Creating socket %p with addr %s", fd_,
    638        addr->as_string);
    639  nr_transport_addr_copy(&my_addr_, addr);
    640 
    641  /* If we have a wildcard port, patch up the addr */
    642  if (nr_transport_addr_is_wildcard(addr)) {
    643    status = PR_GetSockName(fd_, &naddr);
    644    if (status != PR_SUCCESS) {
    645      r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket");
    646      ABORT(R_INTERNAL);
    647    }
    648 
    649    if ((r = nr_praddr_to_transport_addr(&naddr, &my_addr_, addr->protocol, 1)))
    650      ABORT(r);
    651  }
    652 
    653  // Set nonblocking
    654  PRSocketOptionData opt_nonblock;
    655  opt_nonblock.option = PR_SockOpt_Nonblocking;
    656  opt_nonblock.value.non_blocking = PR_TRUE;
    657  status = PR_SetSocketOption(fd_, &opt_nonblock);
    658  if (status != PR_SUCCESS) {
    659    r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking");
    660    ABORT(R_INTERNAL);
    661  }
    662 
    663  // Remember our thread.
    664  ststhread_ = do_QueryInterface(stservice, &rv);
    665  if (!NS_SUCCEEDED(rv)) ABORT(R_INTERNAL);
    666 
    667  // Finally, register with the STS
    668  rv = stservice->AttachSocket(fd_, this);
    669  if (!NS_SUCCEEDED(rv)) {
    670    r_log(LOG_GENERIC, LOG_CRIT, "Couldn't attach socket to STS, rv=%u",
    671          static_cast<unsigned>(rv));
    672    ABORT(R_INTERNAL);
    673  }
    674 
    675  _status = 0;
    676 
    677 abort:
    678  return (_status);
    679 }
    680 
    681 static int ShouldDrop(size_t len) {
    682  // Global rate limiting for stun requests, to mitigate the ice hammer DoS
    683  // (see http://tools.ietf.org/html/draft-thomson-mmusic-ice-webrtc)
    684 
    685  // Tolerate rate of 8k/sec, for one second.
    686  static SimpleTokenBucket burst(16384 * 1, 16384);
    687  // Tolerate rate of 7.2k/sec over twenty seconds.
    688  static SimpleTokenBucket sustained(7372 * 20, 7372);
    689 
    690  // Check number of tokens in each bucket.
    691  if (burst.getTokens(UINT32_MAX) < len) {
    692    r_log(LOG_GENERIC, LOG_ERR,
    693          "Short term global rate limit for STUN requests exceeded.");
    694 #ifdef MOZILLA_INTERNAL_API
    695    nr_socket_short_term_violation_time = TimeStamp::Now();
    696 #endif
    697 
    698 // Bug 1013007
    699 #if !EARLY_BETA_OR_EARLIER
    700    return R_WOULDBLOCK;
    701 #else
    702    MOZ_ASSERT(false,
    703               "Short term global rate limit for STUN requests exceeded. Go "
    704               "bug bcampen@mozilla.com if you weren't intentionally "
    705               "spamming ICE candidates, or don't know what that means.");
    706 #endif
    707  }
    708 
    709  if (sustained.getTokens(UINT32_MAX) < len) {
    710    r_log(LOG_GENERIC, LOG_ERR,
    711          "Long term global rate limit for STUN requests exceeded.");
    712 #ifdef MOZILLA_INTERNAL_API
    713    nr_socket_long_term_violation_time = TimeStamp::Now();
    714 #endif
    715 // Bug 1013007
    716 #if !EARLY_BETA_OR_EARLIER
    717    return R_WOULDBLOCK;
    718 #else
    719    MOZ_ASSERT(false,
    720               "Long term global rate limit for STUN requests exceeded. Go "
    721               "bug bcampen@mozilla.com if you weren't intentionally "
    722               "spamming ICE candidates, or don't know what that means.");
    723 #endif
    724  }
    725 
    726  // Take len tokens from both buckets.
    727  // (not threadsafe, but no problem since this is only called from STS)
    728  burst.getTokens(len);
    729  sustained.getTokens(len);
    730  return 0;
    731 }
    732 
    733 // This should be called on the STS thread.
    734 int NrSocket::sendto(const void* msg, size_t len, int flags,
    735                     const nr_transport_addr* to) {
    736  ASSERT_ON_THREAD(ststhread_);
    737  int r, _status;
    738  PRNetAddr naddr;
    739  int32_t status;
    740 
    741  if ((r = nr_transport_addr_to_praddr(to, &naddr))) ABORT(r);
    742 
    743  if (fd_ == nullptr) ABORT(R_EOD);
    744 
    745  if (nr_is_stun_request_message((UCHAR*)msg, len) && ShouldDrop(len)) {
    746    ABORT(R_WOULDBLOCK);
    747  }
    748 
    749  // TODO: Convert flags?
    750  status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT);
    751  if (status < 0 || (size_t)status != len) {
    752    if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
    753 
    754    r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s: %d", to->as_string,
    755          PR_GetError());
    756    ABORT(R_IO_ERROR);
    757  }
    758 
    759  mozilla::profiler_count_bandwidth_written_bytes(status);
    760  _status = 0;
    761 abort:
    762  return (_status);
    763 }
    764 
    765 int NrSocket::recvfrom(void* buf, size_t maxlen, size_t* len, int flags,
    766                       nr_transport_addr* from) {
    767  ASSERT_ON_THREAD(ststhread_);
    768  int r, _status;
    769  PRNetAddr nfrom;
    770  int32_t status;
    771 
    772  status = PR_RecvFrom(fd_, buf, maxlen, flags, &nfrom, PR_INTERVAL_NO_WAIT);
    773  if (status <= 0) {
    774    if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
    775    r_log(LOG_GENERIC, LOG_INFO, "Error in recvfrom: %d", (int)PR_GetError());
    776    ABORT(R_IO_ERROR);
    777  }
    778  *len = status;
    779 
    780  if ((r = nr_praddr_to_transport_addr(&nfrom, from, my_addr_.protocol, 0)))
    781    ABORT(r);
    782 
    783  // r_log(LOG_GENERIC,LOG_DEBUG,"Read %d bytes from %s",*len,addr->as_string);
    784  mozilla::profiler_count_bandwidth_read_bytes(status);
    785 
    786  _status = 0;
    787 abort:
    788  return (_status);
    789 }
    790 
    791 int NrSocket::getaddr(nr_transport_addr* addrp) {
    792  ASSERT_ON_THREAD(ststhread_);
    793  return nr_transport_addr_copy(addrp, &my_addr_);
    794 }
    795 
    796 // Close the socket so that the STS will detach and then kill it
    797 void NrSocket::close() {
    798  ASSERT_ON_THREAD(ststhread_);
    799  mCondition = NS_BASE_STREAM_CLOSED;
    800  cancel(NR_ASYNC_WAIT_READ);
    801  cancel(NR_ASYNC_WAIT_WRITE);
    802 }
    803 
    804 int NrSocket::connect(const nr_transport_addr* addr) {
    805  ASSERT_ON_THREAD(ststhread_);
    806  int r, _status;
    807  PRNetAddr naddr;
    808  int32_t connect_status, getsockname_status;
    809 
    810  if ((r = nr_transport_addr_to_praddr(addr, &naddr))) ABORT(r);
    811 
    812  if (!fd_) ABORT(R_EOD);
    813 
    814  // Note: this just means we tried to connect, not that we
    815  // are actually live.
    816  connect_invoked_ = true;
    817  connect_status = PR_Connect(fd_, &naddr, PR_INTERVAL_NO_WAIT);
    818  if (connect_status != PR_SUCCESS) {
    819    if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
    820      r_log(LOG_GENERIC, LOG_CRIT, "PR_Connect failed: %d", PR_GetError());
    821      ABORT(R_IO_ERROR);
    822    }
    823  }
    824 
    825  // If our local address is wildcard, then fill in the
    826  // address now.
    827  if (nr_transport_addr_is_wildcard(&my_addr_)) {
    828    getsockname_status = PR_GetSockName(fd_, &naddr);
    829    if (getsockname_status != PR_SUCCESS) {
    830      r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket");
    831      ABORT(R_INTERNAL);
    832    }
    833 
    834    if ((r = nr_praddr_to_transport_addr(&naddr, &my_addr_, addr->protocol, 1)))
    835      ABORT(r);
    836  }
    837 
    838  // Now return the WOULDBLOCK if needed.
    839  if (connect_status != PR_SUCCESS) {
    840    ABORT(R_WOULDBLOCK);
    841  }
    842 
    843  _status = 0;
    844 abort:
    845  return (_status);
    846 }
    847 
    848 int NrSocket::write(const void* msg, size_t len, size_t* written) {
    849  ASSERT_ON_THREAD(ststhread_);
    850  int _status;
    851  int32_t status;
    852 
    853  if (!connect_invoked_) ABORT(R_FAILED);
    854 
    855  status = PR_Write(fd_, msg, len);
    856  if (status < 0) {
    857    if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
    858    r_log(LOG_GENERIC, LOG_INFO, "Error in write");
    859    ABORT(R_IO_ERROR);
    860  }
    861 
    862  *written = status;
    863 
    864  _status = 0;
    865 abort:
    866  return _status;
    867 }
    868 
    869 int NrSocket::read(void* buf, size_t maxlen, size_t* len) {
    870  ASSERT_ON_THREAD(ststhread_);
    871  int _status;
    872  int32_t status;
    873 
    874  if (!connect_invoked_) ABORT(R_FAILED);
    875 
    876  status = PR_Read(fd_, buf, maxlen);
    877  if (status < 0) {
    878    if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
    879    r_log(LOG_GENERIC, LOG_INFO, "Error in read");
    880    ABORT(R_IO_ERROR);
    881  }
    882  if (status == 0) ABORT(R_EOD);
    883 
    884  *len = (size_t)status;  // Guaranteed to be > 0
    885  _status = 0;
    886 abort:
    887  return (_status);
    888 }
    889 
    890 int NrSocket::listen(int backlog) {
    891  ASSERT_ON_THREAD(ststhread_);
    892  int32_t status;
    893  int _status;
    894 
    895  assert(fd_);
    896  status = PR_Listen(fd_, backlog);
    897  if (status != PR_SUCCESS) {
    898    r_log(LOG_GENERIC, LOG_CRIT, "%s: PR_GetError() == %d", __FUNCTION__,
    899          PR_GetError());
    900    ABORT(R_IO_ERROR);
    901  }
    902 
    903  _status = 0;
    904 abort:
    905  return (_status);
    906 }
    907 
    908 int NrSocket::accept(nr_transport_addr* addrp, nr_socket** sockp) {
    909  ASSERT_ON_THREAD(ststhread_);
    910  int _status, r;
    911  PRStatus status;
    912  PRFileDesc* prfd;
    913  PRNetAddr nfrom;
    914  NrSocket* sock = nullptr;
    915  nsresult rv;
    916  PRSocketOptionData opt_nonblock, opt_nodelay;
    917  nsCOMPtr<nsISocketTransportService> stservice =
    918      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    919 
    920  if (NS_FAILED(rv)) {
    921    ABORT(R_INTERNAL);
    922  }
    923 
    924  if (!fd_) ABORT(R_EOD);
    925 
    926  prfd = PR_Accept(fd_, &nfrom, PR_INTERVAL_NO_WAIT);
    927 
    928  if (!prfd) {
    929    if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
    930 
    931    ABORT(R_IO_ERROR);
    932  }
    933 
    934  sock = new NrSocket();
    935 
    936  sock->fd_ = prfd;
    937  nr_transport_addr_copy(&sock->my_addr_, &my_addr_);
    938 
    939  if ((r = nr_praddr_to_transport_addr(&nfrom, addrp, my_addr_.protocol, 0)))
    940    ABORT(r);
    941 
    942  // Set nonblocking
    943  opt_nonblock.option = PR_SockOpt_Nonblocking;
    944  opt_nonblock.value.non_blocking = PR_TRUE;
    945  status = PR_SetSocketOption(prfd, &opt_nonblock);
    946  if (status != PR_SUCCESS) {
    947    r_log(LOG_GENERIC, LOG_CRIT,
    948          "Failed to make accepted socket nonblocking: %d", status);
    949    ABORT(R_INTERNAL);
    950  }
    951  // Disable TCP Nagle
    952  opt_nodelay.option = PR_SockOpt_NoDelay;
    953  opt_nodelay.value.no_delay = PR_TRUE;
    954  status = PR_SetSocketOption(prfd, &opt_nodelay);
    955  if (status != PR_SUCCESS) {
    956    r_log(LOG_GENERIC, LOG_WARNING,
    957          "Failed to set Nodelay on accepted socket: %d", status);
    958  }
    959 
    960  // Should fail only with OOM
    961  if ((r = nr_socket_create_int(static_cast<void*>(sock), sock->vtbl(), sockp)))
    962    ABORT(r);
    963 
    964  // Remember our thread.
    965  sock->ststhread_ = do_QueryInterface(stservice, &rv);
    966  if (NS_FAILED(rv)) ABORT(R_INTERNAL);
    967 
    968  // Finally, register with the STS
    969  rv = stservice->AttachSocket(prfd, sock);
    970  if (NS_FAILED(rv)) {
    971    ABORT(R_INTERNAL);
    972  }
    973 
    974  sock->connect_invoked_ = true;
    975 
    976  // Add a reference so that we can delete it in destroy()
    977  sock->AddRef();
    978  _status = 0;
    979 abort:
    980  if (_status) {
    981    delete sock;
    982  }
    983 
    984  return (_status);
    985 }
    986 
    987 NS_IMPL_ISUPPORTS(NrUdpSocketIpcProxy, nsIUDPSocketInternal)
    988 
    989 nsresult NrUdpSocketIpcProxy::Init(const RefPtr<NrUdpSocketIpc>& socket) {
    990  nsresult rv;
    991  sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    992  if (NS_FAILED(rv)) {
    993    MOZ_ASSERT(false, "Failed to get STS thread");
    994    return rv;
    995  }
    996 
    997  socket_ = socket;
    998  return NS_OK;
    999 }
   1000 
   1001 NrUdpSocketIpcProxy::~NrUdpSocketIpcProxy() {
   1002  // Send our ref to STS to be released
   1003  RUN_ON_THREAD(sts_thread_, mozilla::WrapRelease(socket_.forget()),
   1004                NS_DISPATCH_NORMAL);
   1005 }
   1006 
   1007 // IUDPSocketInternal interfaces
   1008 // callback while error happened in UDP socket operation
   1009 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerError(const nsACString& message,
   1010                                                     const nsACString& filename,
   1011                                                     uint32_t line_number) {
   1012  return socket_->CallListenerError(message, filename, line_number);
   1013 }
   1014 
   1015 // callback while receiving UDP packet
   1016 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerReceivedData(
   1017    const nsACString& host, uint16_t port, const nsTArray<uint8_t>& data) {
   1018  return socket_->CallListenerReceivedData(host, port, data);
   1019 }
   1020 
   1021 // callback while UDP socket is opened
   1022 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerOpened() {
   1023  return socket_->CallListenerOpened();
   1024 }
   1025 
   1026 // callback while UDP socket is connected
   1027 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerConnected() {
   1028  return socket_->CallListenerConnected();
   1029 }
   1030 
   1031 // callback while UDP socket is closed
   1032 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerClosed() {
   1033  return socket_->CallListenerClosed();
   1034 }
   1035 
   1036 // NrUdpSocketIpc Implementation
   1037 NrUdpSocketIpc::NrUdpSocketIpc()
   1038    : NrSocketIpc(GetIOThreadAndAddUse_s()),
   1039      monitor_("NrUdpSocketIpc"),
   1040      err_(false),
   1041      state_(NR_INIT) {}
   1042 
   1043 NrUdpSocketIpc::~NrUdpSocketIpc() = default;
   1044 
   1045 void NrUdpSocketIpc::Destroy() {
   1046 #if defined(MOZILLA_INTERNAL_API)
   1047  // destroy_i also dispatches back to STS to call ReleaseUse, to avoid shutting
   1048  // down the IO thread before close() runs.
   1049  // We use a NonOwning runnable because our refcount has already gone to 0.
   1050  io_thread_->Dispatch(NewNonOwningRunnableMethod(
   1051      "NrUdpSocketIpc::Destroy", this, &NrUdpSocketIpc::destroy_i));
   1052 #endif
   1053 }
   1054 
   1055 // IUDPSocketInternal interfaces
   1056 // callback while error happened in UDP socket operation
   1057 NS_IMETHODIMP NrUdpSocketIpc::CallListenerError(const nsACString& message,
   1058                                                const nsACString& filename,
   1059                                                uint32_t line_number) {
   1060  ASSERT_ON_THREAD(io_thread_);
   1061 
   1062  r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d this=%p",
   1063        message.BeginReading(), filename.BeginReading(), line_number,
   1064        (void*)this);
   1065 
   1066  ReentrantMonitorAutoEnter mon(monitor_);
   1067  err_ = true;
   1068  monitor_.NotifyAll();
   1069 
   1070  return NS_OK;
   1071 }
   1072 
   1073 // callback while receiving UDP packet
   1074 NS_IMETHODIMP NrUdpSocketIpc::CallListenerReceivedData(
   1075    const nsACString& host, uint16_t port, const nsTArray<uint8_t>& data) {
   1076  ASSERT_ON_THREAD(io_thread_);
   1077 
   1078  PRNetAddr addr;
   1079  memset(&addr, 0, sizeof(addr));
   1080 
   1081  {
   1082    ReentrantMonitorAutoEnter mon(monitor_);
   1083 
   1084    if (PR_SUCCESS != PR_StringToNetAddr(host.BeginReading(), &addr)) {
   1085      err_ = true;
   1086      MOZ_ASSERT(false, "Failed to convert remote host to PRNetAddr");
   1087      return NS_OK;
   1088    }
   1089 
   1090    // Use PR_IpAddrNull to avoid address being reset to 0.
   1091    if (PR_SUCCESS !=
   1092        PR_SetNetAddr(PR_IpAddrNull, addr.raw.family, port, &addr)) {
   1093      err_ = true;
   1094      MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
   1095      return NS_OK;
   1096    }
   1097  }
   1098 
   1099  auto buf = MakeUnique<MediaPacket>();
   1100  buf->Copy(data.Elements(), data.Length());
   1101  RefPtr<nr_udp_message> msg(new nr_udp_message(addr, std::move(buf)));
   1102 
   1103  RUN_ON_THREAD(sts_thread_,
   1104                mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
   1105                                      &NrUdpSocketIpc::recv_callback_s, msg),
   1106                NS_DISPATCH_NORMAL);
   1107  return NS_OK;
   1108 }
   1109 
   1110 nsresult NrUdpSocketIpc::SetAddress() {
   1111  uint16_t port = socket_child_->LocalPort();
   1112 
   1113  nsAutoCString address(socket_child_->LocalAddress());
   1114 
   1115  PRNetAddr praddr;
   1116  if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
   1117    err_ = true;
   1118    MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
   1119    return NS_OK;
   1120  }
   1121 
   1122  if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
   1123    err_ = true;
   1124    MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
   1125    return NS_OK;
   1126  }
   1127 
   1128  nr_transport_addr expected_addr;
   1129  if (nr_transport_addr_copy(&expected_addr, &my_addr_)) {
   1130    err_ = true;
   1131    MOZ_ASSERT(false, "Failed to copy my_addr_");
   1132  }
   1133 
   1134  if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
   1135    err_ = true;
   1136    MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
   1137  }
   1138 
   1139  if (!nr_transport_addr_is_wildcard(&expected_addr) &&
   1140      nr_transport_addr_cmp(&expected_addr, &my_addr_,
   1141                            NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
   1142    err_ = true;
   1143    MOZ_ASSERT(false, "Address of opened socket is not expected");
   1144  }
   1145 
   1146  return NS_OK;
   1147 }
   1148 
   1149 // callback while UDP socket is opened
   1150 NS_IMETHODIMP NrUdpSocketIpc::CallListenerOpened() {
   1151  ASSERT_ON_THREAD(io_thread_);
   1152  ReentrantMonitorAutoEnter mon(monitor_);
   1153 
   1154  r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket opened this=%p", (void*)this);
   1155  nsresult rv = SetAddress();
   1156  if (NS_FAILED(rv)) {
   1157    return rv;
   1158  }
   1159 
   1160  mon.NotifyAll();
   1161 
   1162  return NS_OK;
   1163 }
   1164 
   1165 // callback while UDP socket is connected
   1166 NS_IMETHODIMP NrUdpSocketIpc::CallListenerConnected() {
   1167  ASSERT_ON_THREAD(io_thread_);
   1168 
   1169  ReentrantMonitorAutoEnter mon(monitor_);
   1170 
   1171  r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket connected this=%p", (void*)this);
   1172  MOZ_ASSERT(state_ == NR_CONNECTED);
   1173 
   1174  nsresult rv = SetAddress();
   1175  if (NS_FAILED(rv)) {
   1176    mon.NotifyAll();
   1177    return rv;
   1178  }
   1179 
   1180  r_log(LOG_GENERIC, LOG_INFO, "Exit UDP socket connected");
   1181  mon.NotifyAll();
   1182 
   1183  return NS_OK;
   1184 }
   1185 
   1186 // callback while UDP socket is closed
   1187 NS_IMETHODIMP NrUdpSocketIpc::CallListenerClosed() {
   1188  ASSERT_ON_THREAD(io_thread_);
   1189 
   1190  ReentrantMonitorAutoEnter mon(monitor_);
   1191 
   1192  r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket closed this=%p", (void*)this);
   1193  MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
   1194  state_ = NR_CLOSED;
   1195 
   1196  return NS_OK;
   1197 }
   1198 
   1199 //
   1200 // NrSocketBase methods.
   1201 //
   1202 int NrUdpSocketIpc::create(nr_transport_addr* addr) {
   1203  ASSERT_ON_THREAD(sts_thread_);
   1204 
   1205  int r, _status;
   1206  nsresult rv;
   1207  int32_t port;
   1208  nsCString host;
   1209 
   1210  ReentrantMonitorAutoEnter mon(monitor_);
   1211 
   1212  if (state_ != NR_INIT) {
   1213    ABORT(R_INTERNAL);
   1214  }
   1215 
   1216  sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
   1217  if (NS_FAILED(rv)) {
   1218    MOZ_ASSERT(false, "Failed to get STS thread");
   1219    ABORT(R_INTERNAL);
   1220  }
   1221 
   1222  if ((r = nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
   1223    ABORT(r);
   1224  }
   1225 
   1226  // wildcard address will be resolved at NrUdpSocketIpc::CallListenerVoid
   1227  if ((r = nr_transport_addr_copy(&my_addr_, addr))) {
   1228    ABORT(r);
   1229  }
   1230 
   1231  state_ = NR_CONNECTING;
   1232 
   1233  MOZ_ASSERT(io_thread_);
   1234  RUN_ON_THREAD(io_thread_,
   1235                mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
   1236                                      &NrUdpSocketIpc::create_i, host,
   1237                                      static_cast<uint16_t>(port)),
   1238                NS_DISPATCH_NORMAL);
   1239 
   1240  // Wait until socket creation complete.
   1241  mon.Wait();
   1242 
   1243  if (err_) {
   1244    close();
   1245    ABORT(R_INTERNAL);
   1246  }
   1247 
   1248  state_ = NR_CONNECTED;
   1249 
   1250  _status = 0;
   1251 abort:
   1252  return (_status);
   1253 }
   1254 
   1255 int NrUdpSocketIpc::sendto(const void* msg, size_t len, int flags,
   1256                           const nr_transport_addr* to) {
   1257  ASSERT_ON_THREAD(sts_thread_);
   1258 
   1259  ReentrantMonitorAutoEnter mon(monitor_);
   1260 
   1261  // If send err happened before, simply return the error.
   1262  if (err_) {
   1263    return R_IO_ERROR;
   1264  }
   1265 
   1266  if (state_ != NR_CONNECTED) {
   1267    return R_INTERNAL;
   1268  }
   1269 
   1270  int r;
   1271  net::NetAddr addr;
   1272  if ((r = nr_transport_addr_to_netaddr(to, &addr))) {
   1273    return r;
   1274  }
   1275 
   1276  if (nr_is_stun_request_message((UCHAR*)msg, len) && ShouldDrop(len)) {
   1277    return R_WOULDBLOCK;
   1278  }
   1279 
   1280  UniquePtr<MediaPacket> buf(new MediaPacket);
   1281  buf->Copy(static_cast<const uint8_t*>(msg), len);
   1282 
   1283  RUN_ON_THREAD(
   1284      io_thread_,
   1285      mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
   1286                            &NrUdpSocketIpc::sendto_i, addr, std::move(buf)),
   1287      NS_DISPATCH_NORMAL);
   1288  return 0;
   1289 }
   1290 
   1291 void NrUdpSocketIpc::close() {
   1292  r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::close()");
   1293 
   1294  ASSERT_ON_THREAD(sts_thread_);
   1295 
   1296  ReentrantMonitorAutoEnter mon(monitor_);
   1297  state_ = NR_CLOSING;
   1298 
   1299  RUN_ON_THREAD(io_thread_,
   1300                mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
   1301                                      &NrUdpSocketIpc::close_i),
   1302                NS_DISPATCH_NORMAL);
   1303 
   1304  // remove all enqueued messages
   1305  std::queue<RefPtr<nr_udp_message>> empty;
   1306  std::swap(received_msgs_, empty);
   1307 }
   1308 
   1309 int NrUdpSocketIpc::recvfrom(void* buf, size_t maxlen, size_t* len, int flags,
   1310                             nr_transport_addr* from) {
   1311  ASSERT_ON_THREAD(sts_thread_);
   1312 
   1313  ReentrantMonitorAutoEnter mon(monitor_);
   1314 
   1315  int r, _status;
   1316  uint32_t consumed_len;
   1317 
   1318  *len = 0;
   1319 
   1320  if (state_ != NR_CONNECTED) {
   1321    ABORT(R_INTERNAL);
   1322  }
   1323 
   1324  if (received_msgs_.empty()) {
   1325    ABORT(R_WOULDBLOCK);
   1326  }
   1327 
   1328  {
   1329    RefPtr<nr_udp_message> msg(received_msgs_.front());
   1330 
   1331    received_msgs_.pop();
   1332 
   1333    if ((r = nr_praddr_to_transport_addr(&msg->from, from, IPPROTO_UDP, 0))) {
   1334      err_ = true;
   1335      MOZ_ASSERT(false, "Get bogus address for received UDP packet");
   1336      ABORT(r);
   1337    }
   1338 
   1339    consumed_len = std::min(maxlen, msg->data->len());
   1340    if (consumed_len < msg->data->len()) {
   1341      r_log(LOG_GENERIC, LOG_DEBUG,
   1342            "Partial received UDP packet will be discard");
   1343    }
   1344 
   1345    memcpy(buf, msg->data->data(), consumed_len);
   1346    *len = consumed_len;
   1347  }
   1348 
   1349  _status = 0;
   1350 abort:
   1351  return (_status);
   1352 }
   1353 
   1354 int NrUdpSocketIpc::getaddr(nr_transport_addr* addrp) {
   1355  ASSERT_ON_THREAD(sts_thread_);
   1356 
   1357  ReentrantMonitorAutoEnter mon(monitor_);
   1358 
   1359  return nr_transport_addr_copy(addrp, &my_addr_);
   1360 }
   1361 
   1362 int NrUdpSocketIpc::connect(const nr_transport_addr* addr) {
   1363  int r, _status;
   1364  int32_t port;
   1365  nsCString host;
   1366 
   1367  ReentrantMonitorAutoEnter mon(monitor_);
   1368  r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::connect(%s) this=%p",
   1369        addr->as_string, (void*)this);
   1370 
   1371  if ((r = nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
   1372    ABORT(r);
   1373  }
   1374 
   1375  RUN_ON_THREAD(io_thread_,
   1376                mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
   1377                                      &NrUdpSocketIpc::connect_i, host,
   1378                                      static_cast<uint16_t>(port)),
   1379                NS_DISPATCH_NORMAL);
   1380 
   1381  // Wait until connect() completes.
   1382  mon.Wait();
   1383 
   1384  r_log(LOG_GENERIC, LOG_DEBUG,
   1385        "NrUdpSocketIpc::connect this=%p completed err_ = %s", (void*)this,
   1386        err_ ? "true" : "false");
   1387 
   1388  if (err_) {
   1389    ABORT(R_INTERNAL);
   1390  }
   1391 
   1392  _status = 0;
   1393 abort:
   1394  return _status;
   1395 }
   1396 
   1397 int NrUdpSocketIpc::write(const void* msg, size_t len, size_t* written) {
   1398  MOZ_ASSERT(false);
   1399  return R_INTERNAL;
   1400 }
   1401 
   1402 int NrUdpSocketIpc::read(void* buf, size_t maxlen, size_t* len) {
   1403  MOZ_ASSERT(false);
   1404  return R_INTERNAL;
   1405 }
   1406 
   1407 int NrUdpSocketIpc::listen(int backlog) {
   1408  MOZ_ASSERT(false);
   1409  return R_INTERNAL;
   1410 }
   1411 
   1412 int NrUdpSocketIpc::accept(nr_transport_addr* addrp, nr_socket** sockp) {
   1413  MOZ_ASSERT(false);
   1414  return R_INTERNAL;
   1415 }
   1416 
   1417 // IO thread executors
   1418 void NrUdpSocketIpc::create_i(const nsACString& host, const uint16_t port) {
   1419  ASSERT_ON_THREAD(io_thread_);
   1420 
   1421  uint32_t minBuffSize = 0;
   1422  RefPtr<dom::UDPSocketChild> socketChild = new dom::UDPSocketChild();
   1423 
   1424  // This can spin the event loop; don't do that with the monitor held
   1425  socketChild->SetBackgroundSpinsEvents();
   1426 
   1427  ReentrantMonitorAutoEnter mon(monitor_);
   1428  if (!socket_child_) {
   1429    socket_child_ = socketChild;
   1430    socket_child_->SetFilterName(
   1431        nsCString(NS_NETWORK_SOCKET_FILTER_HANDLER_STUN_SUFFIX));
   1432  } else {
   1433    socketChild = nullptr;
   1434  }
   1435 
   1436  RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy);
   1437  nsresult rv = proxy->Init(this);
   1438  if (NS_FAILED(rv)) {
   1439    err_ = true;
   1440    mon.NotifyAll();
   1441    return;
   1442  }
   1443 
   1444  // XXX bug 1126232 - don't use null Principal!
   1445  if (NS_FAILED(socket_child_->Bind(proxy, nullptr, host, port,
   1446                                    /* addressReuse = */ false,
   1447                                    /* loopback = */ false,
   1448                                    /* recv buffer size */ minBuffSize,
   1449                                    /* send buffer size */ minBuffSize))) {
   1450    err_ = true;
   1451    MOZ_ASSERT(false, "Failed to create UDP socket");
   1452    mon.NotifyAll();
   1453    return;
   1454  }
   1455 }
   1456 
   1457 void NrUdpSocketIpc::connect_i(const nsACString& host, const uint16_t port) {
   1458  ASSERT_ON_THREAD(io_thread_);
   1459  nsresult rv;
   1460  ReentrantMonitorAutoEnter mon(monitor_);
   1461 
   1462  RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy);
   1463  rv = proxy->Init(this);
   1464  if (NS_FAILED(rv)) {
   1465    err_ = true;
   1466    mon.NotifyAll();
   1467    return;
   1468  }
   1469 
   1470  socket_child_->Connect(proxy, host, port);
   1471 }
   1472 
   1473 void NrUdpSocketIpc::sendto_i(const net::NetAddr& addr,
   1474                              UniquePtr<MediaPacket> buf) {
   1475  ASSERT_ON_THREAD(io_thread_);
   1476 
   1477  ReentrantMonitorAutoEnter mon(monitor_);
   1478 
   1479  if (!socket_child_) {
   1480    MOZ_ASSERT(false);
   1481    err_ = true;
   1482    return;
   1483  }
   1484  if (NS_FAILED(
   1485          socket_child_->SendWithAddress(&addr, buf->data(), buf->len()))) {
   1486    err_ = true;
   1487  }
   1488 }
   1489 
   1490 void NrUdpSocketIpc::close_i() {
   1491  ASSERT_ON_THREAD(io_thread_);
   1492 
   1493  if (socket_child_) {
   1494    socket_child_->Close();
   1495    socket_child_ = nullptr;
   1496  }
   1497 }
   1498 
   1499 #if defined(MOZILLA_INTERNAL_API)
   1500 
   1501 static void ReleaseIOThread_s() { sThread->ReleaseUse(); }
   1502 
   1503 void NrUdpSocketIpc::destroy_i() {
   1504  close_i();
   1505 
   1506  RUN_ON_THREAD(sts_thread_, WrapRunnableNM(&ReleaseIOThread_s),
   1507                NS_DISPATCH_NORMAL);
   1508 }
   1509 #endif
   1510 
   1511 void NrUdpSocketIpc::recv_callback_s(RefPtr<nr_udp_message> msg) {
   1512  ASSERT_ON_THREAD(sts_thread_);
   1513 
   1514  {
   1515    ReentrantMonitorAutoEnter mon(monitor_);
   1516    if (state_ != NR_CONNECTED) {
   1517      return;
   1518    }
   1519  }
   1520 
   1521  // enqueue received message
   1522  received_msgs_.push(msg);
   1523 
   1524  if ((poll_flags() & PR_POLL_READ)) {
   1525    fire_callback(NR_ASYNC_WAIT_READ);
   1526  }
   1527 }
   1528 
   1529 }  // namespace mozilla
   1530 
   1531 using namespace mozilla;
   1532 
   1533 // Bridge to the nr_socket interface
   1534 static int nr_socket_local_destroy(void** objp);
   1535 static int nr_socket_local_sendto(void* obj, const void* msg, size_t len,
   1536                                  int flags, const nr_transport_addr* to);
   1537 static int nr_socket_local_recvfrom(void* obj, void* restrict buf,
   1538                                    size_t maxlen, size_t* len, int flags,
   1539                                    nr_transport_addr* from);
   1540 static int nr_socket_local_getfd(void* obj, NR_SOCKET* fd);
   1541 static int nr_socket_local_getaddr(void* obj, nr_transport_addr* addrp);
   1542 static int nr_socket_local_close(void* obj);
   1543 static int nr_socket_local_connect(void* obj, const nr_transport_addr* addr);
   1544 static int nr_socket_local_write(void* obj, const void* msg, size_t len,
   1545                                 size_t* written);
   1546 static int nr_socket_local_read(void* obj, void* restrict buf, size_t maxlen,
   1547                                size_t* len);
   1548 static int nr_socket_local_listen(void* obj, int backlog);
   1549 static int nr_socket_local_accept(void* obj, nr_transport_addr* addrp,
   1550                                  nr_socket** sockp);
   1551 
   1552 static nr_socket_vtbl nr_socket_local_vtbl = {2,
   1553                                              nr_socket_local_destroy,
   1554                                              nr_socket_local_sendto,
   1555                                              nr_socket_local_recvfrom,
   1556                                              nr_socket_local_getfd,
   1557                                              nr_socket_local_getaddr,
   1558                                              nr_socket_local_connect,
   1559                                              nr_socket_local_write,
   1560                                              nr_socket_local_read,
   1561                                              nr_socket_local_close,
   1562                                              nr_socket_local_listen,
   1563                                              nr_socket_local_accept};
   1564 
   1565 /* static */
   1566 int NrSocketBase::CreateSocket(
   1567    nr_transport_addr* addr, RefPtr<NrSocketBase>* sock,
   1568    const std::shared_ptr<NrSocketProxyConfig>& config) {
   1569  int r, _status;
   1570 
   1571  if (IsForbiddenAddress(addr)) {
   1572    ABORT(R_REJECTED);
   1573  }
   1574 
   1575  if (config && config->GetForceProxy() && addr->protocol == IPPROTO_UDP) {
   1576    ABORT(R_REJECTED);
   1577  }
   1578 
   1579  // create IPC bridge for content process
   1580  if (XRE_IsParentProcess()) {
   1581    // TODO: Make NrTcpSocket work on the parent process
   1582    *sock = new NrSocket();
   1583  } else if (XRE_IsSocketProcess()) {
   1584    if (addr->protocol == IPPROTO_TCP) {
   1585      *sock = new NrTcpSocket(config);
   1586    } else {
   1587      *sock = new NrSocket();
   1588    }
   1589  } else {
   1590    if (addr->protocol == IPPROTO_TCP) {
   1591      *sock = new NrTcpSocket(config);
   1592    } else {
   1593      *sock = new NrUdpSocketIpc();
   1594    }
   1595  }
   1596 
   1597  r = (*sock)->create(addr);
   1598  if (r) ABORT(r);
   1599 
   1600  _status = 0;
   1601 abort:
   1602  if (_status) {
   1603    *sock = nullptr;
   1604  }
   1605  return _status;
   1606 }
   1607 
   1608 // static
   1609 bool NrSocketBase::IsForbiddenAddress(nr_transport_addr* addr) {
   1610  int r, port;
   1611 
   1612  r = nr_transport_addr_get_port(addr, &port);
   1613  if (r) {
   1614    return true;
   1615  }
   1616 
   1617  // allow auto assigned ports
   1618  if (port != 0) {
   1619    // Don't need to check an override scheme
   1620    nsresult rv = NS_CheckPortSafety(port, nullptr);
   1621    if (NS_FAILED(rv)) {
   1622      return true;
   1623    }
   1624  }
   1625 
   1626  return false;
   1627 }
   1628 
   1629 static int nr_socket_local_destroy(void** objp) {
   1630  if (!objp || !*objp) return 0;
   1631 
   1632  NrSocketBase* sock = static_cast<NrSocketBase*>(*objp);
   1633  *objp = nullptr;
   1634 
   1635  sock->close();    // Signal STS that we want not to listen
   1636  sock->Release();  // Decrement the ref count
   1637 
   1638  return 0;
   1639 }
   1640 
   1641 static int nr_socket_local_sendto(void* obj, const void* msg, size_t len,
   1642                                  int flags, const nr_transport_addr* addr) {
   1643  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1644 
   1645  return sock->sendto(msg, len, flags, addr);
   1646 }
   1647 
   1648 static int nr_socket_local_recvfrom(void* obj, void* restrict buf,
   1649                                    size_t maxlen, size_t* len, int flags,
   1650                                    nr_transport_addr* addr) {
   1651  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1652 
   1653  return sock->recvfrom(buf, maxlen, len, flags, addr);
   1654 }
   1655 
   1656 static int nr_socket_local_getfd(void* obj, NR_SOCKET* fd) {
   1657  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1658 
   1659  *fd = sock;
   1660 
   1661  return 0;
   1662 }
   1663 
   1664 static int nr_socket_local_getaddr(void* obj, nr_transport_addr* addrp) {
   1665  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1666 
   1667  return sock->getaddr(addrp);
   1668 }
   1669 
   1670 static int nr_socket_local_close(void* obj) {
   1671  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1672 
   1673  sock->close();
   1674 
   1675  return 0;
   1676 }
   1677 
   1678 static int nr_socket_local_write(void* obj, const void* msg, size_t len,
   1679                                 size_t* written) {
   1680  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1681 
   1682  return sock->write(msg, len, written);
   1683 }
   1684 
   1685 static int nr_socket_local_read(void* obj, void* restrict buf, size_t maxlen,
   1686                                size_t* len) {
   1687  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1688 
   1689  return sock->read(buf, maxlen, len);
   1690 }
   1691 
   1692 static int nr_socket_local_connect(void* obj, const nr_transport_addr* addr) {
   1693  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1694 
   1695  return sock->connect(addr);
   1696 }
   1697 
   1698 static int nr_socket_local_listen(void* obj, int backlog) {
   1699  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1700 
   1701  return sock->listen(backlog);
   1702 }
   1703 
   1704 static int nr_socket_local_accept(void* obj, nr_transport_addr* addrp,
   1705                                  nr_socket** sockp) {
   1706  NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
   1707 
   1708  return sock->accept(addrp, sockp);
   1709 }
   1710 
   1711 // Implement async api
   1712 int NR_async_wait(NR_SOCKET sock, int how, NR_async_cb cb, void* cb_arg,
   1713                  char* function, int line) {
   1714  NrSocketBase* s = static_cast<NrSocketBase*>(sock);
   1715 
   1716  return s->async_wait(how, cb, cb_arg, function, line);
   1717 }
   1718 
   1719 int NR_async_cancel(NR_SOCKET sock, int how) {
   1720  NrSocketBase* s = static_cast<NrSocketBase*>(sock);
   1721 
   1722  return s->cancel(how);
   1723 }
   1724 
   1725 nr_socket_vtbl* NrSocketBase::vtbl() { return &nr_socket_local_vtbl; }