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