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