media/mtransport/nr_socket_prsock.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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 */
    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/. */
    14 /*
    15 Original code from nICEr and nrappkit.
    17 nICEr copyright:
    19 Copyright (c) 2007, Adobe Systems, Incorporated
    20 All rights reserved.
    22 Redistribution and use in source and binary forms, with or without
    23 modification, are permitted provided that the following conditions are
    24 met:
    26 * Redistributions of source code must retain the above copyright
    27   notice, this list of conditions and the following disclaimer.
    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.
    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.
    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.
    50 nrappkit copyright:
    52    Copyright (C) 2001-2003, Network Resonance, Inc.
    53    Copyright (C) 2006, Network Resonance, Inc.
    54    All Rights Reserved
    56    Redistribution and use in source and binary forms, with or without
    57    modification, are permitted provided that the following conditions
    58    are met:
    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.
    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.
    83    ekr@rtfm.com  Thu Dec 20 20:14:49 2001
    84 */
    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>
    93 #include "nspr.h"
    94 #include "prerror.h"
    95 #include "prio.h"
    96 #include "prnetdb.h"
    98 #include "mozilla/net/DNS.h"
    99 #include "nsCOMPtr.h"
   100 #include "nsASocketHandler.h"
   101 #include "nsISocketTransportService.h"
   102 #include "nsNetCID.h"
   103 #include "nsISupportsImpl.h"
   104 #include "nsServiceManagerUtils.h"
   105 #include "nsComponentManagerUtils.h"
   106 #include "nsXPCOM.h"
   107 #include "nsXULAppAPI.h"
   108 #include "runnable_utils.h"
   110 extern "C" {
   111 #include "nr_api.h"
   112 #include "async_wait.h"
   113 #include "nr_socket.h"
   114 #include "nr_socket_local.h"
   115 #include "stun_hint.h"
   116 }
   117 #include "nr_socket_prsock.h"
   118 #include "simpletokenbucket.h"
   120 // Implement the nsISupports ref counting
   121 namespace mozilla {
   123 // NrSocketBase implementation
   124 // async_event APIs
   125 int NrSocketBase::async_wait(int how, NR_async_cb cb, void *cb_arg,
   126                              char *function, int line) {
   127   uint16_t flag;
   129   switch (how) {
   130     case NR_ASYNC_WAIT_READ:
   131       flag = PR_POLL_READ;
   132       break;
   133     case NR_ASYNC_WAIT_WRITE:
   134       flag = PR_POLL_WRITE;
   135       break;
   136     default:
   137       return R_BAD_ARGS;
   138   }
   140   cbs_[how] = cb;
   141   cb_args_[how] = cb_arg;
   142   poll_flags_ |= flag;
   144   return 0;
   145 }
   147 int NrSocketBase::cancel(int how) {
   148   uint16_t flag;
   150   switch (how) {
   151     case NR_ASYNC_WAIT_READ:
   152       flag = PR_POLL_READ;
   153       break;
   154     case NR_ASYNC_WAIT_WRITE:
   155       flag = PR_POLL_WRITE;
   156       break;
   157     default:
   158       return R_BAD_ARGS;
   159   }
   161   poll_flags_ &= ~flag;
   163   return 0;
   164 }
   166 void NrSocketBase::fire_callback(int how) {
   167   // This can't happen unless we are armed because we only set
   168   // the flags if we are armed
   169   MOZ_ASSERT(cbs_[how]);
   171   // Now cancel so that we need to be re-armed. Note that
   172   // the re-arming probably happens in the callback we are
   173   // about to fire.
   174   cancel(how);
   176   cbs_[how](this, how, cb_args_[how]);
   177 }
   179 // NrSocket implementation
   180 NS_IMPL_ISUPPORTS0(NrSocket)
   183 // The nsASocket callbacks
   184 void NrSocket::OnSocketReady(PRFileDesc *fd, int16_t outflags) {
   185   if (outflags & PR_POLL_READ)
   186     fire_callback(NR_ASYNC_WAIT_READ);
   187   if (outflags & PR_POLL_WRITE)
   188     fire_callback(NR_ASYNC_WAIT_WRITE);
   189 }
   191 void NrSocket::OnSocketDetached(PRFileDesc *fd) {
   192   ;  // TODO: Log?
   193 }
   195 void NrSocket::IsLocal(bool *aIsLocal) {
   196   // TODO(jesup): better check? Does it matter? (likely no)
   197   *aIsLocal = false;
   198 }
   200 // async_event APIs
   201 int NrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg,
   202                          char *function, int line) {
   203   int r = NrSocketBase::async_wait(how, cb, cb_arg, function, line);
   205   if (!r) {
   206     mPollFlags = poll_flags();
   207   }
   209   return r;
   210 }
   212 int NrSocket::cancel(int how) {
   213   int r = NrSocketBase::cancel(how);
   215   if (!r) {
   216     mPollFlags = poll_flags();
   217   }
   219   return r;
   220 }
   222 // Helper functions for addresses
   223 static int nr_transport_addr_to_praddr(nr_transport_addr *addr,
   224   PRNetAddr *naddr)
   225   {
   226     int _status;
   228     memset(naddr, 0, sizeof(*naddr));
   230     switch(addr->protocol){
   231       case IPPROTO_TCP:
   232         break;
   233       case IPPROTO_UDP:
   234         break;
   235       default:
   236         ABORT(R_BAD_ARGS);
   237     }
   239     switch(addr->ip_version){
   240       case NR_IPV4:
   241         naddr->inet.family = PR_AF_INET;
   242         naddr->inet.port = addr->u.addr4.sin_port;
   243         naddr->inet.ip = addr->u.addr4.sin_addr.s_addr;
   244         break;
   245       case NR_IPV6:
   246 #if 0
   247         naddr->ipv6.family = PR_AF_INET6;
   248         naddr->ipv6.port = addr->u.addr6.sin6_port;
   249 #ifdef LINUX
   250         memcpy(naddr->ipv6.ip._S6_un._S6_u8,
   251                &addr->u.addr6.sin6_addr.__in6_u.__u6_addr8, 16);
   252 #else
   253         memcpy(naddr->ipv6.ip._S6_un._S6_u8,
   254                &addr->u.addr6.sin6_addr.__u6_addr.__u6_addr8, 16);
   255 #endif
   256 #else
   257         // TODO: make IPv6 work
   258         ABORT(R_INTERNAL);
   259 #endif
   260         break;
   261       default:
   262         ABORT(R_BAD_ARGS);
   263     }
   265     _status = 0;
   266   abort:
   267     return(_status);
   268   }
   270 //XXX schien@mozilla.com: copy from PRNetAddrToNetAddr,
   271 // should be removed after fix the link error in signaling_unittests
   272 static int praddr_to_netaddr(const PRNetAddr *prAddr, net::NetAddr *addr)
   273 {
   274   int _status;
   276   switch (prAddr->raw.family) {
   277     case PR_AF_INET:
   278       addr->inet.family = AF_INET;
   279       addr->inet.port = prAddr->inet.port;
   280       addr->inet.ip = prAddr->inet.ip;
   281       break;
   282     case PR_AF_INET6:
   283       addr->inet6.family = AF_INET6;
   284       addr->inet6.port = prAddr->ipv6.port;
   285       addr->inet6.flowinfo = prAddr->ipv6.flowinfo;
   286       memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8));
   287       addr->inet6.scope_id = prAddr->ipv6.scope_id;
   288       break;
   289     default:
   290       MOZ_ASSERT(false);
   291       ABORT(R_BAD_ARGS);
   292   }
   294   _status = 0;
   295 abort:
   296   return(_status);
   297 }
   299 static int nr_transport_addr_to_netaddr(nr_transport_addr *addr,
   300   net::NetAddr *naddr)
   301 {
   302   int r, _status;
   303   PRNetAddr praddr;
   305   if((r = nr_transport_addr_to_praddr(addr, &praddr))) {
   306     ABORT(r);
   307   }
   309   if((r = praddr_to_netaddr(&praddr, naddr))) {
   310     ABORT(r);
   311   }
   313   _status = 0;
   314 abort:
   315   return(_status);
   316 }
   318 int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr,
   319                                  nr_transport_addr *addr, int protocol)
   320   {
   321     int _status;
   322     int r;
   324     switch(netaddr->raw.family) {
   325       case AF_INET:
   326         if ((r = nr_ip4_port_to_transport_addr(ntohl(netaddr->inet.ip),
   327                                                ntohs(netaddr->inet.port),
   328                                                protocol, addr)))
   329           ABORT(r);
   330         break;
   331       case AF_INET6:
   332         ABORT(R_BAD_ARGS);
   333       default:
   334         MOZ_ASSERT(false);
   335         ABORT(R_BAD_ARGS);
   336     }
   337     _status=0;
   338   abort:
   339     return(_status);
   340   }
   342 int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
   343                                 nr_transport_addr *addr, int protocol,
   344                                 int keep)
   345   {
   346     int _status;
   347     int r;
   348     struct sockaddr_in ip4;
   350     switch(praddr->raw.family) {
   351       case PR_AF_INET:
   352         ip4.sin_family = PF_INET;
   353         ip4.sin_addr.s_addr = praddr->inet.ip;
   354         ip4.sin_port = praddr->inet.port;
   355         if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip4,
   356                                                sizeof(ip4),
   357                                                protocol, keep,
   358                                                addr)))
   359           ABORT(r);
   360         break;
   361       case PR_AF_INET6:
   362 #if 0
   363         r = nr_sockaddr_to_transport_addr((sockaddr *)&praddr->raw,
   364           sizeof(struct sockaddr_in6),IPPROTO_UDP,keep,addr);
   365         break;
   366 #endif
   367         ABORT(R_BAD_ARGS);
   368       default:
   369         MOZ_ASSERT(false);
   370         ABORT(R_BAD_ARGS);
   371     }
   373     _status=0;
   374  abort:
   375     return(_status);
   376   }
   378 /*
   379  * nr_transport_addr_get_addrstring_and_port
   380  * convert nr_transport_addr to IP address string and port number
   381  */
   382 int nr_transport_addr_get_addrstring_and_port(nr_transport_addr *addr,
   383                                               nsACString *host, int32_t *port) {
   384   int r, _status;
   385   char addr_string[64];
   387   // We cannot directly use |nr_transport_addr.as_string| because it contains
   388   // more than ip address, therefore, we need to explicity convert it
   389   // from |nr_transport_addr_get_addrstring|.
   390   if ((r=nr_transport_addr_get_addrstring(addr, addr_string, sizeof(addr_string)))) {
   391     ABORT(r);
   392   }
   394   if ((r=nr_transport_addr_get_port(addr, port))) {
   395     ABORT(r);
   396   }
   398   *host = addr_string;
   400   _status=0;
   401 abort:
   402   return(_status);
   403 }
   405 // nr_socket APIs (as member functions)
   406 int NrSocket::create(nr_transport_addr *addr) {
   407   int r,_status;
   409   PRStatus status;
   410   PRNetAddr naddr;
   412   nsresult rv;
   413   nsCOMPtr<nsISocketTransportService> stservice =
   414       do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
   416   if (!NS_SUCCEEDED(rv)) {
   417     ABORT(R_INTERNAL);
   418   }
   420   if((r=nr_transport_addr_to_praddr(addr, &naddr)))
   421     ABORT(r);
   423   switch (addr->protocol) {
   424     case IPPROTO_UDP:
   425       if (!(fd_ = PR_NewUDPSocket())) {
   426         r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
   427         ABORT(R_INTERNAL);
   428       }
   429       break;
   430     case IPPROTO_TCP:
   431       if (!(fd_ = PR_NewTCPSocket())) {
   432         r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
   433         ABORT(R_INTERNAL);
   434       }
   435       break;
   436     default:
   437       ABORT(R_INTERNAL);
   438   }
   440   status = PR_Bind(fd_, &naddr);
   441   if (status != PR_SUCCESS) {
   442     r_log(LOG_GENERIC,LOG_CRIT,"Couldn't bind socket to address %s",
   443           addr->as_string);
   444     ABORT(R_INTERNAL);
   445   }
   447   r_log(LOG_GENERIC,LOG_DEBUG,"Creating socket %p with addr %s",
   448         fd_, addr->as_string);
   449   nr_transport_addr_copy(&my_addr_,addr);
   451   /* If we have a wildcard port, patch up the addr */
   452   if(nr_transport_addr_is_wildcard(addr)){
   453     status = PR_GetSockName(fd_, &naddr);
   454     if (status != PR_SUCCESS){
   455       r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket");
   456       ABORT(R_INTERNAL);
   457     }
   459     if((r=nr_praddr_to_transport_addr(&naddr,&my_addr_,addr->protocol,1)))
   460       ABORT(r);
   461   }
   464   // Set nonblocking
   465   PRSocketOptionData option;
   466   option.option = PR_SockOpt_Nonblocking;
   467   option.value.non_blocking = PR_TRUE;
   468   status = PR_SetSocketOption(fd_, &option);
   469   if (status != PR_SUCCESS) {
   470     r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking");
   471     ABORT(R_INTERNAL);
   472   }
   474   // Remember our thread.
   475   ststhread_ = do_QueryInterface(stservice, &rv);
   476   if (!NS_SUCCEEDED(rv))
   477     ABORT(R_INTERNAL);
   479   // Finally, register with the STS
   480   rv = stservice->AttachSocket(fd_, this);
   481   if (!NS_SUCCEEDED(rv)) {
   482     ABORT(R_INTERNAL);
   483   }
   485   _status = 0;
   487 abort:
   488   return(_status);
   489 }
   491 // This should be called on the STS thread.
   492 int NrSocket::sendto(const void *msg, size_t len,
   493                      int flags, nr_transport_addr *to) {
   494   ASSERT_ON_THREAD(ststhread_);
   495   int r,_status;
   496   PRNetAddr naddr;
   497   int32_t status;
   499   if ((r=nr_transport_addr_to_praddr(to, &naddr)))
   500     ABORT(r);
   502   if(fd_==nullptr)
   503     ABORT(R_EOD);
   505   if (nr_is_stun_request_message((UCHAR*)msg, len)) {
   506     // Global rate limiting for stun requests, to mitigate the ice hammer DoS
   507     // (see http://tools.ietf.org/html/draft-thomson-mmusic-ice-webrtc)
   509     // Tolerate rate of 8k/sec, for one second.
   510     static SimpleTokenBucket burst(8192*1, 8192);
   511     // Tolerate rate of 3.6k/sec over twenty seconds.
   512     static SimpleTokenBucket sustained(3686*20, 3686);
   514     // Check number of tokens in each bucket.
   515     if (burst.getTokens(UINT32_MAX) < len ||
   516         sustained.getTokens(UINT32_MAX) < len) {
   517       r_log(LOG_GENERIC, LOG_ERR,
   518                  "Global rate limit for STUN requests exceeded.");
   519       MOZ_ASSERT(false,
   520                  "Global rate limit for STUN requests exceeded. Go bug "
   521                  "bcampen@mozilla.com if you weren't intentionally spamming "
   522                  "ICE candidates, or don't know what that means.");
   523       ABORT(R_WOULDBLOCK);
   524     }
   526     // Take len tokens from both buckets.
   527     // (not threadsafe, but no problem since this is only called from STS)
   528     burst.getTokens(len);
   529     sustained.getTokens(len);
   530   }
   532   // TODO: Convert flags?
   533   status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT);
   534   if (status < 0 || (size_t)status != len) {
   535     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
   536       ABORT(R_WOULDBLOCK);
   538     r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s", to->as_string);
   539     ABORT(R_IO_ERROR);
   540   }
   542   _status=0;
   543 abort:
   544   return(_status);
   545 }
   547 int NrSocket::recvfrom(void * buf, size_t maxlen,
   548                        size_t *len, int flags,
   549                        nr_transport_addr *from) {
   550   ASSERT_ON_THREAD(ststhread_);
   551   int r,_status;
   552   PRNetAddr nfrom;
   553   int32_t status;
   555   status = PR_RecvFrom(fd_, buf, maxlen, flags, &nfrom, PR_INTERVAL_NO_WAIT);
   556   if (status <= 0) {
   557     r_log(LOG_GENERIC,LOG_ERR,"Error in recvfrom");
   558     ABORT(R_IO_ERROR);
   559   }
   560   *len=status;
   562   if((r=nr_praddr_to_transport_addr(&nfrom,from,my_addr_.protocol,0)))
   563     ABORT(r);
   565   //r_log(LOG_GENERIC,LOG_DEBUG,"Read %d bytes from %s",*len,addr->as_string);
   567   _status=0;
   568 abort:
   569   return(_status);
   570 }
   572 int NrSocket::getaddr(nr_transport_addr *addrp) {
   573   ASSERT_ON_THREAD(ststhread_);
   574   return nr_transport_addr_copy(addrp, &my_addr_);
   575 }
   577 // Close the socket so that the STS will detach and then kill it
   578 void NrSocket::close() {
   579   ASSERT_ON_THREAD(ststhread_);
   580   mCondition = NS_BASE_STREAM_CLOSED;
   581 }
   584 int NrSocket::connect(nr_transport_addr *addr) {
   585   ASSERT_ON_THREAD(ststhread_);
   586   int r,_status;
   587   PRNetAddr naddr;
   588   int32_t status;
   590   if ((r=nr_transport_addr_to_praddr(addr, &naddr)))
   591     ABORT(r);
   593   if(!fd_)
   594     ABORT(R_EOD);
   596   // Note: this just means we tried to connect, not that we
   597   // are actually live.
   598   connect_invoked_ = true;
   599   status = PR_Connect(fd_, &naddr, PR_INTERVAL_NO_WAIT);
   601   if (status != PR_SUCCESS) {
   602     if (PR_GetError() == PR_IN_PROGRESS_ERROR)
   603       ABORT(R_WOULDBLOCK);
   605     ABORT(R_IO_ERROR);
   606   }
   608   _status=0;
   609 abort:
   610   return(_status);
   611 }
   614 int NrSocket::write(const void *msg, size_t len, size_t *written) {
   615   ASSERT_ON_THREAD(ststhread_);
   616   int _status;
   617   int32_t status;
   619   if (!connect_invoked_)
   620     ABORT(R_FAILED);
   622   status = PR_Write(fd_, msg, len);
   623   if (status < 0) {
   624     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
   625       ABORT(R_WOULDBLOCK);
   626     ABORT(R_IO_ERROR);
   627   }
   629   *written = status;
   631   _status=0;
   632 abort:
   633   return _status;
   634 }
   636 int NrSocket::read(void* buf, size_t maxlen, size_t *len) {
   637   ASSERT_ON_THREAD(ststhread_);
   638   int _status;
   639   int32_t status;
   641   if (!connect_invoked_)
   642     ABORT(R_FAILED);
   644   status = PR_Read(fd_, buf, maxlen);
   645   if (status < 0) {
   646     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
   647       ABORT(R_WOULDBLOCK);
   648     ABORT(R_IO_ERROR);
   649   }
   650   if (status == 0)
   651     ABORT(R_EOD);
   653   *len = (size_t)status;  // Guaranteed to be > 0
   654   _status = 0;
   655 abort:
   656   return(_status);
   657 }
   659 // NrSocketIpc Implementation
   660 NS_IMPL_ISUPPORTS(NrSocketIpc, nsIUDPSocketInternal)
   662 NrSocketIpc::NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread)
   663     : err_(false),
   664       state_(NR_INIT),
   665       main_thread_(main_thread),
   666       monitor_("NrSocketIpc") {
   667 }
   669 // IUDPSocketInternal interfaces
   670 // callback while error happened in UDP socket operation
   671 NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &type,
   672                                              const nsACString &message,
   673                                              const nsACString &filename,
   674                                              uint32_t line_number,
   675                                              uint32_t column_number) {
   676   ASSERT_ON_THREAD(main_thread_);
   677   MOZ_ASSERT(type.EqualsLiteral("onerror"));
   679   r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d:%d",
   680         message.BeginReading(), filename.BeginReading(),
   681         line_number, column_number);
   683   ReentrantMonitorAutoEnter mon(monitor_);
   684   err_ = true;
   685   monitor_.NotifyAll();
   687   return NS_OK;
   688 }
   690 // callback while receiving UDP packet
   691 NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &type,
   692                                                     const nsACString &host,
   693                                                     uint16_t port, uint8_t *data,
   694                                                     uint32_t data_length) {
   695   ASSERT_ON_THREAD(main_thread_);
   696   MOZ_ASSERT(type.EqualsLiteral("ondata"));
   698   PRNetAddr addr;
   699   memset(&addr, 0, sizeof(addr));
   701   {
   702     ReentrantMonitorAutoEnter mon(monitor_);
   704     if (PR_SUCCESS != PR_StringToNetAddr(host.BeginReading(), &addr)) {
   705       err_ = true;
   706       MOZ_ASSERT(false, "Failed to convert remote host to PRNetAddr");
   707       return NS_OK;
   708     }
   710     // Use PR_IpAddrNull to avoid address being reset to 0.
   711     if (PR_SUCCESS != PR_SetNetAddr(PR_IpAddrNull, addr.raw.family, port, &addr)) {
   712       err_ = true;
   713       MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
   714       return NS_OK;
   715     }
   716   }
   718   nsAutoPtr<DataBuffer> buf(new DataBuffer(data, data_length));
   719   RefPtr<nr_udp_message> msg(new nr_udp_message(addr, buf));
   721   RUN_ON_THREAD(sts_thread_,
   722                 mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
   723                                       &NrSocketIpc::recv_callback_s,
   724                                       msg),
   725                 NS_DISPATCH_NORMAL);
   726   return NS_OK;
   727 }
   729 // callback while UDP socket is opened or closed
   730 NS_IMETHODIMP NrSocketIpc::CallListenerVoid(const nsACString &type) {
   731   ASSERT_ON_THREAD(main_thread_);
   732   if (type.EqualsLiteral("onopen")) {
   733     ReentrantMonitorAutoEnter mon(monitor_);
   735     uint16_t port;
   736     if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
   737       err_ = true;
   738       MOZ_ASSERT(false, "Failed to get local port");
   739       return NS_OK;
   740     }
   742     nsAutoCString address;
   743     if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
   744       err_ = true;
   745       MOZ_ASSERT(false, "Failed to get local address");
   746       return NS_OK;
   747     }
   749     PRNetAddr praddr;
   750     if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
   751       err_ = true;
   752       MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
   753       return NS_OK;
   754     }
   756     if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
   757       err_ = true;
   758       MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
   759       return NS_OK;
   760     }
   762     nr_transport_addr expected_addr;
   763     if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
   764       err_ = true;
   765       MOZ_ASSERT(false, "Failed to copy my_addr_");
   766     }
   768     if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
   769       err_ = true;
   770       MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
   771     }
   773     if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
   774                               NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
   775       err_ = true;
   776       MOZ_ASSERT(false, "Address of opened socket is not expected");
   777     }
   779     mon.NotifyAll();
   780   } else if (type.EqualsLiteral("onclose")) {
   781     // Already handled in UpdateReadyState, nothing to do here
   782   } else {
   783     MOZ_ASSERT(false, "Received unexpected event");
   784   }
   786   return NS_OK;
   787 }
   789 // callback while UDP packet is sent
   790 NS_IMETHODIMP NrSocketIpc::CallListenerSent(const nsACString &type,
   791                                             nsresult result) {
   792   ASSERT_ON_THREAD(main_thread_);
   793   MOZ_ASSERT(type.EqualsLiteral("onsent"));
   795   if (NS_FAILED(result)) {
   796     ReentrantMonitorAutoEnter mon(monitor_);
   797     err_ = true;
   798   }
   799   return NS_OK;
   800 }
   802 // callback for state update after every socket operation
   803 NS_IMETHODIMP NrSocketIpc::UpdateReadyState(const nsACString &readyState) {
   804   ASSERT_ON_THREAD(main_thread_);
   806   ReentrantMonitorAutoEnter mon(monitor_);
   808   if (readyState.EqualsLiteral("closed")) {
   809     MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
   810     state_ = NR_CLOSED;
   811   }
   813   return NS_OK;
   814 }
   816 // nr_socket public APIs
   817 int NrSocketIpc::create(nr_transport_addr *addr) {
   818   ASSERT_ON_THREAD(sts_thread_);
   820   int r, _status;
   821   nsresult rv;
   822   int32_t port;
   823   nsCString host;
   825   ReentrantMonitorAutoEnter mon(monitor_);
   827   if (state_ != NR_INIT) {
   828     ABORT(R_INTERNAL);
   829   }
   831   sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
   832   if (NS_FAILED(rv)) {
   833     MOZ_ASSERT(false, "Failed to get STS thread");
   834     ABORT(R_INTERNAL);
   835   }
   837   if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
   838     ABORT(r);
   839   }
   841   // wildcard address will be resolved at NrSocketIpc::CallListenerVoid
   842   if ((r=nr_transport_addr_copy(&my_addr_, addr))) {
   843     ABORT(r);
   844   }
   846   state_ = NR_CONNECTING;
   848   RUN_ON_THREAD(main_thread_,
   849                 mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
   850                                       &NrSocketIpc::create_m,
   851                                       host, static_cast<uint16_t>(port)),
   852                 NS_DISPATCH_NORMAL);
   854   // Wait until socket creation complete.
   855   mon.Wait();
   857   if (err_) {
   858     ABORT(R_INTERNAL);
   859   }
   861   state_ = NR_CONNECTED;
   863   _status = 0;
   864 abort:
   865   return(_status);
   866 }
   868 int NrSocketIpc::sendto(const void *msg, size_t len, int flags,
   869                         nr_transport_addr *to) {
   870   ASSERT_ON_THREAD(sts_thread_);
   872   ReentrantMonitorAutoEnter mon(monitor_);
   874   //If send err happened before, simply return the error.
   875   if (err_) {
   876     return R_IO_ERROR;
   877   }
   879   if (!socket_child_) {
   880     return R_EOD;
   881   }
   883   if (state_ != NR_CONNECTED) {
   884     return R_INTERNAL;
   885   }
   887   int r;
   888   net::NetAddr addr;
   889   if ((r=nr_transport_addr_to_netaddr(to, &addr))) {
   890     return r;
   891   }
   893   nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t*>(msg), len));
   895   RUN_ON_THREAD(main_thread_,
   896                 mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
   897                                       &NrSocketIpc::sendto_m,
   898                                       addr, buf),
   899                 NS_DISPATCH_NORMAL);
   900   return 0;
   901 }
   903 void NrSocketIpc::close() {
   904   ASSERT_ON_THREAD(sts_thread_);
   906   ReentrantMonitorAutoEnter mon(monitor_);
   907   state_ = NR_CLOSING;
   909   RUN_ON_THREAD(main_thread_,
   910                 mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
   911                                       &NrSocketIpc::close_m),
   912                 NS_DISPATCH_NORMAL);
   914   //remove all enqueued messages
   915   std::queue<RefPtr<nr_udp_message> > empty;
   916   std::swap(received_msgs_, empty);
   917 }
   919 int NrSocketIpc::recvfrom(void *buf, size_t maxlen, size_t *len, int flags,
   920                           nr_transport_addr *from) {
   921   ASSERT_ON_THREAD(sts_thread_);
   923   ReentrantMonitorAutoEnter mon(monitor_);
   925   int r, _status;
   926   uint32_t consumed_len;
   928   *len = 0;
   930   if (state_ != NR_CONNECTED) {
   931     ABORT(R_INTERNAL);
   932   }
   934   if (received_msgs_.empty()) {
   935     ABORT(R_WOULDBLOCK);
   936   }
   938   {
   939     RefPtr<nr_udp_message> msg(received_msgs_.front());
   941     received_msgs_.pop();
   943     if ((r=nr_praddr_to_transport_addr(&msg->from, from, IPPROTO_UDP, 0))) {
   944       err_ = true;
   945       MOZ_ASSERT(false, "Get bogus address for received UDP packet");
   946       ABORT(r);
   947     }
   949     consumed_len = std::min(maxlen, msg->data->len());
   950     if (consumed_len < msg->data->len()) {
   951       r_log(LOG_GENERIC, LOG_DEBUG, "Partial received UDP packet will be discard");
   952     }
   954     memcpy(buf, msg->data->data(), consumed_len);
   955     *len = consumed_len;
   956   }
   958   _status = 0;
   959 abort:
   960   return(_status);
   961 }
   963 int NrSocketIpc::getaddr(nr_transport_addr *addrp) {
   964   ASSERT_ON_THREAD(sts_thread_);
   966   ReentrantMonitorAutoEnter mon(monitor_);
   968   if (state_ != NR_CONNECTED) {
   969     return R_INTERNAL;
   970   }
   972   return nr_transport_addr_copy(addrp, &my_addr_);
   973 }
   975 int NrSocketIpc::connect(nr_transport_addr *addr) {
   976   MOZ_ASSERT(false);
   977   return R_INTERNAL;
   978 }
   980 int NrSocketIpc::write(const void *msg, size_t len, size_t *written) {
   981   MOZ_ASSERT(false);
   982   return R_INTERNAL;
   983 }
   985 int NrSocketIpc::read(void* buf, size_t maxlen, size_t *len) {
   986   MOZ_ASSERT(false);
   987   return R_INTERNAL;
   988 }
   990 // Main thread executors
   991 void NrSocketIpc::create_m(const nsACString &host, const uint16_t port) {
   992   ASSERT_ON_THREAD(main_thread_);
   994   ReentrantMonitorAutoEnter mon(monitor_);
   996   nsresult rv;
   997   socket_child_ = do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
   998   if (NS_FAILED(rv)) {
   999     err_ = true;
  1000     MOZ_ASSERT(false, "Failed to create UDPSocketChild");
  1003   socket_child_->SetFilterName(nsCString("stun"));
  1005   if (NS_FAILED(socket_child_->Bind(this, host, port))) {
  1006     err_ = true;
  1007     MOZ_ASSERT(false, "Failed to create UDP socket");
  1011 void NrSocketIpc::sendto_m(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf) {
  1012   ASSERT_ON_THREAD(main_thread_);
  1014   MOZ_ASSERT(socket_child_);
  1016   ReentrantMonitorAutoEnter mon(monitor_);
  1018   if (NS_FAILED(socket_child_->SendWithAddress(&addr,
  1019                                                buf->data(),
  1020                                                buf->len()))) {
  1021     err_ = true;
  1025 void NrSocketIpc::close_m() {
  1026   ASSERT_ON_THREAD(main_thread_);
  1028   if (socket_child_) {
  1029     socket_child_->Close();
  1030     socket_child_ = nullptr;
  1034 void NrSocketIpc::recv_callback_s(RefPtr<nr_udp_message> msg) {
  1035   ASSERT_ON_THREAD(sts_thread_);
  1038     ReentrantMonitorAutoEnter mon(monitor_);
  1039     if (state_ != NR_CONNECTED) {
  1040       return;
  1044   //enqueue received message
  1045   received_msgs_.push(msg);
  1047   if ((poll_flags() & PR_POLL_READ)) {
  1048     fire_callback(NR_ASYNC_WAIT_READ);
  1052 }  // close namespace
  1055 using namespace mozilla;
  1057 // Bridge to the nr_socket interface
  1058 static int nr_socket_local_destroy(void **objp);
  1059 static int nr_socket_local_sendto(void *obj,const void *msg, size_t len,
  1060                                   int flags, nr_transport_addr *to);
  1061 static int nr_socket_local_recvfrom(void *obj,void * restrict buf,
  1062   size_t maxlen, size_t *len, int flags, nr_transport_addr *from);
  1063 static int nr_socket_local_getfd(void *obj, NR_SOCKET *fd);
  1064 static int nr_socket_local_getaddr(void *obj, nr_transport_addr *addrp);
  1065 static int nr_socket_local_close(void *obj);
  1066 static int nr_socket_local_connect(void *sock, nr_transport_addr *addr);
  1067 static int nr_socket_local_write(void *obj,const void *msg, size_t len,
  1068                                  size_t *written);
  1069 static int nr_socket_local_read(void *obj,void * restrict buf, size_t maxlen,
  1070                                 size_t *len);
  1072 static nr_socket_vtbl nr_socket_local_vtbl={
  1073   1,
  1074   nr_socket_local_destroy,
  1075   nr_socket_local_sendto,
  1076   nr_socket_local_recvfrom,
  1077   nr_socket_local_getfd,
  1078   nr_socket_local_getaddr,
  1079   nr_socket_local_connect,
  1080   nr_socket_local_write,
  1081   nr_socket_local_read,
  1082   nr_socket_local_close
  1083 };
  1085 int nr_socket_local_create(nr_transport_addr *addr, nr_socket **sockp) {
  1086   NrSocketBase *sock = nullptr;
  1088   // create IPC bridge for content process
  1089   if (XRE_GetProcessType() == GeckoProcessType_Default) {
  1090     sock = new NrSocket();
  1091   } else {
  1092     nsCOMPtr<nsIThread> main_thread;
  1093     NS_GetMainThread(getter_AddRefs(main_thread));
  1094     sock = new NrSocketIpc(main_thread.get());
  1097   int r, _status;
  1099   r = sock->create(addr);
  1100   if (r)
  1101     ABORT(r);
  1103   r = nr_socket_create_int(static_cast<void *>(sock),
  1104                            sock->vtbl(), sockp);
  1105   if (r)
  1106     ABORT(r);
  1108   // Add a reference so that we can delete it in destroy()
  1109   sock->AddRef();
  1111   _status = 0;
  1113 abort:
  1114   if (_status) {
  1115     delete sock;
  1117   return _status;
  1121 static int nr_socket_local_destroy(void **objp) {
  1122   if(!objp || !*objp)
  1123     return 0;
  1125   NrSocketBase *sock = static_cast<NrSocketBase *>(*objp);
  1126   *objp=0;
  1128   sock->close();  // Signal STS that we want not to listen
  1129   sock->Release();  // Decrement the ref count
  1131   return 0;
  1134 static int nr_socket_local_sendto(void *obj,const void *msg, size_t len,
  1135                                   int flags, nr_transport_addr *addr) {
  1136   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
  1138   return sock->sendto(msg, len, flags, addr);
  1141 static int nr_socket_local_recvfrom(void *obj,void * restrict buf,
  1142                                     size_t maxlen, size_t *len, int flags,
  1143                                     nr_transport_addr *addr) {
  1144   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
  1146   return sock->recvfrom(buf, maxlen, len, flags, addr);
  1149 static int nr_socket_local_getfd(void *obj, NR_SOCKET *fd) {
  1150   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
  1152   *fd = sock;
  1154   return 0;
  1157 static int nr_socket_local_getaddr(void *obj, nr_transport_addr *addrp) {
  1158   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
  1160   return sock->getaddr(addrp);
  1164 static int nr_socket_local_close(void *obj) {
  1165   NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
  1167   sock->close();
  1169   return 0;
  1172 static int nr_socket_local_write(void *obj, const void *msg, size_t len,
  1173                                  size_t *written) {
  1174   NrSocket *sock = static_cast<NrSocket *>(obj);
  1176   return sock->write(msg, len, written);
  1179 static int nr_socket_local_read(void *obj, void * restrict buf, size_t maxlen,
  1180                                 size_t *len) {
  1181   NrSocket *sock = static_cast<NrSocket *>(obj);
  1183   return sock->read(buf, maxlen, len);
  1186 static int nr_socket_local_connect(void *obj, nr_transport_addr *addr) {
  1187   NrSocket *sock = static_cast<NrSocket *>(obj);
  1189   return sock->connect(addr);
  1192 // Implement async api
  1193 int NR_async_wait(NR_SOCKET sock, int how, NR_async_cb cb,void *cb_arg,
  1194                   char *function,int line) {
  1195   NrSocketBase *s = static_cast<NrSocketBase *>(sock);
  1197   return s->async_wait(how, cb, cb_arg, function, line);
  1200 int NR_async_cancel(NR_SOCKET sock,int how) {
  1201   NrSocketBase *s = static_cast<NrSocketBase *>(sock);
  1203   return s->cancel(how);
  1206 nr_socket_vtbl* NrSocketBase::vtbl() {
  1207   return &nr_socket_local_vtbl;

mercurial