LCOV - code coverage report
Current view: top level - media/mtransport - nr_socket_prsock.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 2 990 0.2 %
Date: 2017-07-14 16:53:18 Functions: 2 130 1.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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 <csi_platform.h>
      87             : #include <stdio.h>
      88             : #include <string.h>
      89             : #include <sys/types.h>
      90             : #include <assert.h>
      91             : #include <errno.h>
      92             : #include <string>
      93             : 
      94             : #include "nspr.h"
      95             : #include "prerror.h"
      96             : #include "prio.h"
      97             : #include "prnetdb.h"
      98             : 
      99             : #include "mozilla/net/DNS.h"
     100             : #include "nsCOMPtr.h"
     101             : #include "nsASocketHandler.h"
     102             : #include "nsISocketTransportService.h"
     103             : #include "nsNetCID.h"
     104             : #include "nsISupportsImpl.h"
     105             : #include "nsServiceManagerUtils.h"
     106             : #include "nsComponentManagerUtils.h"
     107             : #include "nsXPCOM.h"
     108             : #include "nsXULAppAPI.h"
     109             : #include "runnable_utils.h"
     110             : #include "mozilla/SyncRunnable.h"
     111             : #include "nsTArray.h"
     112             : #include "mozilla/dom/TCPSocketBinding.h"
     113             : #include "mozilla/SystemGroup.h"
     114             : #include "nsITCPSocketCallback.h"
     115             : #include "nsIPrefService.h"
     116             : #include "nsIPrefBranch.h"
     117             : #include "nsISocketFilter.h"
     118             : #include "nsDebug.h"
     119             : 
     120             : #ifdef XP_WIN
     121             : #include "mozilla/WindowsVersion.h"
     122             : #endif
     123             : 
     124             : #if defined(MOZILLA_INTERNAL_API)
     125             : // csi_platform.h deep in nrappkit defines LOG_INFO and LOG_WARNING
     126             : #ifdef LOG_INFO
     127             : #define LOG_TEMP_INFO LOG_INFO
     128             : #undef LOG_INFO
     129             : #endif
     130             : #ifdef LOG_WARNING
     131             : #define LOG_TEMP_WARNING LOG_WARNING
     132             : #undef LOG_WARNING
     133             : #endif
     134             : #if defined(LOG_DEBUG)
     135             : #define LOG_TEMP_DEBUG LOG_DEBUG
     136             : #undef LOG_DEBUG
     137             : #endif
     138             : #undef strlcpy
     139             : 
     140             : #include "mozilla/dom/network/TCPSocketChild.h"
     141             : 
     142             : #ifdef LOG_TEMP_INFO
     143             : #define LOG_INFO LOG_TEMP_INFO
     144             : #endif
     145             : #ifdef LOG_TEMP_WARNING
     146             : #define LOG_WARNING LOG_TEMP_WARNING
     147             : #endif
     148             : 
     149             : #ifdef LOG_TEMP_DEBUG
     150             : #define LOG_DEBUG LOG_TEMP_DEBUG
     151             : #endif
     152             : #ifdef XP_WIN
     153             : #ifdef LOG_DEBUG
     154             : #undef LOG_DEBUG
     155             : #endif
     156             : // cloned from csi_platform.h.  Win32 doesn't like how we hide symbols
     157             : #define LOG_DEBUG 7
     158             : #endif
     159             : #endif
     160             : 
     161             : 
     162             : extern "C" {
     163             : #include "nr_api.h"
     164             : #include "async_wait.h"
     165             : #include "nr_socket.h"
     166             : #include "nr_socket_local.h"
     167             : #include "stun_hint.h"
     168             : }
     169             : #include "nr_socket_prsock.h"
     170             : #include "simpletokenbucket.h"
     171             : #include "test_nr_socket.h"
     172             : 
     173             : // Implement the nsISupports ref counting
     174             : namespace mozilla {
     175             : 
     176             : #if defined(MOZILLA_INTERNAL_API)
     177             : class SingletonThreadHolder final
     178             : {
     179             : private:
     180           0 :   ~SingletonThreadHolder()
     181           0 :   {
     182           0 :     r_log(LOG_GENERIC,LOG_DEBUG,"Deleting SingletonThreadHolder");
     183           0 :     if (mThread) {
     184             :       // Likely a connection is somehow being held in CC or GC
     185           0 :       NS_WARNING("SingletonThreads should be Released and shut down before exit!");
     186           0 :       mThread->Shutdown();
     187           0 :       mThread = nullptr;
     188             :     }
     189           0 :   }
     190             : 
     191             :   DISALLOW_COPY_ASSIGN(SingletonThreadHolder);
     192             : 
     193             : public:
     194             :   // Must be threadsafe for StaticRefPtr/ClearOnShutdown
     195           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SingletonThreadHolder)
     196             : 
     197           0 :   explicit SingletonThreadHolder(const nsACString& aName)
     198           0 :     : mName(aName)
     199             :   {
     200           0 :     mParentThread = NS_GetCurrentThread();
     201           0 :   }
     202             : 
     203           0 :   nsIThread* GetThread() {
     204           0 :     return mThread;
     205             :   }
     206             : 
     207             :   /*
     208             :    * Keep track of how many instances are using a SingletonThreadHolder.
     209             :    * When no one is using it, shut it down
     210             :    */
     211           0 :   void AddUse()
     212             :   {
     213           0 :     RUN_ON_THREAD(mParentThread,
     214           0 :                   mozilla::WrapRunnable(RefPtr<SingletonThreadHolder>(this),
     215             :                                         &SingletonThreadHolder::AddUse_i),
     216           0 :                   NS_DISPATCH_SYNC);
     217           0 :   }
     218             : 
     219           0 :   void AddUse_i()
     220             :   {
     221           0 :     MOZ_ASSERT(int32_t(mUseCount) >= 0, "illegal refcnt");
     222           0 :     nsrefcnt count = ++mUseCount;
     223           0 :     if (count == 1) {
     224             :       // idle -> in-use
     225           0 :       nsresult rv = NS_NewNamedThread(mName, getter_AddRefs(mThread));
     226           0 :       MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv) && mThread,
     227             :                          "Should successfully create mtransport I/O thread");
     228           0 :       r_log(LOG_GENERIC,LOG_DEBUG,"Created wrapped SingletonThread %p",
     229           0 :             mThread.get());
     230             :     }
     231           0 :     r_log(LOG_GENERIC,LOG_DEBUG,"AddUse_i: %lu", (unsigned long) count);
     232           0 :   }
     233             : 
     234           0 :   void ReleaseUse()
     235             :   {
     236           0 :     RUN_ON_THREAD(mParentThread,
     237           0 :                   mozilla::WrapRunnable(RefPtr<SingletonThreadHolder>(this),
     238             :                                         &SingletonThreadHolder::ReleaseUse_i),
     239           0 :                   NS_DISPATCH_SYNC);
     240           0 :   }
     241             : 
     242           0 :   void ReleaseUse_i()
     243             :   {
     244           0 :     MOZ_ASSERT(mParentThread == NS_GetCurrentThread());
     245           0 :     nsrefcnt count = --mUseCount;
     246           0 :     MOZ_ASSERT(int32_t(mUseCount) >= 0, "illegal refcnt");
     247           0 :     if (mThread && count == 0) {
     248             :       // in-use -> idle -- no one forcing it to remain instantiated
     249           0 :       r_log(LOG_GENERIC,LOG_DEBUG,"Shutting down wrapped SingletonThread %p",
     250           0 :             mThread.get());
     251           0 :       mThread->Shutdown();
     252           0 :       mThread = nullptr;
     253             :       // It'd be nice to use a timer instead...  But be careful of
     254             :       // xpcom-shutdown-threads in that case
     255             :     }
     256           0 :     r_log(LOG_GENERIC,LOG_DEBUG,"ReleaseUse_i: %lu", (unsigned long) count);
     257           0 :   }
     258             : 
     259             : private:
     260             :   nsCString mName;
     261             :   nsAutoRefCnt mUseCount;
     262             :   nsCOMPtr<nsIThread> mParentThread;
     263             :   nsCOMPtr<nsIThread> mThread;
     264             : };
     265             : 
     266           3 : static StaticRefPtr<SingletonThreadHolder> sThread;
     267             : 
     268           0 : static void ClearSingletonOnShutdown()
     269             : {
     270           0 :   ClearOnShutdown(&sThread, ShutdownPhase::ShutdownThreads);
     271           0 : }
     272             : #endif
     273             : 
     274           0 : static nsIThread* GetIOThreadAndAddUse_s()
     275             : {
     276             :   // Always runs on STS thread!
     277             : #if defined(MOZILLA_INTERNAL_API)
     278             :   // We need to safely release this on shutdown to avoid leaks
     279           0 :   if (!sThread) {
     280           0 :     sThread = new SingletonThreadHolder(NS_LITERAL_CSTRING("mtransport"));
     281           0 :     NS_DispatchToMainThread(mozilla::WrapRunnableNM(&ClearSingletonOnShutdown));
     282             :   }
     283             :   // Mark that we're using the shared thread and need it to stick around
     284           0 :   sThread->AddUse();
     285           0 :   return sThread->GetThread();
     286             : #else
     287             :   static nsCOMPtr<nsIThread> sThread;
     288             :   if (!sThread) {
     289             :     (void) NS_NewNamedThread("mtransport", getter_AddRefs(sThread));
     290             :   }
     291             :   return sThread;
     292             : #endif
     293             : }
     294             : 
     295           0 : NrSocketIpc::NrSocketIpc(nsIEventTarget *aThread)
     296           0 :   : io_thread_(aThread)
     297           0 : {}
     298             : 
     299             : static TimeStamp nr_socket_short_term_violation_time;
     300             : static TimeStamp nr_socket_long_term_violation_time;
     301             : 
     302           0 : TimeStamp NrSocketBase::short_term_violation_time() {
     303           0 :   return nr_socket_short_term_violation_time;
     304             : }
     305             : 
     306           0 : TimeStamp NrSocketBase::long_term_violation_time() {
     307           0 :   return nr_socket_long_term_violation_time;
     308             : }
     309             : 
     310             : // NrSocketBase implementation
     311             : // async_event APIs
     312           0 : int NrSocketBase::async_wait(int how, NR_async_cb cb, void *cb_arg,
     313             :                              char *function, int line) {
     314             :   uint16_t flag;
     315             : 
     316           0 :   switch (how) {
     317             :     case NR_ASYNC_WAIT_READ:
     318           0 :       flag = PR_POLL_READ;
     319           0 :       break;
     320             :     case NR_ASYNC_WAIT_WRITE:
     321           0 :       flag = PR_POLL_WRITE;
     322           0 :       break;
     323             :     default:
     324           0 :       return R_BAD_ARGS;
     325             :   }
     326             : 
     327           0 :   cbs_[how] = cb;
     328           0 :   cb_args_[how] = cb_arg;
     329           0 :   poll_flags_ |= flag;
     330             : 
     331           0 :   return 0;
     332             : }
     333             : 
     334           0 : int NrSocketBase::cancel(int how) {
     335             :   uint16_t flag;
     336             : 
     337           0 :   switch (how) {
     338             :     case NR_ASYNC_WAIT_READ:
     339           0 :       flag = PR_POLL_READ;
     340           0 :       break;
     341             :     case NR_ASYNC_WAIT_WRITE:
     342           0 :       flag = PR_POLL_WRITE;
     343           0 :       break;
     344             :     default:
     345           0 :       return R_BAD_ARGS;
     346             :   }
     347             : 
     348           0 :   poll_flags_ &= ~flag;
     349             : 
     350           0 :   return 0;
     351             : }
     352             : 
     353           0 : void NrSocketBase::fire_callback(int how) {
     354             :   // This can't happen unless we are armed because we only set
     355             :   // the flags if we are armed
     356           0 :   MOZ_ASSERT(cbs_[how]);
     357             : 
     358             :   // Now cancel so that we need to be re-armed. Note that
     359             :   // the re-arming probably happens in the callback we are
     360             :   // about to fire.
     361           0 :   cancel(how);
     362             : 
     363           0 :   cbs_[how](this, how, cb_args_[how]);
     364           0 : }
     365             : 
     366             : // NrSocket implementation
     367           0 : NS_IMPL_ISUPPORTS0(NrSocket)
     368             : 
     369             : 
     370             : // The nsASocket callbacks
     371           0 : void NrSocket::OnSocketReady(PRFileDesc *fd, int16_t outflags) {
     372           0 :   if (outflags & PR_POLL_READ & poll_flags())
     373           0 :     fire_callback(NR_ASYNC_WAIT_READ);
     374           0 :   if (outflags & PR_POLL_WRITE & poll_flags())
     375           0 :     fire_callback(NR_ASYNC_WAIT_WRITE);
     376           0 :   if (outflags & (PR_POLL_ERR | PR_POLL_NVAL | PR_POLL_HUP))
     377             :     // TODO: Bug 946423: how do we notify the upper layers about this?
     378           0 :     close();
     379           0 : }
     380             : 
     381           0 : void NrSocket::OnSocketDetached(PRFileDesc *fd) {
     382           0 :   r_log(LOG_GENERIC, LOG_DEBUG, "Socket %p detached", fd);
     383           0 : }
     384             : 
     385           0 : void NrSocket::IsLocal(bool *aIsLocal) {
     386             :   // TODO(jesup): better check? Does it matter? (likely no)
     387           0 :   *aIsLocal = false;
     388           0 : }
     389             : 
     390             : // async_event APIs
     391           0 : int NrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg,
     392             :                          char *function, int line) {
     393           0 :   int r = NrSocketBase::async_wait(how, cb, cb_arg, function, line);
     394             : 
     395           0 :   if (!r) {
     396           0 :     mPollFlags = poll_flags();
     397             :   }
     398             : 
     399           0 :   return r;
     400             : }
     401             : 
     402           0 : int NrSocket::cancel(int how) {
     403           0 :   int r = NrSocketBase::cancel(how);
     404             : 
     405           0 :   if (!r) {
     406           0 :     mPollFlags = poll_flags();
     407             :   }
     408             : 
     409           0 :   return r;
     410             : }
     411             : 
     412             : // Helper functions for addresses
     413           0 : static int nr_transport_addr_to_praddr(nr_transport_addr *addr,
     414             :   PRNetAddr *naddr)
     415             :   {
     416             :     int _status;
     417             : 
     418           0 :     memset(naddr, 0, sizeof(*naddr));
     419             : 
     420           0 :     switch(addr->protocol){
     421             :       case IPPROTO_TCP:
     422           0 :         break;
     423             :       case IPPROTO_UDP:
     424           0 :         break;
     425             :       default:
     426           0 :         ABORT(R_BAD_ARGS);
     427             :     }
     428             : 
     429           0 :     switch(addr->ip_version){
     430             :       case NR_IPV4:
     431           0 :         naddr->inet.family = PR_AF_INET;
     432           0 :         naddr->inet.port = addr->u.addr4.sin_port;
     433           0 :         naddr->inet.ip = addr->u.addr4.sin_addr.s_addr;
     434           0 :         break;
     435             :       case NR_IPV6:
     436           0 :         naddr->ipv6.family = PR_AF_INET6;
     437           0 :         naddr->ipv6.port = addr->u.addr6.sin6_port;
     438           0 :         naddr->ipv6.flowinfo = addr->u.addr6.sin6_flowinfo;
     439           0 :         memcpy(&naddr->ipv6.ip, &addr->u.addr6.sin6_addr, sizeof(in6_addr));
     440           0 :         naddr->ipv6.scope_id = addr->u.addr6.sin6_scope_id;
     441           0 :         break;
     442             :       default:
     443           0 :         ABORT(R_BAD_ARGS);
     444             :     }
     445             : 
     446           0 :     _status = 0;
     447             :   abort:
     448           0 :     return(_status);
     449             :   }
     450             : 
     451             : //XXX schien@mozilla.com: copy from PRNetAddrToNetAddr,
     452             : // should be removed after fix the link error in signaling_unittests
     453           0 : static int praddr_to_netaddr(const PRNetAddr *prAddr, net::NetAddr *addr)
     454             : {
     455             :   int _status;
     456             : 
     457           0 :   switch (prAddr->raw.family) {
     458             :     case PR_AF_INET:
     459           0 :       addr->inet.family = AF_INET;
     460           0 :       addr->inet.port = prAddr->inet.port;
     461           0 :       addr->inet.ip = prAddr->inet.ip;
     462           0 :       break;
     463             :     case PR_AF_INET6:
     464           0 :       addr->inet6.family = AF_INET6;
     465           0 :       addr->inet6.port = prAddr->ipv6.port;
     466           0 :       addr->inet6.flowinfo = prAddr->ipv6.flowinfo;
     467           0 :       memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8));
     468           0 :       addr->inet6.scope_id = prAddr->ipv6.scope_id;
     469           0 :       break;
     470             :     default:
     471           0 :       MOZ_ASSERT(false);
     472             :       ABORT(R_BAD_ARGS);
     473             :   }
     474             : 
     475           0 :   _status = 0;
     476             : abort:
     477           0 :   return(_status);
     478             : }
     479             : 
     480           0 : static int nr_transport_addr_to_netaddr(nr_transport_addr *addr,
     481             :   net::NetAddr *naddr)
     482             : {
     483             :   int r, _status;
     484             :   PRNetAddr praddr;
     485             : 
     486           0 :   if((r = nr_transport_addr_to_praddr(addr, &praddr))) {
     487           0 :     ABORT(r);
     488             :   }
     489             : 
     490           0 :   if((r = praddr_to_netaddr(&praddr, naddr))) {
     491           0 :     ABORT(r);
     492             :   }
     493             : 
     494           0 :   _status = 0;
     495             : abort:
     496           0 :   return(_status);
     497             : }
     498             : 
     499           0 : int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr,
     500             :                                  nr_transport_addr *addr, int protocol)
     501             :   {
     502             :     int _status;
     503             :     int r;
     504             : 
     505           0 :     switch(netaddr->raw.family) {
     506             :       case AF_INET:
     507           0 :         if ((r = nr_ip4_port_to_transport_addr(ntohl(netaddr->inet.ip),
     508           0 :                                                ntohs(netaddr->inet.port),
     509             :                                                protocol, addr)))
     510           0 :           ABORT(r);
     511           0 :         break;
     512             :       case AF_INET6:
     513           0 :         if ((r = nr_ip6_port_to_transport_addr((in6_addr *)&netaddr->inet6.ip.u8,
     514           0 :                                                ntohs(netaddr->inet6.port),
     515             :                                                protocol, addr)))
     516           0 :           ABORT(r);
     517           0 :         break;
     518             :       default:
     519           0 :         MOZ_ASSERT(false);
     520             :         ABORT(R_BAD_ARGS);
     521             :     }
     522           0 :     _status = 0;
     523             :   abort:
     524           0 :     return(_status);
     525             :   }
     526             : 
     527           0 : int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
     528             :                                 nr_transport_addr *addr, int protocol,
     529             :                                 int keep)
     530             :   {
     531             :     int _status;
     532             :     int r;
     533             :     struct sockaddr_in ip4;
     534             :     struct sockaddr_in6 ip6;
     535             : 
     536           0 :     switch(praddr->raw.family) {
     537             :       case PR_AF_INET:
     538           0 :         ip4.sin_family = PF_INET;
     539           0 :         ip4.sin_addr.s_addr = praddr->inet.ip;
     540           0 :         ip4.sin_port = praddr->inet.port;
     541           0 :         if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip4,
     542             :                                                protocol, keep,
     543             :                                                addr)))
     544           0 :           ABORT(r);
     545           0 :         break;
     546             :       case PR_AF_INET6:
     547           0 :         ip6.sin6_family = PF_INET6;
     548           0 :         ip6.sin6_port = praddr->ipv6.port;
     549           0 :         ip6.sin6_flowinfo = praddr->ipv6.flowinfo;
     550           0 :         memcpy(&ip6.sin6_addr, &praddr->ipv6.ip, sizeof(in6_addr));
     551           0 :         ip6.sin6_scope_id = praddr->ipv6.scope_id;
     552           0 :         if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip6,protocol,keep,addr)))
     553           0 :           ABORT(r);
     554           0 :         break;
     555             :       default:
     556           0 :         MOZ_ASSERT(false);
     557             :         ABORT(R_BAD_ARGS);
     558             :     }
     559             : 
     560           0 :     _status = 0;
     561             :  abort:
     562           0 :     return(_status);
     563             :   }
     564             : 
     565             : /*
     566             :  * nr_transport_addr_get_addrstring_and_port
     567             :  * convert nr_transport_addr to IP address string and port number
     568             :  */
     569           0 : int nr_transport_addr_get_addrstring_and_port(nr_transport_addr *addr,
     570             :                                               nsACString *host, int32_t *port) {
     571             :   int r, _status;
     572             :   char addr_string[64];
     573             : 
     574             :   // We cannot directly use |nr_transport_addr.as_string| because it contains
     575             :   // more than ip address, therefore, we need to explicity convert it
     576             :   // from |nr_transport_addr_get_addrstring|.
     577           0 :   if ((r=nr_transport_addr_get_addrstring(addr, addr_string, sizeof(addr_string)))) {
     578           0 :     ABORT(r);
     579             :   }
     580             : 
     581           0 :   if ((r=nr_transport_addr_get_port(addr, port))) {
     582           0 :     ABORT(r);
     583             :   }
     584             : 
     585           0 :   *host = addr_string;
     586             : 
     587           0 :   _status = 0;
     588             : abort:
     589           0 :   return(_status);
     590             : }
     591             : 
     592             : // nr_socket APIs (as member functions)
     593           0 : int NrSocket::create(nr_transport_addr *addr) {
     594             :   int r,_status;
     595             : 
     596             :   PRStatus status;
     597             :   PRNetAddr naddr;
     598             : 
     599             :   nsresult rv;
     600             :   nsCOMPtr<nsISocketTransportService> stservice =
     601           0 :       do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
     602             : 
     603           0 :   if (!NS_SUCCEEDED(rv)) {
     604           0 :     ABORT(R_INTERNAL);
     605             :   }
     606             : 
     607           0 :   if((r=nr_transport_addr_to_praddr(addr, &naddr)))
     608           0 :     ABORT(r);
     609             : 
     610           0 :   switch (addr->protocol) {
     611             :     case IPPROTO_UDP:
     612           0 :       if (!(fd_ = PR_OpenUDPSocket(naddr.raw.family))) {
     613           0 :         r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create UDP socket, "
     614           0 :               "family=%d, err=%d", naddr.raw.family, PR_GetError());
     615           0 :         ABORT(R_INTERNAL);
     616             :       }
     617             : #ifdef XP_WIN
     618             :       if (!mozilla::IsWin8OrLater()) {
     619             :         // Increase default send and receive buffer sizes on <= Win7 to be able to
     620             :         // receive and send an unpaced HD (>= 720p = 1280x720 - I Frame ~ 21K size)
     621             :         // stream without losing packets.
     622             :         // Manual testing showed that 100K buffer size was not enough and the
     623             :         // packet loss dis-appeared with 256K buffer size.
     624             :         // See bug 1252769 for future improvements of this.
     625             :         PRSize min_buffer_size = 256 * 1024;
     626             :         PRSocketOptionData opt_rcvbuf;
     627             :         opt_rcvbuf.option = PR_SockOpt_RecvBufferSize;
     628             :         if ((status = PR_GetSocketOption(fd_, &opt_rcvbuf)) == PR_SUCCESS) {
     629             :           if (opt_rcvbuf.value.recv_buffer_size < min_buffer_size) {
     630             :             opt_rcvbuf.value.recv_buffer_size = min_buffer_size;
     631             :             if ((status = PR_SetSocketOption(fd_, &opt_rcvbuf)) != PR_SUCCESS) {
     632             :               r_log(LOG_GENERIC, LOG_CRIT,
     633             :                 "Couldn't set socket receive buffer size: %d", status);
     634             :             }
     635             :           } else {
     636             :             r_log(LOG_GENERIC, LOG_INFO,
     637             :               "Socket receive buffer size is already: %d",
     638             :               opt_rcvbuf.value.recv_buffer_size);
     639             :           }
     640             :         } else {
     641             :           r_log(LOG_GENERIC, LOG_CRIT,
     642             :             "Couldn't get socket receive buffer size: %d", status);
     643             :         }
     644             :         PRSocketOptionData opt_sndbuf;
     645             :         opt_sndbuf.option = PR_SockOpt_SendBufferSize;
     646             :         if ((status = PR_GetSocketOption(fd_, &opt_sndbuf)) == PR_SUCCESS) {
     647             :           if (opt_sndbuf.value.recv_buffer_size < min_buffer_size) {
     648             :             opt_sndbuf.value.recv_buffer_size = min_buffer_size;
     649             :             if ((status = PR_SetSocketOption(fd_, &opt_sndbuf)) != PR_SUCCESS) {
     650             :               r_log(LOG_GENERIC, LOG_CRIT,
     651             :                 "Couldn't set socket send buffer size: %d", status);
     652             :             }
     653             :           } else {
     654             :             r_log(LOG_GENERIC, LOG_INFO,
     655             :               "Socket send buffer size is already: %d",
     656             :               opt_sndbuf.value.recv_buffer_size);
     657             :           }
     658             :         } else {
     659             :           r_log(LOG_GENERIC, LOG_CRIT,
     660             :             "Couldn't get socket send buffer size: %d", status);
     661             :         }
     662             :       }
     663             : #endif
     664           0 :       break;
     665             :     case IPPROTO_TCP:
     666             :       // TODO: Add TLS layer with nsISocketProviderService?
     667           0 :       if (my_addr_.tls_host[0] != '\0')
     668           0 :         ABORT(R_INTERNAL);
     669             : 
     670           0 :       if (!(fd_ = PR_OpenTCPSocket(naddr.raw.family))) {
     671           0 :         r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create TCP socket, "
     672           0 :               "family=%d, err=%d", naddr.raw.family, PR_GetError());
     673           0 :         ABORT(R_INTERNAL);
     674             :       }
     675             :       // Set ReuseAddr for TCP sockets to enable having several
     676             :       // sockets bound to same local IP and port
     677             :       PRSocketOptionData opt_reuseaddr;
     678           0 :       opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
     679           0 :       opt_reuseaddr.value.reuse_addr = PR_TRUE;
     680           0 :       status = PR_SetSocketOption(fd_, &opt_reuseaddr);
     681           0 :       if (status != PR_SUCCESS) {
     682             :         r_log(LOG_GENERIC, LOG_CRIT,
     683           0 :           "Couldn't set reuse addr socket option: %d", status);
     684           0 :         ABORT(R_INTERNAL);
     685             :       }
     686             :       // And also set ReusePort for platforms supporting this socket option
     687             :       PRSocketOptionData opt_reuseport;
     688           0 :       opt_reuseport.option = PR_SockOpt_Reuseport;
     689           0 :       opt_reuseport.value.reuse_port = PR_TRUE;
     690           0 :       status = PR_SetSocketOption(fd_, &opt_reuseport);
     691           0 :       if (status != PR_SUCCESS) {
     692           0 :         if (PR_GetError() != PR_OPERATION_NOT_SUPPORTED_ERROR) {
     693             :           r_log(LOG_GENERIC, LOG_CRIT,
     694           0 :             "Couldn't set reuse port socket option: %d", status);
     695           0 :           ABORT(R_INTERNAL);
     696             :         }
     697             :       }
     698             :       // Try to speedup packet delivery by disabling TCP Nagle
     699             :       PRSocketOptionData opt_nodelay;
     700           0 :       opt_nodelay.option = PR_SockOpt_NoDelay;
     701           0 :       opt_nodelay.value.no_delay = PR_TRUE;
     702           0 :       status = PR_SetSocketOption(fd_, &opt_nodelay);
     703           0 :       if (status != PR_SUCCESS) {
     704             :         r_log(LOG_GENERIC, LOG_WARNING,
     705           0 :           "Couldn't set Nodelay socket option: %d", status);
     706             :       }
     707           0 :       break;
     708             :     default:
     709           0 :       ABORT(R_INTERNAL);
     710             :   }
     711             : 
     712           0 :   status = PR_Bind(fd_, &naddr);
     713           0 :   if (status != PR_SUCCESS) {
     714           0 :     r_log(LOG_GENERIC,LOG_CRIT,"Couldn't bind socket to address %s",
     715           0 :           addr->as_string);
     716           0 :     ABORT(R_INTERNAL);
     717             :   }
     718             : 
     719           0 :   r_log(LOG_GENERIC,LOG_DEBUG,"Creating socket %p with addr %s",
     720           0 :         fd_, addr->as_string);
     721           0 :   nr_transport_addr_copy(&my_addr_,addr);
     722             : 
     723             :   /* If we have a wildcard port, patch up the addr */
     724           0 :   if(nr_transport_addr_is_wildcard(addr)){
     725           0 :     status = PR_GetSockName(fd_, &naddr);
     726           0 :     if (status != PR_SUCCESS){
     727           0 :       r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket");
     728           0 :       ABORT(R_INTERNAL);
     729             :     }
     730             : 
     731           0 :     if((r=nr_praddr_to_transport_addr(&naddr,&my_addr_,addr->protocol,1)))
     732           0 :       ABORT(r);
     733             :   }
     734             : 
     735             : 
     736             :   // Set nonblocking
     737             :   PRSocketOptionData opt_nonblock;
     738           0 :   opt_nonblock.option = PR_SockOpt_Nonblocking;
     739           0 :   opt_nonblock.value.non_blocking = PR_TRUE;
     740           0 :   status = PR_SetSocketOption(fd_, &opt_nonblock);
     741           0 :   if (status != PR_SUCCESS) {
     742           0 :     r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking");
     743           0 :     ABORT(R_INTERNAL);
     744             :   }
     745             : 
     746             :   // Remember our thread.
     747           0 :   ststhread_ = do_QueryInterface(stservice, &rv);
     748           0 :   if (!NS_SUCCEEDED(rv))
     749           0 :     ABORT(R_INTERNAL);
     750             : 
     751             :   // Finally, register with the STS
     752           0 :   rv = stservice->AttachSocket(fd_, this);
     753           0 :   if (!NS_SUCCEEDED(rv)) {
     754           0 :     r_log(LOG_GENERIC, LOG_CRIT, "Couldn't attach socket to STS, rv=%u",
     755           0 :           static_cast<unsigned>(rv));
     756           0 :     ABORT(R_INTERNAL);
     757             :   }
     758             : 
     759           0 :   _status = 0;
     760             : 
     761             : abort:
     762           0 :   return(_status);
     763             : }
     764             : 
     765           0 : static int ShouldDrop(size_t len) {
     766             :   // Global rate limiting for stun requests, to mitigate the ice hammer DoS
     767             :   // (see http://tools.ietf.org/html/draft-thomson-mmusic-ice-webrtc)
     768             : 
     769             :   // Tolerate rate of 8k/sec, for one second.
     770           0 :   static SimpleTokenBucket burst(16384*1, 16384);
     771             :   // Tolerate rate of 7.2k/sec over twenty seconds.
     772           0 :   static SimpleTokenBucket sustained(7372*20, 7372);
     773             : 
     774             :   // Check number of tokens in each bucket.
     775           0 :   if (burst.getTokens(UINT32_MAX) < len) {
     776             :     r_log(LOG_GENERIC, LOG_ERR,
     777           0 :                "Short term global rate limit for STUN requests exceeded.");
     778             : #ifdef MOZILLA_INTERNAL_API
     779           0 :     nr_socket_short_term_violation_time = TimeStamp::Now();
     780             : #endif
     781             : 
     782             : // Bug 1013007
     783             : #if !EARLY_BETA_OR_EARLIER
     784             :     return R_WOULDBLOCK;
     785             : #else
     786           0 :     MOZ_ASSERT(false,
     787             :                "Short term global rate limit for STUN requests exceeded. Go "
     788             :                "bug bcampen@mozilla.com if you weren't intentionally "
     789             :                "spamming ICE candidates, or don't know what that means.");
     790             : #endif
     791             :   }
     792             : 
     793           0 :   if (sustained.getTokens(UINT32_MAX) < len) {
     794             :     r_log(LOG_GENERIC, LOG_ERR,
     795           0 :                "Long term global rate limit for STUN requests exceeded.");
     796             : #ifdef MOZILLA_INTERNAL_API
     797           0 :     nr_socket_long_term_violation_time = TimeStamp::Now();
     798             : #endif
     799             : // Bug 1013007
     800             : #if !EARLY_BETA_OR_EARLIER
     801             :     return R_WOULDBLOCK;
     802             : #else
     803           0 :     MOZ_ASSERT(false,
     804             :                "Long term global rate limit for STUN requests exceeded. Go "
     805             :                "bug bcampen@mozilla.com if you weren't intentionally "
     806             :                "spamming ICE candidates, or don't know what that means.");
     807             : #endif
     808             :   }
     809             : 
     810             :   // Take len tokens from both buckets.
     811             :   // (not threadsafe, but no problem since this is only called from STS)
     812           0 :   burst.getTokens(len);
     813           0 :   sustained.getTokens(len);
     814           0 :   return 0;
     815             : }
     816             : 
     817             : // This should be called on the STS thread.
     818           0 : int NrSocket::sendto(const void *msg, size_t len,
     819             :                      int flags, nr_transport_addr *to) {
     820           0 :   ASSERT_ON_THREAD(ststhread_);
     821             :   int r,_status;
     822             :   PRNetAddr naddr;
     823             :   int32_t status;
     824             : 
     825           0 :   if ((r=nr_transport_addr_to_praddr(to, &naddr)))
     826           0 :     ABORT(r);
     827             : 
     828           0 :   if(fd_==nullptr)
     829           0 :     ABORT(R_EOD);
     830             : 
     831           0 :   if (nr_is_stun_request_message((UCHAR*)msg, len) && ShouldDrop(len)) {
     832           0 :     ABORT(R_WOULDBLOCK);
     833             :   }
     834             : 
     835             :   // TODO: Convert flags?
     836           0 :   status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT);
     837           0 :   if (status < 0 || (size_t)status != len) {
     838           0 :     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
     839           0 :       ABORT(R_WOULDBLOCK);
     840             : 
     841           0 :     r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s: %d",
     842           0 :           to->as_string, PR_GetError());
     843           0 :     ABORT(R_IO_ERROR);
     844             :   }
     845             : 
     846           0 :   _status = 0;
     847             : abort:
     848           0 :   return(_status);
     849             : }
     850             : 
     851           0 : int NrSocket::recvfrom(void * buf, size_t maxlen,
     852             :                        size_t *len, int flags,
     853             :                        nr_transport_addr *from) {
     854           0 :   ASSERT_ON_THREAD(ststhread_);
     855             :   int r,_status;
     856             :   PRNetAddr nfrom;
     857             :   int32_t status;
     858             : 
     859           0 :   status = PR_RecvFrom(fd_, buf, maxlen, flags, &nfrom, PR_INTERVAL_NO_WAIT);
     860           0 :   if (status <= 0) {
     861           0 :     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
     862           0 :       ABORT(R_WOULDBLOCK);
     863           0 :     r_log(LOG_GENERIC, LOG_INFO, "Error in recvfrom: %d", (int)PR_GetError());
     864           0 :     ABORT(R_IO_ERROR);
     865             :   }
     866           0 :   *len = status;
     867             : 
     868           0 :   if((r=nr_praddr_to_transport_addr(&nfrom,from,my_addr_.protocol,0)))
     869           0 :     ABORT(r);
     870             : 
     871             :   //r_log(LOG_GENERIC,LOG_DEBUG,"Read %d bytes from %s",*len,addr->as_string);
     872             : 
     873           0 :   _status = 0;
     874             : abort:
     875           0 :   return(_status);
     876             : }
     877             : 
     878           0 : int NrSocket::getaddr(nr_transport_addr *addrp) {
     879           0 :   ASSERT_ON_THREAD(ststhread_);
     880           0 :   return nr_transport_addr_copy(addrp, &my_addr_);
     881             : }
     882             : 
     883             : // Close the socket so that the STS will detach and then kill it
     884           0 : void NrSocket::close() {
     885           0 :   ASSERT_ON_THREAD(ststhread_);
     886           0 :   mCondition = NS_BASE_STREAM_CLOSED;
     887           0 : }
     888             : 
     889             : 
     890           0 : int NrSocket::connect(nr_transport_addr *addr) {
     891           0 :   ASSERT_ON_THREAD(ststhread_);
     892             :   int r,_status;
     893             :   PRNetAddr naddr;
     894             :   int32_t connect_status, getsockname_status;
     895             : 
     896           0 :   if ((r=nr_transport_addr_to_praddr(addr, &naddr)))
     897           0 :     ABORT(r);
     898             : 
     899           0 :   if(!fd_)
     900           0 :     ABORT(R_EOD);
     901             : 
     902             :   // Note: this just means we tried to connect, not that we
     903             :   // are actually live.
     904           0 :   connect_invoked_ = true;
     905           0 :   connect_status = PR_Connect(fd_, &naddr, PR_INTERVAL_NO_WAIT);
     906           0 :   if (connect_status != PR_SUCCESS) {
     907           0 :     if (PR_GetError() != PR_IN_PROGRESS_ERROR)
     908           0 :       ABORT(R_IO_ERROR);
     909             :   }
     910             : 
     911             :   // If our local address is wildcard, then fill in the
     912             :   // address now.
     913           0 :   if(nr_transport_addr_is_wildcard(&my_addr_)){
     914           0 :     getsockname_status = PR_GetSockName(fd_, &naddr);
     915           0 :     if (getsockname_status != PR_SUCCESS){
     916           0 :       r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket");
     917           0 :       ABORT(R_INTERNAL);
     918             :     }
     919             : 
     920           0 :     if((r=nr_praddr_to_transport_addr(&naddr,&my_addr_,addr->protocol,1)))
     921           0 :       ABORT(r);
     922             :   }
     923             : 
     924             :   // Now return the WOULDBLOCK if needed.
     925           0 :   if (connect_status != PR_SUCCESS) {
     926           0 :     ABORT(R_WOULDBLOCK);
     927             :   }
     928             : 
     929           0 :   _status = 0;
     930             : abort:
     931           0 :   return(_status);
     932             : }
     933             : 
     934             : 
     935           0 : int NrSocket::write(const void *msg, size_t len, size_t *written) {
     936           0 :   ASSERT_ON_THREAD(ststhread_);
     937             :   int _status;
     938             :   int32_t status;
     939             : 
     940           0 :   if (!connect_invoked_)
     941           0 :     ABORT(R_FAILED);
     942             : 
     943           0 :   status = PR_Write(fd_, msg, len);
     944           0 :   if (status < 0) {
     945           0 :     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
     946           0 :       ABORT(R_WOULDBLOCK);
     947           0 :     r_log(LOG_GENERIC, LOG_INFO, "Error in write");
     948           0 :     ABORT(R_IO_ERROR);
     949             :   }
     950             : 
     951           0 :   *written = status;
     952             : 
     953           0 :   _status = 0;
     954             : abort:
     955           0 :   return _status;
     956             : }
     957             : 
     958           0 : int NrSocket::read(void* buf, size_t maxlen, size_t *len) {
     959           0 :   ASSERT_ON_THREAD(ststhread_);
     960             :   int _status;
     961             :   int32_t status;
     962             : 
     963           0 :   if (!connect_invoked_)
     964           0 :     ABORT(R_FAILED);
     965             : 
     966           0 :   status = PR_Read(fd_, buf, maxlen);
     967           0 :   if (status < 0) {
     968           0 :     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
     969           0 :       ABORT(R_WOULDBLOCK);
     970           0 :     r_log(LOG_GENERIC, LOG_INFO, "Error in read");
     971           0 :     ABORT(R_IO_ERROR);
     972             :   }
     973           0 :   if (status == 0)
     974           0 :     ABORT(R_EOD);
     975             : 
     976           0 :   *len = (size_t)status;  // Guaranteed to be > 0
     977           0 :   _status = 0;
     978             : abort:
     979           0 :   return(_status);
     980             : }
     981             : 
     982           0 : int NrSocket::listen(int backlog) {
     983           0 :   ASSERT_ON_THREAD(ststhread_);
     984             :   int32_t status;
     985             :   int _status;
     986             : 
     987           0 :   assert(fd_);
     988           0 :   status = PR_Listen(fd_, backlog);
     989           0 :   if (status != PR_SUCCESS) {
     990           0 :     r_log(LOG_GENERIC, LOG_CRIT, "%s: PR_GetError() == %d",
     991           0 :           __FUNCTION__, PR_GetError());
     992           0 :     ABORT(R_IO_ERROR);
     993             :   }
     994             : 
     995           0 :   _status = 0;
     996             : abort:
     997           0 :   return(_status);
     998             : }
     999             : 
    1000           0 : int NrSocket::accept(nr_transport_addr *addrp, nr_socket **sockp) {
    1001           0 :   ASSERT_ON_THREAD(ststhread_);
    1002             :   int _status, r;
    1003             :   PRStatus status;
    1004             :   PRFileDesc *prfd;
    1005             :   PRNetAddr nfrom;
    1006           0 :   NrSocket *sock=nullptr;
    1007             :   nsresult rv;
    1008             :   PRSocketOptionData opt_nonblock, opt_nodelay;
    1009             :   nsCOMPtr<nsISocketTransportService> stservice =
    1010           0 :       do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    1011             : 
    1012           0 :   if (NS_FAILED(rv)) {
    1013           0 :     ABORT(R_INTERNAL);
    1014             :   }
    1015             : 
    1016           0 :   if(!fd_)
    1017           0 :     ABORT(R_EOD);
    1018             : 
    1019           0 :   prfd = PR_Accept(fd_, &nfrom, PR_INTERVAL_NO_WAIT);
    1020             : 
    1021           0 :   if (!prfd) {
    1022           0 :     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
    1023           0 :       ABORT(R_WOULDBLOCK);
    1024             : 
    1025           0 :     ABORT(R_IO_ERROR);
    1026             :   }
    1027             : 
    1028           0 :   sock = new NrSocket();
    1029             : 
    1030           0 :   sock->fd_=prfd;
    1031           0 :   nr_transport_addr_copy(&sock->my_addr_, &my_addr_);
    1032             : 
    1033           0 :   if((r=nr_praddr_to_transport_addr(&nfrom, addrp, my_addr_.protocol, 0)))
    1034           0 :     ABORT(r);
    1035             : 
    1036             :   // Set nonblocking
    1037           0 :   opt_nonblock.option = PR_SockOpt_Nonblocking;
    1038           0 :   opt_nonblock.value.non_blocking = PR_TRUE;
    1039           0 :   status = PR_SetSocketOption(prfd, &opt_nonblock);
    1040           0 :   if (status != PR_SUCCESS) {
    1041             :     r_log(LOG_GENERIC, LOG_CRIT,
    1042           0 :       "Failed to make accepted socket nonblocking: %d", status);
    1043           0 :     ABORT(R_INTERNAL);
    1044             :   }
    1045             :   // Disable TCP Nagle
    1046           0 :   opt_nodelay.option = PR_SockOpt_NoDelay;
    1047           0 :   opt_nodelay.value.no_delay = PR_TRUE;
    1048           0 :   status = PR_SetSocketOption(prfd, &opt_nodelay);
    1049           0 :   if (status != PR_SUCCESS) {
    1050             :     r_log(LOG_GENERIC, LOG_WARNING,
    1051           0 :       "Failed to set Nodelay on accepted socket: %d", status);
    1052             :   }
    1053             : 
    1054             :   // Should fail only with OOM
    1055           0 :   if ((r=nr_socket_create_int(static_cast<void *>(sock), sock->vtbl(), sockp)))
    1056           0 :     ABORT(r);
    1057             : 
    1058             :   // Remember our thread.
    1059           0 :   sock->ststhread_ = do_QueryInterface(stservice, &rv);
    1060           0 :   if (NS_FAILED(rv))
    1061           0 :     ABORT(R_INTERNAL);
    1062             : 
    1063             :   // Finally, register with the STS
    1064           0 :   rv = stservice->AttachSocket(prfd, sock);
    1065           0 :   if (NS_FAILED(rv)) {
    1066           0 :     ABORT(R_INTERNAL);
    1067             :   }
    1068             : 
    1069           0 :   sock->connect_invoked_ = true;
    1070             : 
    1071             :   // Add a reference so that we can delete it in destroy()
    1072           0 :   sock->AddRef();
    1073           0 :   _status = 0;
    1074             : abort:
    1075           0 :   if (_status) {
    1076           0 :     delete sock;
    1077             :   }
    1078             : 
    1079           0 :   return(_status);
    1080             : }
    1081             : 
    1082           0 : NS_IMPL_ISUPPORTS(NrUdpSocketIpcProxy, nsIUDPSocketInternal)
    1083             : 
    1084             : nsresult
    1085           0 : NrUdpSocketIpcProxy::Init(const RefPtr<NrUdpSocketIpc>& socket)
    1086             : {
    1087             :   nsresult rv;
    1088           0 :   sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    1089           0 :   if (NS_FAILED(rv)) {
    1090           0 :     MOZ_ASSERT(false, "Failed to get STS thread");
    1091             :     return rv;
    1092             :   }
    1093             : 
    1094           0 :   socket_ = socket;
    1095           0 :   return NS_OK;
    1096             : }
    1097             : 
    1098           0 : NrUdpSocketIpcProxy::~NrUdpSocketIpcProxy()
    1099             : {
    1100             :   // Send our ref to STS to be released
    1101           0 :   RUN_ON_THREAD(sts_thread_,
    1102           0 :                 mozilla::WrapRelease(socket_.forget()),
    1103           0 :                 NS_DISPATCH_NORMAL);
    1104           0 : }
    1105             : 
    1106             : // IUDPSocketInternal interfaces
    1107             : // callback while error happened in UDP socket operation
    1108           0 : NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerError(const nsACString &message,
    1109             :                                                      const nsACString &filename,
    1110             :                                                      uint32_t line_number) {
    1111           0 :   return socket_->CallListenerError(message, filename, line_number);
    1112             : }
    1113             : 
    1114             : // callback while receiving UDP packet
    1115           0 : NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerReceivedData(const nsACString &host,
    1116             :                                                             uint16_t port,
    1117             :                                                             const uint8_t *data,
    1118             :                                                             uint32_t data_length) {
    1119           0 :   return socket_->CallListenerReceivedData(host, port, data, data_length);
    1120             : }
    1121             : 
    1122             : // callback while UDP socket is opened
    1123           0 : NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerOpened() {
    1124           0 :   return socket_->CallListenerOpened();
    1125             : }
    1126             : 
    1127             : // callback while UDP socket is connected
    1128           0 : NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerConnected() {
    1129           0 :   return socket_->CallListenerConnected();
    1130             : }
    1131             : 
    1132             : // callback while UDP socket is closed
    1133           0 : NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerClosed() {
    1134           0 :   return socket_->CallListenerClosed();
    1135             : }
    1136             : 
    1137             : // NrUdpSocketIpc Implementation
    1138           0 : NrUdpSocketIpc::NrUdpSocketIpc()
    1139           0 :   : NrSocketIpc(GetIOThreadAndAddUse_s()),
    1140             :     monitor_("NrUdpSocketIpc"),
    1141             :     err_(false),
    1142           0 :     state_(NR_INIT) {
    1143           0 : }
    1144             : 
    1145           0 : NrUdpSocketIpc::~NrUdpSocketIpc()
    1146             : {
    1147             :   // also guarantees socket_child_ is released from the io_thread, and
    1148             :   // tells the SingletonThreadHolder we're done with it
    1149             : 
    1150             : #if defined(MOZILLA_INTERNAL_API)
    1151             :   // close(), but transfer the socket_child_ reference to die as well
    1152           0 :   RUN_ON_THREAD(io_thread_,
    1153           0 :                 mozilla::WrapRunnableNM(&NrUdpSocketIpc::release_child_i,
    1154           0 :                                         socket_child_.forget().take()),
    1155           0 :                 NS_DISPATCH_NORMAL);
    1156             :   // This may shut down the io_thread_, but it should spin the event loop so
    1157             :   // the above runnable happens.
    1158           0 :   sThread->ReleaseUse();
    1159             : #endif
    1160           0 : }
    1161             : 
    1162             : // IUDPSocketInternal interfaces
    1163             : // callback while error happened in UDP socket operation
    1164           0 : NS_IMETHODIMP NrUdpSocketIpc::CallListenerError(const nsACString &message,
    1165             :                                                 const nsACString &filename,
    1166             :                                                 uint32_t line_number) {
    1167           0 :   ASSERT_ON_THREAD(io_thread_);
    1168             : 
    1169           0 :   r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d this=%p",
    1170           0 :         message.BeginReading(), filename.BeginReading(), line_number, (void*) this );
    1171             : 
    1172           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1173           0 :   err_ = true;
    1174           0 :   monitor_.NotifyAll();
    1175             : 
    1176           0 :   return NS_OK;
    1177             : }
    1178             : 
    1179             : // callback while receiving UDP packet
    1180           0 : NS_IMETHODIMP NrUdpSocketIpc::CallListenerReceivedData(const nsACString &host,
    1181             :                                                        uint16_t port,
    1182             :                                                        const uint8_t *data,
    1183             :                                                        uint32_t data_length) {
    1184           0 :   ASSERT_ON_THREAD(io_thread_);
    1185             : 
    1186             :   PRNetAddr addr;
    1187           0 :   memset(&addr, 0, sizeof(addr));
    1188             : 
    1189             :   {
    1190           0 :     ReentrantMonitorAutoEnter mon(monitor_);
    1191             : 
    1192           0 :     if (PR_SUCCESS != PR_StringToNetAddr(host.BeginReading(), &addr)) {
    1193           0 :       err_ = true;
    1194           0 :       MOZ_ASSERT(false, "Failed to convert remote host to PRNetAddr");
    1195             :       return NS_OK;
    1196             :     }
    1197             : 
    1198             :     // Use PR_IpAddrNull to avoid address being reset to 0.
    1199           0 :     if (PR_SUCCESS != PR_SetNetAddr(PR_IpAddrNull, addr.raw.family, port, &addr)) {
    1200           0 :       err_ = true;
    1201           0 :       MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
    1202             :       return NS_OK;
    1203             :     }
    1204             :   }
    1205             : 
    1206           0 :   nsAutoPtr<DataBuffer> buf(new DataBuffer(data, data_length));
    1207           0 :   RefPtr<nr_udp_message> msg(new nr_udp_message(addr, buf));
    1208             : 
    1209           0 :   RUN_ON_THREAD(sts_thread_,
    1210           0 :                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
    1211             :                                       &NrUdpSocketIpc::recv_callback_s,
    1212             :                                       msg),
    1213           0 :                 NS_DISPATCH_NORMAL);
    1214           0 :   return NS_OK;
    1215             : }
    1216             : 
    1217           0 : nsresult NrUdpSocketIpc::SetAddress() {
    1218             :   uint16_t port;
    1219           0 :   if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
    1220           0 :     err_ = true;
    1221           0 :     MOZ_ASSERT(false, "Failed to get local port");
    1222             :     return NS_OK;
    1223             :   }
    1224             : 
    1225           0 :   nsAutoCString address;
    1226           0 :   if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
    1227           0 :     err_ = true;
    1228           0 :     MOZ_ASSERT(false, "Failed to get local address");
    1229             :     return NS_OK;
    1230             :   }
    1231             : 
    1232             :   PRNetAddr praddr;
    1233           0 :   if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
    1234           0 :     err_ = true;
    1235           0 :     MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
    1236             :     return NS_OK;
    1237             :   }
    1238             : 
    1239           0 :   if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
    1240           0 :     err_ = true;
    1241           0 :     MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
    1242             :     return NS_OK;
    1243             :   }
    1244             : 
    1245             :   nr_transport_addr expected_addr;
    1246           0 :   if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
    1247           0 :     err_ = true;
    1248           0 :     MOZ_ASSERT(false, "Failed to copy my_addr_");
    1249             :   }
    1250             : 
    1251           0 :   if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
    1252           0 :     err_ = true;
    1253           0 :     MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
    1254             :   }
    1255             : 
    1256           0 :   if (!nr_transport_addr_is_wildcard(&expected_addr) &&
    1257           0 :       nr_transport_addr_cmp(&expected_addr, &my_addr_,
    1258             :                             NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
    1259           0 :     err_ = true;
    1260           0 :     MOZ_ASSERT(false, "Address of opened socket is not expected");
    1261             :   }
    1262             : 
    1263           0 :   return NS_OK;
    1264             : }
    1265             : 
    1266             : // callback while UDP socket is opened
    1267           0 : NS_IMETHODIMP NrUdpSocketIpc::CallListenerOpened() {
    1268           0 :   ASSERT_ON_THREAD(io_thread_);
    1269           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1270             : 
    1271           0 :   r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket opened this=%p", (void*) this);
    1272           0 :   nsresult rv = SetAddress();
    1273           0 :   if (NS_FAILED(rv)) {
    1274           0 :     return rv;
    1275             :   }
    1276             : 
    1277           0 :   mon.NotifyAll();
    1278             : 
    1279           0 :   return NS_OK;
    1280             : }
    1281             : 
    1282             : // callback while UDP socket is connected
    1283           0 : NS_IMETHODIMP NrUdpSocketIpc::CallListenerConnected() {
    1284           0 :   ASSERT_ON_THREAD(io_thread_);
    1285             : 
    1286           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1287             : 
    1288           0 :   r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket connected this=%p", (void*) this);
    1289           0 :   MOZ_ASSERT(state_ == NR_CONNECTED);
    1290             : 
    1291           0 :   nsresult rv = SetAddress();
    1292           0 :   if (NS_FAILED(rv)) {
    1293           0 :     mon.NotifyAll();
    1294           0 :     return rv;
    1295             :   }
    1296             : 
    1297           0 :   r_log(LOG_GENERIC, LOG_INFO, "Exit UDP socket connected");
    1298           0 :   mon.NotifyAll();
    1299             : 
    1300           0 :   return NS_OK;
    1301             : }
    1302             : 
    1303             : // callback while UDP socket is closed
    1304           0 : NS_IMETHODIMP NrUdpSocketIpc::CallListenerClosed() {
    1305           0 :   ASSERT_ON_THREAD(io_thread_);
    1306             : 
    1307           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1308             : 
    1309           0 :   r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket closed this=%p", (void*) this);
    1310           0 :   MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
    1311           0 :   state_ = NR_CLOSED;
    1312             : 
    1313           0 :   return NS_OK;
    1314             : }
    1315             : 
    1316             : //
    1317             : // NrSocketBase methods.
    1318             : //
    1319           0 : int NrUdpSocketIpc::create(nr_transport_addr *addr) {
    1320           0 :   ASSERT_ON_THREAD(sts_thread_);
    1321             : 
    1322             :   int r, _status;
    1323             :   nsresult rv;
    1324             :   int32_t port;
    1325           0 :   nsCString host;
    1326             : 
    1327           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1328             : 
    1329           0 :   if (state_ != NR_INIT) {
    1330           0 :     ABORT(R_INTERNAL);
    1331             :   }
    1332             : 
    1333           0 :   sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    1334           0 :   if (NS_FAILED(rv)) {
    1335           0 :     MOZ_ASSERT(false, "Failed to get STS thread");
    1336             :     ABORT(R_INTERNAL);
    1337             :   }
    1338             : 
    1339           0 :   if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
    1340           0 :     ABORT(r);
    1341             :   }
    1342             : 
    1343             :   // wildcard address will be resolved at NrUdpSocketIpc::CallListenerVoid
    1344           0 :   if ((r=nr_transport_addr_copy(&my_addr_, addr))) {
    1345           0 :     ABORT(r);
    1346             :   }
    1347             : 
    1348           0 :   state_ = NR_CONNECTING;
    1349             : 
    1350           0 :   RUN_ON_THREAD(io_thread_,
    1351           0 :                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
    1352             :                                       &NrUdpSocketIpc::create_i,
    1353             :                                       host, static_cast<uint16_t>(port)),
    1354           0 :                 NS_DISPATCH_NORMAL);
    1355             : 
    1356             :   // Wait until socket creation complete.
    1357           0 :   mon.Wait();
    1358             : 
    1359           0 :   if (err_) {
    1360           0 :     close();
    1361           0 :     ABORT(R_INTERNAL);
    1362             :   }
    1363             : 
    1364           0 :   state_ = NR_CONNECTED;
    1365             : 
    1366           0 :   _status = 0;
    1367             : abort:
    1368           0 :   return(_status);
    1369             : }
    1370             : 
    1371           0 : int NrUdpSocketIpc::sendto(const void *msg, size_t len, int flags,
    1372             :                         nr_transport_addr *to) {
    1373           0 :   ASSERT_ON_THREAD(sts_thread_);
    1374             : 
    1375           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1376             : 
    1377             :   //If send err happened before, simply return the error.
    1378           0 :   if (err_) {
    1379           0 :     return R_IO_ERROR;
    1380             :   }
    1381             : 
    1382           0 :   if (state_ != NR_CONNECTED) {
    1383           0 :     return R_INTERNAL;
    1384             :   }
    1385             : 
    1386             :   int r;
    1387             :   net::NetAddr addr;
    1388           0 :   if ((r=nr_transport_addr_to_netaddr(to, &addr))) {
    1389           0 :     return r;
    1390             :   }
    1391             : 
    1392           0 :   if (nr_is_stun_request_message((UCHAR*)msg, len) && ShouldDrop(len)) {
    1393           0 :     return R_WOULDBLOCK;
    1394             :   }
    1395             : 
    1396           0 :   nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t*>(msg), len));
    1397             : 
    1398           0 :   RUN_ON_THREAD(io_thread_,
    1399           0 :                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
    1400             :                                       &NrUdpSocketIpc::sendto_i,
    1401             :                                       addr, buf),
    1402           0 :                 NS_DISPATCH_NORMAL);
    1403           0 :   return 0;
    1404             : }
    1405             : 
    1406           0 : void NrUdpSocketIpc::close() {
    1407           0 :   r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::close()");
    1408             : 
    1409           0 :   ASSERT_ON_THREAD(sts_thread_);
    1410             : 
    1411           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1412           0 :   state_ = NR_CLOSING;
    1413             : 
    1414           0 :   RUN_ON_THREAD(io_thread_,
    1415           0 :                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
    1416             :                                       &NrUdpSocketIpc::close_i),
    1417           0 :                 NS_DISPATCH_NORMAL);
    1418             : 
    1419             :   //remove all enqueued messages
    1420           0 :   std::queue<RefPtr<nr_udp_message> > empty;
    1421           0 :   std::swap(received_msgs_, empty);
    1422           0 : }
    1423             : 
    1424           0 : int NrUdpSocketIpc::recvfrom(void *buf, size_t maxlen, size_t *len, int flags,
    1425             :                           nr_transport_addr *from) {
    1426           0 :   ASSERT_ON_THREAD(sts_thread_);
    1427             : 
    1428           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1429             : 
    1430             :   int r, _status;
    1431             :   uint32_t consumed_len;
    1432             : 
    1433           0 :   *len = 0;
    1434             : 
    1435           0 :   if (state_ != NR_CONNECTED) {
    1436           0 :     ABORT(R_INTERNAL);
    1437             :   }
    1438             : 
    1439           0 :   if (received_msgs_.empty()) {
    1440           0 :     ABORT(R_WOULDBLOCK);
    1441             :   }
    1442             : 
    1443             :   {
    1444           0 :     RefPtr<nr_udp_message> msg(received_msgs_.front());
    1445             : 
    1446           0 :     received_msgs_.pop();
    1447             : 
    1448           0 :     if ((r=nr_praddr_to_transport_addr(&msg->from, from, IPPROTO_UDP, 0))) {
    1449           0 :       err_ = true;
    1450           0 :       MOZ_ASSERT(false, "Get bogus address for received UDP packet");
    1451             :       ABORT(r);
    1452             :     }
    1453             : 
    1454           0 :     consumed_len = std::min(maxlen, msg->data->len());
    1455           0 :     if (consumed_len < msg->data->len()) {
    1456           0 :       r_log(LOG_GENERIC, LOG_DEBUG, "Partial received UDP packet will be discard");
    1457             :     }
    1458             : 
    1459           0 :     memcpy(buf, msg->data->data(), consumed_len);
    1460           0 :     *len = consumed_len;
    1461             :   }
    1462             : 
    1463           0 :   _status = 0;
    1464             : abort:
    1465           0 :   return(_status);
    1466             : }
    1467             : 
    1468           0 : int NrUdpSocketIpc::getaddr(nr_transport_addr *addrp) {
    1469           0 :   ASSERT_ON_THREAD(sts_thread_);
    1470             : 
    1471           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1472             : 
    1473           0 :   if (state_ != NR_CONNECTED) {
    1474           0 :     return R_INTERNAL;
    1475             :   }
    1476             : 
    1477           0 :   return nr_transport_addr_copy(addrp, &my_addr_);
    1478             : }
    1479             : 
    1480           0 : int NrUdpSocketIpc::connect(nr_transport_addr *addr) {
    1481             :   int r,_status;
    1482             :   int32_t port;
    1483           0 :   nsCString host;
    1484             : 
    1485           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1486           0 :   r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::connect(%s) this=%p", addr->as_string,
    1487           0 :         (void*) this);
    1488             : 
    1489           0 :   if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
    1490           0 :     ABORT(r);
    1491             :   }
    1492             : 
    1493           0 :   RUN_ON_THREAD(io_thread_,
    1494           0 :                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
    1495             :                                       &NrUdpSocketIpc::connect_i,
    1496             :                                       host, static_cast<uint16_t>(port)),
    1497           0 :                 NS_DISPATCH_NORMAL);
    1498             : 
    1499             :   // Wait until connect() completes.
    1500           0 :   mon.Wait();
    1501             : 
    1502           0 :   r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::connect this=%p completed err_ = %s",
    1503           0 :         (void*) this, err_ ? "true" : "false");
    1504             : 
    1505           0 :   if (err_) {
    1506           0 :     ABORT(R_INTERNAL);
    1507             :   }
    1508             : 
    1509           0 :   _status = 0;
    1510             : abort:
    1511           0 :   return _status;
    1512             : }
    1513             : 
    1514           0 : int NrUdpSocketIpc::write(const void *msg, size_t len, size_t *written) {
    1515           0 :   MOZ_ASSERT(false);
    1516             :   return R_INTERNAL;
    1517             : }
    1518             : 
    1519           0 : int NrUdpSocketIpc::read(void* buf, size_t maxlen, size_t *len) {
    1520           0 :   MOZ_ASSERT(false);
    1521             :   return R_INTERNAL;
    1522             : }
    1523             : 
    1524           0 : int NrUdpSocketIpc::listen(int backlog) {
    1525           0 :   MOZ_ASSERT(false);
    1526             :   return R_INTERNAL;
    1527             : }
    1528             : 
    1529           0 : int NrUdpSocketIpc::accept(nr_transport_addr *addrp, nr_socket **sockp) {
    1530           0 :   MOZ_ASSERT(false);
    1531             :   return R_INTERNAL;
    1532             : }
    1533             : 
    1534             : // IO thread executors
    1535           0 : void NrUdpSocketIpc::create_i(const nsACString &host, const uint16_t port) {
    1536           0 :   ASSERT_ON_THREAD(io_thread_);
    1537             : 
    1538           0 :   uint32_t minBuffSize = 0;
    1539             :   nsresult rv;
    1540           0 :   nsCOMPtr<nsIUDPSocketChild> socketChild = do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
    1541           0 :   if (NS_FAILED(rv)) {
    1542           0 :     ReentrantMonitorAutoEnter mon(monitor_);
    1543           0 :     err_ = true;
    1544           0 :     MOZ_ASSERT(false, "Failed to create UDPSocketChild");
    1545             :     return;
    1546             :   }
    1547             : 
    1548             :   // This can spin the event loop; don't do that with the monitor held
    1549           0 :   socketChild->SetBackgroundSpinsEvents();
    1550             : 
    1551           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1552           0 :   if (!socket_child_) {
    1553           0 :     socket_child_ = socketChild;
    1554           0 :     socket_child_->SetFilterName(nsCString(NS_NETWORK_SOCKET_FILTER_HANDLER_STUN_SUFFIX));
    1555             :   } else {
    1556           0 :     socketChild = nullptr;
    1557             :   }
    1558             : 
    1559           0 :   RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy);
    1560           0 :   rv = proxy->Init(this);
    1561           0 :   if (NS_FAILED(rv)) {
    1562           0 :     err_ = true;
    1563           0 :     mon.NotifyAll();
    1564           0 :     return;
    1565             :   }
    1566             : 
    1567             : #ifdef XP_WIN
    1568             :   if (!mozilla::IsWin8OrLater()) {
    1569             :     // Increase default receive and send buffer size on <= Win7 to be able to
    1570             :     // receive and send an unpaced HD (>= 720p = 1280x720 - I Frame ~ 21K size)
    1571             :     // stream without losing packets.
    1572             :     // Manual testing showed that 100K buffer size was not enough and the
    1573             :     // packet loss dis-appeared with 256K buffer size.
    1574             :     // See bug 1252769 for future improvements of this.
    1575             :     minBuffSize = 256 * 1024;
    1576             :   }
    1577             : #endif
    1578             :   // XXX bug 1126232 - don't use null Principal!
    1579           0 :   if (NS_FAILED(socket_child_->Bind(proxy, nullptr, host, port,
    1580             :                                     /* reuse = */ false,
    1581             :                                     /* loopback = */ false,
    1582             :                                     /* recv buffer size */ minBuffSize,
    1583             :                                     /* send buffer size */ minBuffSize,
    1584             :                                     /* mainThreadEventTarget */ nullptr))) {
    1585           0 :     err_ = true;
    1586           0 :     MOZ_ASSERT(false, "Failed to create UDP socket");
    1587             :     mon.NotifyAll();
    1588             :     return;
    1589             :   }
    1590             : }
    1591             : 
    1592           0 : void NrUdpSocketIpc::connect_i(const nsACString &host, const uint16_t port) {
    1593           0 :   ASSERT_ON_THREAD(io_thread_);
    1594             :   nsresult rv;
    1595           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1596             : 
    1597           0 :   RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy);
    1598           0 :   rv = proxy->Init(this);
    1599           0 :   if (NS_FAILED(rv)) {
    1600           0 :     err_ = true;
    1601           0 :     mon.NotifyAll();
    1602           0 :     return;
    1603             :   }
    1604             : 
    1605           0 :   if (NS_FAILED(socket_child_->Connect(proxy, host, port))) {
    1606           0 :     err_ = true;
    1607           0 :     MOZ_ASSERT(false, "Failed to connect UDP socket");
    1608             :     mon.NotifyAll();
    1609             :     return;
    1610             :   }
    1611             : }
    1612             : 
    1613             : 
    1614           0 : void NrUdpSocketIpc::sendto_i(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf) {
    1615           0 :   ASSERT_ON_THREAD(io_thread_);
    1616             : 
    1617           0 :   ReentrantMonitorAutoEnter mon(monitor_);
    1618             : 
    1619           0 :   if (!socket_child_) {
    1620           0 :     MOZ_ASSERT(false);
    1621             :     err_ = true;
    1622             :     return;
    1623             :   }
    1624           0 :   if (NS_FAILED(socket_child_->SendWithAddress(&addr,
    1625             :                                                buf->data(),
    1626             :                                                buf->len()))) {
    1627           0 :     err_ = true;
    1628             :   }
    1629             : }
    1630             : 
    1631           0 : void NrUdpSocketIpc::close_i() {
    1632           0 :   ASSERT_ON_THREAD(io_thread_);
    1633             : 
    1634           0 :   if (socket_child_) {
    1635           0 :     socket_child_->Close();
    1636           0 :     socket_child_ = nullptr;
    1637             :   }
    1638           0 : }
    1639             : 
    1640             : #if defined(MOZILLA_INTERNAL_API)
    1641             : // close(), but transfer the socket_child_ reference to die as well
    1642             : // static
    1643           0 : void NrUdpSocketIpc::release_child_i(nsIUDPSocketChild* aChild) {
    1644             :   RefPtr<nsIUDPSocketChild> socket_child_ref =
    1645           0 :     already_AddRefed<nsIUDPSocketChild>(aChild);
    1646           0 :   if (socket_child_ref) {
    1647           0 :     socket_child_ref->Close();
    1648             :   }
    1649           0 : }
    1650             : #endif
    1651             : 
    1652           0 : void NrUdpSocketIpc::recv_callback_s(RefPtr<nr_udp_message> msg) {
    1653           0 :   ASSERT_ON_THREAD(sts_thread_);
    1654             : 
    1655             :   {
    1656           0 :     ReentrantMonitorAutoEnter mon(monitor_);
    1657           0 :     if (state_ != NR_CONNECTED) {
    1658           0 :       return;
    1659             :     }
    1660             :   }
    1661             : 
    1662             :   //enqueue received message
    1663           0 :   received_msgs_.push(msg);
    1664             : 
    1665           0 :   if ((poll_flags() & PR_POLL_READ)) {
    1666           0 :     fire_callback(NR_ASYNC_WAIT_READ);
    1667             :   }
    1668             : }
    1669             : 
    1670             : #if defined(MOZILLA_INTERNAL_API)
    1671             : // TCPSocket.
    1672           0 : class NrTcpSocketIpc::TcpSocketReadyRunner: public Runnable
    1673             : {
    1674             : public:
    1675           0 :   explicit TcpSocketReadyRunner(NrTcpSocketIpc *sck)
    1676           0 :     : Runnable("NrTcpSocketIpc::TcpSocketReadyRunner"), socket_(sck) {}
    1677             : 
    1678           0 :   NS_IMETHOD Run() override {
    1679           0 :     socket_->maybe_post_socket_ready();
    1680           0 :     return NS_OK;
    1681             :   }
    1682             : 
    1683             : private:
    1684             :   RefPtr<NrTcpSocketIpc> socket_;
    1685             : };
    1686             : 
    1687             : 
    1688           0 : NS_IMPL_ISUPPORTS(NrTcpSocketIpc,
    1689             :                   nsITCPSocketCallback)
    1690             : 
    1691           0 : NrTcpSocketIpc::NrTcpSocketIpc(nsIThread* aThread)
    1692             :   : NrSocketIpc(static_cast<nsIEventTarget*>(aThread)),
    1693             :     mirror_state_(NR_INIT),
    1694             :     state_(NR_INIT),
    1695             :     buffered_bytes_(0),
    1696           0 :     tracking_number_(0) {
    1697           0 : }
    1698             : 
    1699           0 : NrTcpSocketIpc::~NrTcpSocketIpc()
    1700             : {
    1701             :   // also guarantees socket_child_ is released from the io_thread
    1702             : 
    1703             :   // close(), but transfer the socket_child_ reference to die as well
    1704           0 :   RUN_ON_THREAD(io_thread_,
    1705           0 :                 mozilla::WrapRunnableNM(&NrTcpSocketIpc::release_child_i,
    1706           0 :                                         socket_child_.forget().take()),
    1707           0 :                 NS_DISPATCH_NORMAL);
    1708           0 : }
    1709             : 
    1710             : //
    1711             : // nsITCPSocketCallback methods
    1712             : //
    1713           0 : NS_IMETHODIMP NrTcpSocketIpc::UpdateReadyState(uint32_t aReadyState) {
    1714           0 :   NrSocketIpcState temp = NR_INIT;
    1715           0 :   switch (static_cast<dom::TCPReadyState>(aReadyState)) {
    1716             :     case dom::TCPReadyState::Connecting:
    1717           0 :       temp = NR_CONNECTING;
    1718           0 :       break;
    1719             :     case dom::TCPReadyState::Open:
    1720           0 :       temp = NR_CONNECTED;
    1721           0 :       break;
    1722             :     case dom::TCPReadyState::Closing:
    1723           0 :       temp = NR_CLOSING;
    1724           0 :       break;
    1725             :     case dom::TCPReadyState::Closed:
    1726           0 :       temp = NR_CLOSED;
    1727           0 :       break;
    1728             :     default:
    1729           0 :       MOZ_ASSERT(false, "Invalid ReadyState");
    1730             :       return NS_OK;
    1731             :   }
    1732           0 :   if (mirror_state_ != temp) {
    1733           0 :     mirror_state_ = temp;
    1734           0 :     RUN_ON_THREAD(sts_thread_,
    1735           0 :                   mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
    1736             :                                         &NrTcpSocketIpc::update_state_s,
    1737             :                                         temp),
    1738           0 :                   NS_DISPATCH_NORMAL);
    1739             :   }
    1740           0 :   return NS_OK;
    1741             : }
    1742             : 
    1743           0 : NS_IMETHODIMP NrTcpSocketIpc::UpdateBufferedAmount(uint32_t buffered_amount,
    1744             :                                                    uint32_t tracking_number) {
    1745           0 :   RUN_ON_THREAD(sts_thread_,
    1746           0 :                 mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
    1747             :                                       &NrTcpSocketIpc::message_sent_s,
    1748             :                                       buffered_amount,
    1749             :                                       tracking_number),
    1750           0 :                 NS_DISPATCH_NORMAL);
    1751             : 
    1752           0 :   return NS_OK;
    1753             : }
    1754             : 
    1755           0 : NS_IMETHODIMP NrTcpSocketIpc::FireDataArrayEvent(const nsAString& aType,
    1756             :                                                  const InfallibleTArray<uint8_t>& buffer) {
    1757             :   // Called when we received data.
    1758           0 :   uint8_t *buf = const_cast<uint8_t*>(buffer.Elements());
    1759             : 
    1760           0 :   nsAutoPtr<DataBuffer> data_buf(new DataBuffer(buf, buffer.Length()));
    1761           0 :   RefPtr<nr_tcp_message> msg = new nr_tcp_message(data_buf);
    1762             : 
    1763           0 :   RUN_ON_THREAD(sts_thread_,
    1764           0 :                 mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
    1765             :                                       &NrTcpSocketIpc::recv_message_s,
    1766             :                                       msg),
    1767           0 :                 NS_DISPATCH_NORMAL);
    1768           0 :   return NS_OK;
    1769             : }
    1770             : 
    1771           0 : NS_IMETHODIMP NrTcpSocketIpc::FireErrorEvent(const nsAString &type,
    1772             :                                              const nsAString &name) {
    1773           0 :   r_log(LOG_GENERIC, LOG_ERR,
    1774             :         "Error from TCPSocketChild: type: %s, name: %s",
    1775           0 :         NS_LossyConvertUTF16toASCII(type).get(), NS_LossyConvertUTF16toASCII(name).get());
    1776           0 :   socket_child_ = nullptr;
    1777             : 
    1778           0 :   mirror_state_ = NR_CLOSED;
    1779           0 :   RUN_ON_THREAD(sts_thread_,
    1780           0 :                 mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
    1781             :                                       &NrTcpSocketIpc::update_state_s,
    1782             :                                       NR_CLOSED),
    1783           0 :                 NS_DISPATCH_NORMAL);
    1784             : 
    1785           0 :   return NS_OK;
    1786             : }
    1787             : 
    1788             : // methods of nsITCPSocketCallback that we are not going to implement.
    1789             : 
    1790           0 : NS_IMETHODIMP NrTcpSocketIpc::FireDataStringEvent(const nsAString &type,
    1791             :                                                   const nsACString &data) {
    1792           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1793             : }
    1794             : 
    1795           0 : NS_IMETHODIMP NrTcpSocketIpc::FireEvent(const nsAString &type) {
    1796             :   // XXX support type.mData == 'close' at least
    1797           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1798             : }
    1799             : 
    1800             : //
    1801             : // NrSocketBase methods.
    1802             : //
    1803           0 : int NrTcpSocketIpc::create(nr_transport_addr *addr) {
    1804             :   int r, _status;
    1805             :   nsresult rv;
    1806             :   int32_t port;
    1807           0 :   nsCString host;
    1808             : 
    1809           0 :   if (state_ != NR_INIT) {
    1810           0 :     ABORT(R_INTERNAL);
    1811             :   }
    1812             : 
    1813           0 :   sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    1814           0 :   if (NS_FAILED(rv)) {
    1815           0 :     MOZ_ASSERT(false, "Failed to get STS thread");
    1816             :     ABORT(R_INTERNAL);
    1817             :   }
    1818             : 
    1819             :   // Sanity check
    1820           0 :   if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
    1821           0 :     ABORT(r);
    1822             :   }
    1823             : 
    1824           0 :   if ((r=nr_transport_addr_copy(&my_addr_, addr))) {
    1825           0 :     ABORT(r);
    1826             :   }
    1827             : 
    1828           0 :   _status = 0;
    1829             : abort:
    1830           0 :   return(_status);
    1831             : }
    1832             : 
    1833           0 : int NrTcpSocketIpc::sendto(const void *msg, size_t len,
    1834             :                            int flags, nr_transport_addr *to) {
    1835           0 :   MOZ_ASSERT(false);
    1836             :   return R_INTERNAL;
    1837             : }
    1838             : 
    1839           0 : int NrTcpSocketIpc::recvfrom(void * buf, size_t maxlen,
    1840             :                              size_t *len, int flags,
    1841             :                              nr_transport_addr *from) {
    1842           0 :   MOZ_ASSERT(false);
    1843             :   return R_INTERNAL;
    1844             : }
    1845             : 
    1846           0 : int NrTcpSocketIpc::getaddr(nr_transport_addr *addrp) {
    1847           0 :   ASSERT_ON_THREAD(sts_thread_);
    1848           0 :   return nr_transport_addr_copy(addrp, &my_addr_);
    1849             : }
    1850             : 
    1851           0 : void NrTcpSocketIpc::close() {
    1852           0 :   ASSERT_ON_THREAD(sts_thread_);
    1853             : 
    1854           0 :   if (state_ == NR_CLOSED || state_ == NR_CLOSING) {
    1855           0 :     return;
    1856             :   }
    1857             : 
    1858           0 :   state_ = NR_CLOSING;
    1859             : 
    1860           0 :   RUN_ON_THREAD(io_thread_,
    1861           0 :                 mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
    1862             :                                       &NrTcpSocketIpc::close_i),
    1863           0 :                 NS_DISPATCH_NORMAL);
    1864             : 
    1865             :   //remove all enqueued messages
    1866           0 :   std::queue<RefPtr<nr_tcp_message>> empty;
    1867           0 :   std::swap(msg_queue_, empty);
    1868             : }
    1869             : 
    1870           0 : int NrTcpSocketIpc::connect(nr_transport_addr *addr) {
    1871           0 :   nsCString remote_addr, local_addr;
    1872             :   int32_t remote_port, local_port;
    1873             :   int r, _status;
    1874           0 :   if ((r=nr_transport_addr_get_addrstring_and_port(addr,
    1875             :                                                    &remote_addr,
    1876             :                                                    &remote_port))) {
    1877           0 :     ABORT(r);
    1878             :   }
    1879             : 
    1880           0 :   if ((r=nr_transport_addr_get_addrstring_and_port(&my_addr_,
    1881             :                                                    &local_addr,
    1882             :                                                    &local_port))) {
    1883           0 :     MOZ_ASSERT(false); // shouldn't fail as it was sanity-checked in ::create()
    1884             :     ABORT(r);
    1885             :   }
    1886             : 
    1887           0 :   state_ = mirror_state_ = NR_CONNECTING;
    1888           0 :   RUN_ON_THREAD(io_thread_,
    1889           0 :                 mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
    1890             :                              &NrTcpSocketIpc::connect_i,
    1891             :                              remote_addr,
    1892             :                              static_cast<uint16_t>(remote_port),
    1893             :                              local_addr,
    1894             :                              static_cast<uint16_t>(local_port),
    1895           0 :                              nsCString(my_addr_.tls_host)),
    1896           0 :                 NS_DISPATCH_NORMAL);
    1897             : 
    1898             :   // Make caller wait for ready to write.
    1899           0 :   _status = R_WOULDBLOCK;
    1900             :  abort:
    1901           0 :   return _status;
    1902             : }
    1903             : 
    1904           0 : int NrTcpSocketIpc::write(const void *msg, size_t len, size_t *written) {
    1905           0 :   ASSERT_ON_THREAD(sts_thread_);
    1906           0 :   int _status = 0;
    1907           0 :   if (state_ != NR_CONNECTED) {
    1908           0 :     ABORT(R_FAILED);
    1909             :   }
    1910             : 
    1911           0 :   if (buffered_bytes_ + len >= nsITCPSocketCallback::BUFFER_SIZE) {
    1912           0 :     ABORT(R_WOULDBLOCK);
    1913             :   }
    1914             : 
    1915           0 :   buffered_bytes_ += len;
    1916             :   {
    1917           0 :     InfallibleTArray<uint8_t>* arr = new InfallibleTArray<uint8_t>();
    1918           0 :     arr->AppendElements(static_cast<const uint8_t*>(msg), len);
    1919             :     // keep track of un-acknowleged writes by tracking number.
    1920           0 :     writes_in_flight_.push_back(len);
    1921           0 :     RUN_ON_THREAD(io_thread_,
    1922           0 :                   mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
    1923             :                                         &NrTcpSocketIpc::write_i,
    1924           0 :                                         nsAutoPtr<InfallibleTArray<uint8_t>>(arr),
    1925           0 :                                         ++tracking_number_),
    1926           0 :                   NS_DISPATCH_NORMAL);
    1927             :   }
    1928           0 :   *written = len;
    1929             :  abort:
    1930           0 :   return _status;
    1931             : }
    1932             : 
    1933           0 : int NrTcpSocketIpc::read(void* buf, size_t maxlen, size_t *len) {
    1934           0 :   int _status = 0;
    1935           0 :   if (state_ != NR_CONNECTED) {
    1936           0 :     ABORT(R_FAILED);
    1937             :   }
    1938             : 
    1939           0 :   if (msg_queue_.size() == 0) {
    1940           0 :     ABORT(R_WOULDBLOCK);
    1941             :   }
    1942             : 
    1943             :   {
    1944           0 :     RefPtr<nr_tcp_message> msg(msg_queue_.front());
    1945           0 :     size_t consumed_len = std::min(maxlen, msg->unread_bytes());
    1946           0 :     memcpy(buf, msg->reading_pointer(), consumed_len);
    1947           0 :     if (consumed_len < msg->unread_bytes()) {
    1948             :       // There is still something left in buffer.
    1949           0 :       msg->read_bytes += consumed_len;
    1950             :     } else {
    1951           0 :       msg_queue_.pop();
    1952             :     }
    1953           0 :     *len = consumed_len;
    1954             :   }
    1955             : 
    1956             :  abort:
    1957           0 :   return _status;
    1958             : }
    1959             : 
    1960           0 : int NrTcpSocketIpc::listen(int backlog) {
    1961           0 :   return R_INTERNAL;
    1962             : }
    1963             : 
    1964           0 : int NrTcpSocketIpc::accept(nr_transport_addr *addrp, nr_socket **sockp) {
    1965           0 :   return R_INTERNAL;
    1966             : }
    1967             : 
    1968           0 : void NrTcpSocketIpc::connect_i(const nsACString &remote_addr,
    1969             :                                uint16_t remote_port,
    1970             :                                const nsACString &local_addr,
    1971             :                                uint16_t local_port,
    1972             :                                const nsACString &tls_host) {
    1973           0 :   ASSERT_ON_THREAD(io_thread_);
    1974             :   // io_thread_ was initialized as main thread at constructor,
    1975             :   // so the following assertion should be true.
    1976           0 :   MOZ_ASSERT(NS_IsMainThread());
    1977             : 
    1978           0 :   mirror_state_ = NR_CONNECTING;
    1979             : 
    1980             :   dom::TCPSocketChild* child =
    1981           0 :     new dom::TCPSocketChild(NS_ConvertUTF8toUTF16(remote_addr),
    1982             :                             remote_port,
    1983           0 :                             SystemGroup::EventTargetFor(TaskCategory::Other));
    1984           0 :   socket_child_ = child;
    1985             : 
    1986             :   // Bug 1285330: put filtering back in here
    1987             : 
    1988           0 :   if (tls_host.IsEmpty()) {
    1989             :     // XXX remove remote!
    1990           0 :     socket_child_->SendWindowlessOpenBind(this,
    1991             :                                           remote_addr, remote_port,
    1992             :                                           local_addr, local_port,
    1993             :                                           /* use ssl */ false,
    1994           0 :                                           /* reuse addr port */ true);
    1995             :   } else {
    1996             :     // XXX remove remote!
    1997           0 :     socket_child_->SendWindowlessOpenBind(this,
    1998             :                                           tls_host, remote_port,
    1999             :                                           local_addr, local_port,
    2000             :                                           /* use ssl */ true,
    2001           0 :                                           /* reuse addr port */ true);
    2002             :   }
    2003           0 : }
    2004             : 
    2005           0 : void NrTcpSocketIpc::write_i(nsAutoPtr<InfallibleTArray<uint8_t>> arr,
    2006             :                              uint32_t tracking_number) {
    2007           0 :   ASSERT_ON_THREAD(io_thread_);
    2008           0 :   if (!socket_child_) {
    2009           0 :     return;
    2010             :   }
    2011           0 :   socket_child_->SendSendArray(*arr, tracking_number);
    2012             : }
    2013             : 
    2014           0 : void NrTcpSocketIpc::close_i() {
    2015           0 :   ASSERT_ON_THREAD(io_thread_);
    2016           0 :   mirror_state_ = NR_CLOSING;
    2017           0 :   if (!socket_child_) {
    2018           0 :     return;
    2019             :   }
    2020           0 :   socket_child_->SendClose();
    2021             : }
    2022             : 
    2023             : // close(), but transfer the socket_child_ reference to die as well
    2024             : // static
    2025           0 : void NrTcpSocketIpc::release_child_i(dom::TCPSocketChild* aChild) {
    2026             :   RefPtr<dom::TCPSocketChild> socket_child_ref =
    2027           0 :     already_AddRefed<dom::TCPSocketChild>(aChild);
    2028           0 :   if (socket_child_ref) {
    2029           0 :     socket_child_ref->SendClose();
    2030             :   }
    2031             :   // io_thread_ is MainThread, so no use to release
    2032           0 : }
    2033             : 
    2034           0 : void NrTcpSocketIpc::message_sent_s(uint32_t buffered_amount,
    2035             :                                     uint32_t tracking_number) {
    2036           0 :   ASSERT_ON_THREAD(sts_thread_);
    2037             : 
    2038           0 :   size_t num_unacked_writes = tracking_number_ - tracking_number;
    2039           0 :   while (writes_in_flight_.size() > num_unacked_writes) {
    2040           0 :     writes_in_flight_.pop_front();
    2041             :   }
    2042             : 
    2043           0 :   for (size_t unacked_write_len : writes_in_flight_) {
    2044           0 :     buffered_amount += unacked_write_len;
    2045             :   }
    2046             : 
    2047           0 :   r_log(LOG_GENERIC, LOG_ERR,
    2048             :         "UpdateBufferedAmount: (tracking %u): %u, waiting: %s",
    2049             :         tracking_number, buffered_amount,
    2050           0 :         (poll_flags() & PR_POLL_WRITE) ? "yes" : "no");
    2051             : 
    2052           0 :   buffered_bytes_ = buffered_amount;
    2053           0 :   maybe_post_socket_ready();
    2054           0 : }
    2055             : 
    2056           0 : void NrTcpSocketIpc::recv_message_s(nr_tcp_message *msg) {
    2057           0 :   ASSERT_ON_THREAD(sts_thread_);
    2058           0 :   msg_queue_.push(msg);
    2059           0 :   maybe_post_socket_ready();
    2060           0 : }
    2061             : 
    2062           0 : void NrTcpSocketIpc::update_state_s(NrSocketIpcState next_state) {
    2063           0 :   ASSERT_ON_THREAD(sts_thread_);
    2064             :   // only allow valid transitions
    2065           0 :   switch (state_) {
    2066             :     case NR_CONNECTING:
    2067           0 :       if (next_state == NR_CONNECTED) {
    2068           0 :         state_ = NR_CONNECTED;
    2069           0 :         maybe_post_socket_ready();
    2070             :       } else {
    2071           0 :         state_ = next_state; // all states are valid from CONNECTING
    2072             :       }
    2073           0 :       break;
    2074             :     case NR_CONNECTED:
    2075           0 :       if (next_state != NR_CONNECTING) {
    2076           0 :         state_ = next_state;
    2077             :       }
    2078           0 :       break;
    2079             :     case NR_CLOSING:
    2080           0 :       if (next_state == NR_CLOSED) {
    2081           0 :         state_ = next_state;
    2082             :       }
    2083           0 :       break;
    2084             :     case NR_CLOSED:
    2085           0 :       break;
    2086             :     default:
    2087           0 :       MOZ_CRASH("update_state_s while in illegal state");
    2088             :   }
    2089           0 : }
    2090             : 
    2091           0 : void NrTcpSocketIpc::maybe_post_socket_ready() {
    2092           0 :   bool has_event = false;
    2093           0 :   if (state_ == NR_CONNECTED) {
    2094           0 :     if (poll_flags() & PR_POLL_WRITE) {
    2095             :       // This effectively polls via the event loop until the
    2096             :       // NR_ASYNC_WAIT_WRITE is no longer armed.
    2097           0 :       if (buffered_bytes_ < nsITCPSocketCallback::BUFFER_SIZE) {
    2098             :         r_log(LOG_GENERIC, LOG_INFO, "Firing write callback (%u)",
    2099           0 :               (uint32_t)buffered_bytes_);
    2100           0 :         fire_callback(NR_ASYNC_WAIT_WRITE);
    2101           0 :         has_event = true;
    2102             :       }
    2103             :     }
    2104           0 :     if (poll_flags() & PR_POLL_READ) {
    2105           0 :       if (msg_queue_.size()) {
    2106           0 :         if (msg_queue_.size() > 5) {
    2107           0 :           r_log(LOG_GENERIC, LOG_INFO, "Firing read callback (%u)",
    2108           0 :                 (uint32_t)msg_queue_.size());
    2109             :         }
    2110           0 :         fire_callback(NR_ASYNC_WAIT_READ);
    2111           0 :         has_event = true;
    2112             :       }
    2113             :     }
    2114             :   }
    2115             : 
    2116             :   // If any event has been posted, we post a runnable to see
    2117             :   // if the events have to be posted again.
    2118           0 :   if (has_event) {
    2119           0 :     RefPtr<TcpSocketReadyRunner> runnable = new TcpSocketReadyRunner(this);
    2120           0 :     NS_DispatchToCurrentThread(runnable);
    2121             :   }
    2122           0 : }
    2123             : #endif
    2124             : 
    2125             : }  // close namespace
    2126             : 
    2127             : 
    2128             : using namespace mozilla;
    2129             : 
    2130             : // Bridge to the nr_socket interface
    2131             : static int nr_socket_local_destroy(void **objp);
    2132             : static int nr_socket_local_sendto(void *obj,const void *msg, size_t len,
    2133             :                                   int flags, nr_transport_addr *to);
    2134             : static int nr_socket_local_recvfrom(void *obj,void * restrict buf,
    2135             :   size_t maxlen, size_t *len, int flags, nr_transport_addr *from);
    2136             : static int nr_socket_local_getfd(void *obj, NR_SOCKET *fd);
    2137             : static int nr_socket_local_getaddr(void *obj, nr_transport_addr *addrp);
    2138             : static int nr_socket_local_close(void *obj);
    2139             : static int nr_socket_local_connect(void *sock, nr_transport_addr *addr);
    2140             : static int nr_socket_local_write(void *obj,const void *msg, size_t len,
    2141             :                                  size_t *written);
    2142             : static int nr_socket_local_read(void *obj,void * restrict buf, size_t maxlen,
    2143             :                                 size_t *len);
    2144             : static int nr_socket_local_listen(void *obj, int backlog);
    2145             : static int nr_socket_local_accept(void *obj, nr_transport_addr *addrp,
    2146             :                                   nr_socket **sockp);
    2147             : 
    2148             : static nr_socket_vtbl nr_socket_local_vtbl={
    2149             :   2,
    2150             :   nr_socket_local_destroy,
    2151             :   nr_socket_local_sendto,
    2152             :   nr_socket_local_recvfrom,
    2153             :   nr_socket_local_getfd,
    2154             :   nr_socket_local_getaddr,
    2155             :   nr_socket_local_connect,
    2156             :   nr_socket_local_write,
    2157             :   nr_socket_local_read,
    2158             :   nr_socket_local_close,
    2159             :   nr_socket_local_listen,
    2160             :   nr_socket_local_accept
    2161             : };
    2162             : 
    2163             : /* static */
    2164             : int
    2165           0 : NrSocketBase::CreateSocket(nr_transport_addr *addr, RefPtr<NrSocketBase> *sock)
    2166             : {
    2167             :   int r, _status;
    2168             : 
    2169             :   // create IPC bridge for content process
    2170           0 :   if (XRE_IsParentProcess()) {
    2171           0 :     *sock = new NrSocket();
    2172             :   } else {
    2173           0 :     switch (addr->protocol) {
    2174             :       case IPPROTO_UDP:
    2175           0 :         *sock = new NrUdpSocketIpc();
    2176           0 :         break;
    2177             :       case IPPROTO_TCP:
    2178             : #if defined(MOZILLA_INTERNAL_API)
    2179             :         {
    2180           0 :           nsCOMPtr<nsIThread> main_thread;
    2181           0 :           NS_GetMainThread(getter_AddRefs(main_thread));
    2182           0 :           *sock = new NrTcpSocketIpc(main_thread.get());
    2183             :         }
    2184             : #else
    2185             :         ABORT(R_REJECTED);
    2186             : #endif
    2187           0 :         break;
    2188             :     }
    2189             :   }
    2190             : 
    2191           0 :   r = (*sock)->create(addr);
    2192           0 :   if (r)
    2193           0 :     ABORT(r);
    2194             : 
    2195           0 :   _status = 0;
    2196             : abort:
    2197           0 :   if (_status) {
    2198           0 :     *sock = nullptr;
    2199             :   }
    2200           0 :   return _status;
    2201             : }
    2202             : 
    2203           0 : int nr_socket_local_create(void *obj, nr_transport_addr *addr, nr_socket **sockp) {
    2204           0 :   RefPtr<NrSocketBase> sock;
    2205             :   int r, _status;
    2206             : 
    2207           0 :   r = NrSocketBase::CreateSocket(addr, &sock);
    2208           0 :   if (r) {
    2209           0 :     ABORT(r);
    2210             :   }
    2211             : 
    2212           0 :   r = nr_socket_create_int(static_cast<void *>(sock),
    2213           0 :                            sock->vtbl(), sockp);
    2214           0 :   if (r)
    2215           0 :     ABORT(r);
    2216             : 
    2217           0 :   _status = 0;
    2218             : 
    2219             :   {
    2220             :     // We will release this reference in destroy(), not exactly the normal
    2221             :     // ownership model, but it is what it is.
    2222           0 :     NrSocketBase* dummy = sock.forget().take();
    2223             :     (void)dummy;
    2224             :   }
    2225             : 
    2226             : abort:
    2227           0 :   return _status;
    2228             : }
    2229             : 
    2230             : 
    2231           0 : static int nr_socket_local_destroy(void **objp) {
    2232           0 :   if(!objp || !*objp)
    2233           0 :     return 0;
    2234             : 
    2235           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(*objp);
    2236           0 :   *objp = nullptr;
    2237             : 
    2238           0 :   sock->close();  // Signal STS that we want not to listen
    2239           0 :   sock->Release();  // Decrement the ref count
    2240             : 
    2241           0 :   return 0;
    2242             : }
    2243             : 
    2244           0 : static int nr_socket_local_sendto(void *obj,const void *msg, size_t len,
    2245             :                                   int flags, nr_transport_addr *addr) {
    2246           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2247             : 
    2248           0 :   return sock->sendto(msg, len, flags, addr);
    2249             : }
    2250             : 
    2251           0 : static int nr_socket_local_recvfrom(void *obj,void * restrict buf,
    2252             :                                     size_t maxlen, size_t *len, int flags,
    2253             :                                     nr_transport_addr *addr) {
    2254           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2255             : 
    2256           0 :   return sock->recvfrom(buf, maxlen, len, flags, addr);
    2257             : }
    2258             : 
    2259           0 : static int nr_socket_local_getfd(void *obj, NR_SOCKET *fd) {
    2260           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2261             : 
    2262           0 :   *fd = sock;
    2263             : 
    2264           0 :   return 0;
    2265             : }
    2266             : 
    2267           0 : static int nr_socket_local_getaddr(void *obj, nr_transport_addr *addrp) {
    2268           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2269             : 
    2270           0 :   return sock->getaddr(addrp);
    2271             : }
    2272             : 
    2273             : 
    2274           0 : static int nr_socket_local_close(void *obj) {
    2275           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2276             : 
    2277           0 :   sock->close();
    2278             : 
    2279           0 :   return 0;
    2280             : }
    2281             : 
    2282           0 : static int nr_socket_local_write(void *obj, const void *msg, size_t len,
    2283             :                                  size_t *written) {
    2284           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2285             : 
    2286           0 :   return sock->write(msg, len, written);
    2287             : }
    2288             : 
    2289           0 : static int nr_socket_local_read(void *obj, void * restrict buf, size_t maxlen,
    2290             :                                 size_t *len) {
    2291           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2292             : 
    2293           0 :   return sock->read(buf, maxlen, len);
    2294             : }
    2295             : 
    2296           0 : static int nr_socket_local_connect(void *obj, nr_transport_addr *addr) {
    2297           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2298             : 
    2299           0 :   return sock->connect(addr);
    2300             : }
    2301             : 
    2302           0 : static int nr_socket_local_listen(void *obj, int backlog) {
    2303           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2304             : 
    2305           0 :   return sock->listen(backlog);
    2306             : }
    2307             : 
    2308           0 : static int nr_socket_local_accept(void *obj, nr_transport_addr *addrp,
    2309             :                                   nr_socket **sockp) {
    2310           0 :   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
    2311             : 
    2312           0 :   return sock->accept(addrp, sockp);
    2313             : }
    2314             : 
    2315             : // Implement async api
    2316           0 : int NR_async_wait(NR_SOCKET sock, int how, NR_async_cb cb,void *cb_arg,
    2317             :                   char *function,int line) {
    2318           0 :   NrSocketBase *s = static_cast<NrSocketBase *>(sock);
    2319             : 
    2320           0 :   return s->async_wait(how, cb, cb_arg, function, line);
    2321             : }
    2322             : 
    2323           0 : int NR_async_cancel(NR_SOCKET sock,int how) {
    2324           0 :   NrSocketBase *s = static_cast<NrSocketBase *>(sock);
    2325             : 
    2326           0 :   return s->cancel(how);
    2327             : }
    2328             : 
    2329           0 : nr_socket_vtbl* NrSocketBase::vtbl() {
    2330           0 :   return &nr_socket_local_vtbl;
    2331           9 : }

Generated by: LCOV version 1.13