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::ShutdownLoaders);
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(NS_LITERAL_CSTRING("mtransport"));
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_ISUPPORTS0(NrSocket)338 NS_IMPL_ISUPPORTS0(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(nr_transport_addr * addr,PRNetAddr * naddr)382 static int nr_transport_addr_to_praddr(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(nr_transport_addr * addr,net::NetAddr * naddr)447 static int nr_transport_addr_to_netaddr(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(nr_transport_addr * addr,nsACString * host,int32_t * port)533 int nr_transport_addr_get_addrstring_and_port(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: Add TLS layer with nsISocketProviderService?
632       if (my_addr_.tls_host[0] != '\0') ABORT(R_INTERNAL);
633 
634       if (!(fd_ = PR_OpenTCPSocket(naddr.raw.family))) {
635         r_log(LOG_GENERIC, LOG_CRIT,
636               "Couldn't create TCP socket, "
637               "family=%d, err=%d",
638               naddr.raw.family, PR_GetError());
639         ABORT(R_INTERNAL);
640       }
641       // Set ReuseAddr for TCP sockets to enable having several
642       // sockets bound to same local IP and port
643       PRSocketOptionData opt_reuseaddr;
644       opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
645       opt_reuseaddr.value.reuse_addr = PR_TRUE;
646       status = PR_SetSocketOption(fd_, &opt_reuseaddr);
647       if (status != PR_SUCCESS) {
648         r_log(LOG_GENERIC, LOG_CRIT,
649               "Couldn't set reuse addr socket option: %d", status);
650         ABORT(R_INTERNAL);
651       }
652       // And also set ReusePort for platforms supporting this socket option
653       PRSocketOptionData opt_reuseport;
654       opt_reuseport.option = PR_SockOpt_Reuseport;
655       opt_reuseport.value.reuse_port = PR_TRUE;
656       status = PR_SetSocketOption(fd_, &opt_reuseport);
657       if (status != PR_SUCCESS) {
658         if (PR_GetError() != PR_OPERATION_NOT_SUPPORTED_ERROR) {
659           r_log(LOG_GENERIC, LOG_CRIT,
660                 "Couldn't set reuse port socket option: %d", status);
661           ABORT(R_INTERNAL);
662         }
663       }
664       // Try to speedup packet delivery by disabling TCP Nagle
665       PRSocketOptionData opt_nodelay;
666       opt_nodelay.option = PR_SockOpt_NoDelay;
667       opt_nodelay.value.no_delay = PR_TRUE;
668       status = PR_SetSocketOption(fd_, &opt_nodelay);
669       if (status != PR_SUCCESS) {
670         r_log(LOG_GENERIC, LOG_WARNING,
671               "Couldn't set Nodelay socket option: %d", status);
672       }
673       break;
674     default:
675       ABORT(R_INTERNAL);
676   }
677 
678   status = PR_Bind(fd_, &naddr);
679   if (status != PR_SUCCESS) {
680     r_log(LOG_GENERIC, LOG_CRIT, "Couldn't bind socket to address %s",
681           addr->as_string);
682     ABORT(R_INTERNAL);
683   }
684 
685   r_log(LOG_GENERIC, LOG_DEBUG, "Creating socket %p with addr %s", fd_,
686         addr->as_string);
687   nr_transport_addr_copy(&my_addr_, addr);
688 
689   /* If we have a wildcard port, patch up the addr */
690   if (nr_transport_addr_is_wildcard(addr)) {
691     status = PR_GetSockName(fd_, &naddr);
692     if (status != PR_SUCCESS) {
693       r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket");
694       ABORT(R_INTERNAL);
695     }
696 
697     if ((r = nr_praddr_to_transport_addr(&naddr, &my_addr_, addr->protocol, 1)))
698       ABORT(r);
699   }
700 
701   // Set nonblocking
702   PRSocketOptionData opt_nonblock;
703   opt_nonblock.option = PR_SockOpt_Nonblocking;
704   opt_nonblock.value.non_blocking = PR_TRUE;
705   status = PR_SetSocketOption(fd_, &opt_nonblock);
706   if (status != PR_SUCCESS) {
707     r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking");
708     ABORT(R_INTERNAL);
709   }
710 
711   // Remember our thread.
712   ststhread_ = do_QueryInterface(stservice, &rv);
713   if (!NS_SUCCEEDED(rv)) ABORT(R_INTERNAL);
714 
715   // Finally, register with the STS
716   rv = stservice->AttachSocket(fd_, this);
717   if (!NS_SUCCEEDED(rv)) {
718     r_log(LOG_GENERIC, LOG_CRIT, "Couldn't attach socket to STS, rv=%u",
719           static_cast<unsigned>(rv));
720     ABORT(R_INTERNAL);
721   }
722 
723   _status = 0;
724 
725 abort:
726   return (_status);
727 }
728 
ShouldDrop(size_t len)729 static int ShouldDrop(size_t len) {
730   // Global rate limiting for stun requests, to mitigate the ice hammer DoS
731   // (see http://tools.ietf.org/html/draft-thomson-mmusic-ice-webrtc)
732 
733   // Tolerate rate of 8k/sec, for one second.
734   static SimpleTokenBucket burst(16384 * 1, 16384);
735   // Tolerate rate of 7.2k/sec over twenty seconds.
736   static SimpleTokenBucket sustained(7372 * 20, 7372);
737 
738   // Check number of tokens in each bucket.
739   if (burst.getTokens(UINT32_MAX) < len) {
740     r_log(LOG_GENERIC, LOG_ERR,
741           "Short term global rate limit for STUN requests exceeded.");
742 #ifdef MOZILLA_INTERNAL_API
743     nr_socket_short_term_violation_time = TimeStamp::Now();
744 #endif
745 
746 // Bug 1013007
747 #if !EARLY_BETA_OR_EARLIER
748     return R_WOULDBLOCK;
749 #else
750     MOZ_ASSERT(false,
751                "Short term global rate limit for STUN requests exceeded. Go "
752                "bug bcampen@mozilla.com if you weren't intentionally "
753                "spamming ICE candidates, or don't know what that means.");
754 #endif
755   }
756 
757   if (sustained.getTokens(UINT32_MAX) < len) {
758     r_log(LOG_GENERIC, LOG_ERR,
759           "Long term global rate limit for STUN requests exceeded.");
760 #ifdef MOZILLA_INTERNAL_API
761     nr_socket_long_term_violation_time = TimeStamp::Now();
762 #endif
763 // Bug 1013007
764 #if !EARLY_BETA_OR_EARLIER
765     return R_WOULDBLOCK;
766 #else
767     MOZ_ASSERT(false,
768                "Long term global rate limit for STUN requests exceeded. Go "
769                "bug bcampen@mozilla.com if you weren't intentionally "
770                "spamming ICE candidates, or don't know what that means.");
771 #endif
772   }
773 
774   // Take len tokens from both buckets.
775   // (not threadsafe, but no problem since this is only called from STS)
776   burst.getTokens(len);
777   sustained.getTokens(len);
778   return 0;
779 }
780 
781 // This should be called on the STS thread.
sendto(const void * msg,size_t len,int flags,nr_transport_addr * to)782 int NrSocket::sendto(const void* msg, size_t len, int flags,
783                      nr_transport_addr* to) {
784   ASSERT_ON_THREAD(ststhread_);
785   int r, _status;
786   PRNetAddr naddr;
787   int32_t status;
788 
789   if ((r = nr_transport_addr_to_praddr(to, &naddr))) ABORT(r);
790 
791   if (fd_ == nullptr) ABORT(R_EOD);
792 
793   if (nr_is_stun_request_message((UCHAR*)msg, len) && ShouldDrop(len)) {
794     ABORT(R_WOULDBLOCK);
795   }
796 
797   // TODO: Convert flags?
798   status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT);
799   if (status < 0 || (size_t)status != len) {
800     if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
801 
802     r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s: %d", to->as_string,
803           PR_GetError());
804     ABORT(R_IO_ERROR);
805   }
806 
807   _status = 0;
808 abort:
809   return (_status);
810 }
811 
recvfrom(void * buf,size_t maxlen,size_t * len,int flags,nr_transport_addr * from)812 int NrSocket::recvfrom(void* buf, size_t maxlen, size_t* len, int flags,
813                        nr_transport_addr* from) {
814   ASSERT_ON_THREAD(ststhread_);
815   int r, _status;
816   PRNetAddr nfrom;
817   int32_t status;
818 
819   status = PR_RecvFrom(fd_, buf, maxlen, flags, &nfrom, PR_INTERVAL_NO_WAIT);
820   if (status <= 0) {
821     if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
822     r_log(LOG_GENERIC, LOG_INFO, "Error in recvfrom: %d", (int)PR_GetError());
823     ABORT(R_IO_ERROR);
824   }
825   *len = status;
826 
827   if ((r = nr_praddr_to_transport_addr(&nfrom, from, my_addr_.protocol, 0)))
828     ABORT(r);
829 
830   // r_log(LOG_GENERIC,LOG_DEBUG,"Read %d bytes from %s",*len,addr->as_string);
831 
832   _status = 0;
833 abort:
834   return (_status);
835 }
836 
getaddr(nr_transport_addr * addrp)837 int NrSocket::getaddr(nr_transport_addr* addrp) {
838   ASSERT_ON_THREAD(ststhread_);
839   return nr_transport_addr_copy(addrp, &my_addr_);
840 }
841 
842 // Close the socket so that the STS will detach and then kill it
close()843 void NrSocket::close() {
844   ASSERT_ON_THREAD(ststhread_);
845   mCondition = NS_BASE_STREAM_CLOSED;
846   cancel(NR_ASYNC_WAIT_READ);
847   cancel(NR_ASYNC_WAIT_WRITE);
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) {
866       r_log(LOG_GENERIC, LOG_CRIT, "PR_Connect failed: %d", PR_GetError());
867       ABORT(R_IO_ERROR);
868     }
869   }
870 
871   // If our local address is wildcard, then fill in the
872   // address now.
873   if (nr_transport_addr_is_wildcard(&my_addr_)) {
874     getsockname_status = PR_GetSockName(fd_, &naddr);
875     if (getsockname_status != PR_SUCCESS) {
876       r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket");
877       ABORT(R_INTERNAL);
878     }
879 
880     if ((r = nr_praddr_to_transport_addr(&naddr, &my_addr_, addr->protocol, 1)))
881       ABORT(r);
882   }
883 
884   // Now return the WOULDBLOCK if needed.
885   if (connect_status != PR_SUCCESS) {
886     ABORT(R_WOULDBLOCK);
887   }
888 
889   _status = 0;
890 abort:
891   return (_status);
892 }
893 
write(const void * msg,size_t len,size_t * written)894 int NrSocket::write(const void* msg, size_t len, size_t* written) {
895   ASSERT_ON_THREAD(ststhread_);
896   int _status;
897   int32_t status;
898 
899   if (!connect_invoked_) ABORT(R_FAILED);
900 
901   status = PR_Write(fd_, msg, len);
902   if (status < 0) {
903     if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
904     r_log(LOG_GENERIC, LOG_INFO, "Error in write");
905     ABORT(R_IO_ERROR);
906   }
907 
908   *written = status;
909 
910   _status = 0;
911 abort:
912   return _status;
913 }
914 
read(void * buf,size_t maxlen,size_t * len)915 int NrSocket::read(void* buf, size_t maxlen, size_t* len) {
916   ASSERT_ON_THREAD(ststhread_);
917   int _status;
918   int32_t status;
919 
920   if (!connect_invoked_) ABORT(R_FAILED);
921 
922   status = PR_Read(fd_, buf, maxlen);
923   if (status < 0) {
924     if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
925     r_log(LOG_GENERIC, LOG_INFO, "Error in read");
926     ABORT(R_IO_ERROR);
927   }
928   if (status == 0) ABORT(R_EOD);
929 
930   *len = (size_t)status;  // Guaranteed to be > 0
931   _status = 0;
932 abort:
933   return (_status);
934 }
935 
listen(int backlog)936 int NrSocket::listen(int backlog) {
937   ASSERT_ON_THREAD(ststhread_);
938   int32_t status;
939   int _status;
940 
941   assert(fd_);
942   status = PR_Listen(fd_, backlog);
943   if (status != PR_SUCCESS) {
944     r_log(LOG_GENERIC, LOG_CRIT, "%s: PR_GetError() == %d", __FUNCTION__,
945           PR_GetError());
946     ABORT(R_IO_ERROR);
947   }
948 
949   _status = 0;
950 abort:
951   return (_status);
952 }
953 
accept(nr_transport_addr * addrp,nr_socket ** sockp)954 int NrSocket::accept(nr_transport_addr* addrp, nr_socket** sockp) {
955   ASSERT_ON_THREAD(ststhread_);
956   int _status, r;
957   PRStatus status;
958   PRFileDesc* prfd;
959   PRNetAddr nfrom;
960   NrSocket* sock = nullptr;
961   nsresult rv;
962   PRSocketOptionData opt_nonblock, opt_nodelay;
963   nsCOMPtr<nsISocketTransportService> stservice =
964       do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
965 
966   if (NS_FAILED(rv)) {
967     ABORT(R_INTERNAL);
968   }
969 
970   if (!fd_) ABORT(R_EOD);
971 
972   prfd = PR_Accept(fd_, &nfrom, PR_INTERVAL_NO_WAIT);
973 
974   if (!prfd) {
975     if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK);
976 
977     ABORT(R_IO_ERROR);
978   }
979 
980   sock = new NrSocket();
981 
982   sock->fd_ = prfd;
983   nr_transport_addr_copy(&sock->my_addr_, &my_addr_);
984 
985   if ((r = nr_praddr_to_transport_addr(&nfrom, addrp, my_addr_.protocol, 0)))
986     ABORT(r);
987 
988   // Set nonblocking
989   opt_nonblock.option = PR_SockOpt_Nonblocking;
990   opt_nonblock.value.non_blocking = PR_TRUE;
991   status = PR_SetSocketOption(prfd, &opt_nonblock);
992   if (status != PR_SUCCESS) {
993     r_log(LOG_GENERIC, LOG_CRIT,
994           "Failed to make accepted socket nonblocking: %d", status);
995     ABORT(R_INTERNAL);
996   }
997   // Disable TCP Nagle
998   opt_nodelay.option = PR_SockOpt_NoDelay;
999   opt_nodelay.value.no_delay = PR_TRUE;
1000   status = PR_SetSocketOption(prfd, &opt_nodelay);
1001   if (status != PR_SUCCESS) {
1002     r_log(LOG_GENERIC, LOG_WARNING,
1003           "Failed to set Nodelay on accepted socket: %d", status);
1004   }
1005 
1006   // Should fail only with OOM
1007   if ((r = nr_socket_create_int(static_cast<void*>(sock), sock->vtbl(), sockp)))
1008     ABORT(r);
1009 
1010   // Remember our thread.
1011   sock->ststhread_ = do_QueryInterface(stservice, &rv);
1012   if (NS_FAILED(rv)) ABORT(R_INTERNAL);
1013 
1014   // Finally, register with the STS
1015   rv = stservice->AttachSocket(prfd, sock);
1016   if (NS_FAILED(rv)) {
1017     ABORT(R_INTERNAL);
1018   }
1019 
1020   sock->connect_invoked_ = true;
1021 
1022   // Add a reference so that we can delete it in destroy()
1023   sock->AddRef();
1024   _status = 0;
1025 abort:
1026   if (_status) {
1027     delete sock;
1028   }
1029 
1030   return (_status);
1031 }
1032 
NS_IMPL_ISUPPORTS(NrUdpSocketIpcProxy,nsIUDPSocketInternal)1033 NS_IMPL_ISUPPORTS(NrUdpSocketIpcProxy, nsIUDPSocketInternal)
1034 
1035 nsresult NrUdpSocketIpcProxy::Init(const RefPtr<NrUdpSocketIpc>& socket) {
1036   nsresult rv;
1037   sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
1038   if (NS_FAILED(rv)) {
1039     MOZ_ASSERT(false, "Failed to get STS thread");
1040     return rv;
1041   }
1042 
1043   socket_ = socket;
1044   return NS_OK;
1045 }
1046 
~NrUdpSocketIpcProxy()1047 NrUdpSocketIpcProxy::~NrUdpSocketIpcProxy() {
1048   // Send our ref to STS to be released
1049   RUN_ON_THREAD(sts_thread_, mozilla::WrapRelease(socket_.forget()),
1050                 NS_DISPATCH_NORMAL);
1051 }
1052 
1053 // IUDPSocketInternal interfaces
1054 // callback while error happened in UDP socket operation
CallListenerError(const nsACString & message,const nsACString & filename,uint32_t line_number)1055 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerError(const nsACString& message,
1056                                                      const nsACString& filename,
1057                                                      uint32_t line_number) {
1058   return socket_->CallListenerError(message, filename, line_number);
1059 }
1060 
1061 // callback while receiving UDP packet
CallListenerReceivedData(const nsACString & host,uint16_t port,const nsTArray<uint8_t> & data)1062 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerReceivedData(
1063     const nsACString& host, uint16_t port, const nsTArray<uint8_t>& data) {
1064   return socket_->CallListenerReceivedData(host, port, data);
1065 }
1066 
1067 // callback while UDP socket is opened
CallListenerOpened()1068 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerOpened() {
1069   return socket_->CallListenerOpened();
1070 }
1071 
1072 // callback while UDP socket is connected
CallListenerConnected()1073 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerConnected() {
1074   return socket_->CallListenerConnected();
1075 }
1076 
1077 // callback while UDP socket is closed
CallListenerClosed()1078 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerClosed() {
1079   return socket_->CallListenerClosed();
1080 }
1081 
1082 // NrUdpSocketIpc Implementation
NrUdpSocketIpc()1083 NrUdpSocketIpc::NrUdpSocketIpc()
1084     : NrSocketIpc(GetIOThreadAndAddUse_s()),
1085       monitor_("NrUdpSocketIpc"),
1086       err_(false),
1087       state_(NR_INIT) {}
1088 
~NrUdpSocketIpc()1089 NrUdpSocketIpc::~NrUdpSocketIpc() {
1090 #if defined(MOZILLA_INTERNAL_API)
1091   // close(), but transfer the socket_child_ reference to die as well
1092   // destroy_i also dispatches back to STS to call ReleaseUse, to avoid shutting
1093   // down the IO thread before close() runs.
1094   RUN_ON_THREAD(
1095       io_thread_,
1096       mozilla::WrapRunnableNM(&NrUdpSocketIpc::destroy_i,
1097                               socket_child_.forget().take(), sts_thread_),
1098       NS_DISPATCH_NORMAL);
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,nr_transport_addr * to)1302 int NrUdpSocketIpc::sendto(const void* msg, size_t len, int flags,
1303                            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   if (state_ != NR_CONNECTED) {
1407     return R_INTERNAL;
1408   }
1409 
1410   return nr_transport_addr_copy(addrp, &my_addr_);
1411 }
1412 
connect(nr_transport_addr * addr)1413 int NrUdpSocketIpc::connect(nr_transport_addr* addr) {
1414   int r, _status;
1415   int32_t port;
1416   nsCString host;
1417 
1418   ReentrantMonitorAutoEnter mon(monitor_);
1419   r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::connect(%s) this=%p",
1420         addr->as_string, (void*)this);
1421 
1422   if ((r = nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
1423     ABORT(r);
1424   }
1425 
1426   RUN_ON_THREAD(io_thread_,
1427                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
1428                                       &NrUdpSocketIpc::connect_i, host,
1429                                       static_cast<uint16_t>(port)),
1430                 NS_DISPATCH_NORMAL);
1431 
1432   // Wait until connect() completes.
1433   mon.Wait();
1434 
1435   r_log(LOG_GENERIC, LOG_DEBUG,
1436         "NrUdpSocketIpc::connect this=%p completed err_ = %s", (void*)this,
1437         err_ ? "true" : "false");
1438 
1439   if (err_) {
1440     ABORT(R_INTERNAL);
1441   }
1442 
1443   _status = 0;
1444 abort:
1445   return _status;
1446 }
1447 
write(const void * msg,size_t len,size_t * written)1448 int NrUdpSocketIpc::write(const void* msg, size_t len, size_t* written) {
1449   MOZ_ASSERT(false);
1450   return R_INTERNAL;
1451 }
1452 
read(void * buf,size_t maxlen,size_t * len)1453 int NrUdpSocketIpc::read(void* buf, size_t maxlen, size_t* len) {
1454   MOZ_ASSERT(false);
1455   return R_INTERNAL;
1456 }
1457 
listen(int backlog)1458 int NrUdpSocketIpc::listen(int backlog) {
1459   MOZ_ASSERT(false);
1460   return R_INTERNAL;
1461 }
1462 
accept(nr_transport_addr * addrp,nr_socket ** sockp)1463 int NrUdpSocketIpc::accept(nr_transport_addr* addrp, nr_socket** sockp) {
1464   MOZ_ASSERT(false);
1465   return R_INTERNAL;
1466 }
1467 
1468 // IO thread executors
create_i(const nsACString & host,const uint16_t port)1469 void NrUdpSocketIpc::create_i(const nsACString& host, const uint16_t port) {
1470   ASSERT_ON_THREAD(io_thread_);
1471 
1472   uint32_t minBuffSize = 0;
1473   RefPtr<dom::UDPSocketChild> socketChild = new dom::UDPSocketChild();
1474 
1475   // This can spin the event loop; don't do that with the monitor held
1476   socketChild->SetBackgroundSpinsEvents();
1477 
1478   ReentrantMonitorAutoEnter mon(monitor_);
1479   if (!socket_child_) {
1480     socket_child_ = socketChild;
1481     socket_child_->SetFilterName(
1482         nsCString(NS_NETWORK_SOCKET_FILTER_HANDLER_STUN_SUFFIX));
1483   } else {
1484     socketChild = nullptr;
1485   }
1486 
1487   RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy);
1488   nsresult rv = proxy->Init(this);
1489   if (NS_FAILED(rv)) {
1490     err_ = true;
1491     mon.NotifyAll();
1492     return;
1493   }
1494 
1495 #ifdef XP_WIN
1496   if (!mozilla::IsWin8OrLater()) {
1497     // Increase default receive and send buffer size on <= Win7 to be able to
1498     // receive and send an unpaced HD (>= 720p = 1280x720 - I Frame ~ 21K size)
1499     // stream without losing packets.
1500     // Manual testing showed that 100K buffer size was not enough and the
1501     // packet loss dis-appeared with 256K buffer size.
1502     // See bug 1252769 for future improvements of this.
1503     minBuffSize = 256 * 1024;
1504   }
1505 #endif
1506   // XXX bug 1126232 - don't use null Principal!
1507   if (NS_FAILED(socket_child_->Bind(proxy, nullptr, host, port,
1508                                     /* addressReuse = */ false,
1509                                     /* loopback = */ false,
1510                                     /* recv buffer size */ minBuffSize,
1511                                     /* send buffer size */ minBuffSize,
1512                                     /* mainThreadEventTarget */ nullptr))) {
1513     err_ = true;
1514     MOZ_ASSERT(false, "Failed to create UDP socket");
1515     mon.NotifyAll();
1516     return;
1517   }
1518 }
1519 
connect_i(const nsACString & host,const uint16_t port)1520 void NrUdpSocketIpc::connect_i(const nsACString& host, const uint16_t port) {
1521   ASSERT_ON_THREAD(io_thread_);
1522   nsresult rv;
1523   ReentrantMonitorAutoEnter mon(monitor_);
1524 
1525   RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy);
1526   rv = proxy->Init(this);
1527   if (NS_FAILED(rv)) {
1528     err_ = true;
1529     mon.NotifyAll();
1530     return;
1531   }
1532 
1533   socket_child_->Connect(proxy, host, port);
1534 }
1535 
sendto_i(const net::NetAddr & addr,UniquePtr<MediaPacket> buf)1536 void NrUdpSocketIpc::sendto_i(const net::NetAddr& addr,
1537                               UniquePtr<MediaPacket> buf) {
1538   ASSERT_ON_THREAD(io_thread_);
1539 
1540   ReentrantMonitorAutoEnter mon(monitor_);
1541 
1542   if (!socket_child_) {
1543     MOZ_ASSERT(false);
1544     err_ = true;
1545     return;
1546   }
1547   if (NS_FAILED(
1548           socket_child_->SendWithAddress(&addr, buf->data(), buf->len()))) {
1549     err_ = true;
1550   }
1551 }
1552 
close_i()1553 void NrUdpSocketIpc::close_i() {
1554   ASSERT_ON_THREAD(io_thread_);
1555 
1556   if (socket_child_) {
1557     socket_child_->Close();
1558     socket_child_ = nullptr;
1559   }
1560 }
1561 
1562 #if defined(MOZILLA_INTERNAL_API)
1563 
ReleaseIOThread_s()1564 static void ReleaseIOThread_s() { sThread->ReleaseUse(); }
1565 
1566 // close(), but transfer the socket_child_ reference to die as well
1567 // static
destroy_i(dom::UDPSocketChild * aChild,const nsCOMPtr<nsIEventTarget> & aStsThread)1568 void NrUdpSocketIpc::destroy_i(dom::UDPSocketChild* aChild,
1569                                const nsCOMPtr<nsIEventTarget>& aStsThread) {
1570   RefPtr<dom::UDPSocketChild> socket_child_ref =
1571       already_AddRefed<dom::UDPSocketChild>(aChild);
1572   if (socket_child_ref) {
1573     socket_child_ref->Close();
1574   }
1575 
1576   RUN_ON_THREAD(aStsThread, WrapRunnableNM(&ReleaseIOThread_s),
1577                 NS_DISPATCH_NORMAL);
1578 }
1579 #endif
1580 
recv_callback_s(RefPtr<nr_udp_message> msg)1581 void NrUdpSocketIpc::recv_callback_s(RefPtr<nr_udp_message> msg) {
1582   ASSERT_ON_THREAD(sts_thread_);
1583 
1584   {
1585     ReentrantMonitorAutoEnter mon(monitor_);
1586     if (state_ != NR_CONNECTED) {
1587       return;
1588     }
1589   }
1590 
1591   // enqueue received message
1592   received_msgs_.push(msg);
1593 
1594   if ((poll_flags() & PR_POLL_READ)) {
1595     fire_callback(NR_ASYNC_WAIT_READ);
1596   }
1597 }
1598 
1599 }  // namespace mozilla
1600 
1601 using namespace mozilla;
1602 
1603 // Bridge to the nr_socket interface
1604 static int nr_socket_local_destroy(void** objp);
1605 static int nr_socket_local_sendto(void* obj, const void* msg, size_t len,
1606                                   int flags, nr_transport_addr* to);
1607 static int nr_socket_local_recvfrom(void* obj, void* restrict buf,
1608                                     size_t maxlen, size_t* len, int flags,
1609                                     nr_transport_addr* from);
1610 static int nr_socket_local_getfd(void* obj, NR_SOCKET* fd);
1611 static int nr_socket_local_getaddr(void* obj, nr_transport_addr* addrp);
1612 static int nr_socket_local_close(void* obj);
1613 static int nr_socket_local_connect(void* sock, nr_transport_addr* addr);
1614 static int nr_socket_local_write(void* obj, const void* msg, size_t len,
1615                                  size_t* written);
1616 static int nr_socket_local_read(void* obj, void* restrict buf, size_t maxlen,
1617                                 size_t* len);
1618 static int nr_socket_local_listen(void* obj, int backlog);
1619 static int nr_socket_local_accept(void* obj, nr_transport_addr* addrp,
1620                                   nr_socket** sockp);
1621 
1622 static nr_socket_vtbl nr_socket_local_vtbl = {2,
1623                                               nr_socket_local_destroy,
1624                                               nr_socket_local_sendto,
1625                                               nr_socket_local_recvfrom,
1626                                               nr_socket_local_getfd,
1627                                               nr_socket_local_getaddr,
1628                                               nr_socket_local_connect,
1629                                               nr_socket_local_write,
1630                                               nr_socket_local_read,
1631                                               nr_socket_local_close,
1632                                               nr_socket_local_listen,
1633                                               nr_socket_local_accept};
1634 
1635 /* static */
CreateSocket(nr_transport_addr * addr,RefPtr<NrSocketBase> * sock,const std::shared_ptr<NrSocketProxyConfig> & config)1636 int NrSocketBase::CreateSocket(
1637     nr_transport_addr* addr, RefPtr<NrSocketBase>* sock,
1638     const std::shared_ptr<NrSocketProxyConfig>& config) {
1639   int r, _status;
1640 
1641   if (IsForbiddenAddress(addr)) {
1642     ABORT(R_REJECTED);
1643   }
1644 
1645   if (config && config->GetForceProxy() && addr->protocol == IPPROTO_UDP) {
1646     ABORT(R_REJECTED);
1647   }
1648 
1649   // create IPC bridge for content process
1650   if (XRE_IsParentProcess()) {
1651     // TODO: Make NrTcpSocket work on the parent process
1652     *sock = new NrSocket();
1653   } else if (XRE_IsSocketProcess()) {
1654     if (addr->protocol == IPPROTO_TCP) {
1655       *sock = new NrTcpSocket(config);
1656     } else {
1657       *sock = new NrSocket();
1658     }
1659   } else {
1660     if (addr->protocol == IPPROTO_TCP) {
1661       *sock = new NrTcpSocket(config);
1662     } else {
1663       *sock = new NrUdpSocketIpc();
1664     }
1665   }
1666 
1667   r = (*sock)->create(addr);
1668   if (r) ABORT(r);
1669 
1670   _status = 0;
1671 abort:
1672   if (_status) {
1673     *sock = nullptr;
1674   }
1675   return _status;
1676 }
1677 
1678 // static
IsForbiddenAddress(nr_transport_addr * addr)1679 bool NrSocketBase::IsForbiddenAddress(nr_transport_addr* addr) {
1680   int r, port;
1681 
1682   r = nr_transport_addr_get_port(addr, &port);
1683   if (r) {
1684     return true;
1685   }
1686 
1687   // allow auto assigned ports
1688   if (port != 0) {
1689     // Don't need to check an override scheme
1690     nsresult rv = NS_CheckPortSafety(port, nullptr);
1691     if (NS_FAILED(rv)) {
1692       return true;
1693     }
1694   }
1695 
1696   return false;
1697 }
1698 
nr_socket_local_destroy(void ** objp)1699 static int nr_socket_local_destroy(void** objp) {
1700   if (!objp || !*objp) return 0;
1701 
1702   NrSocketBase* sock = static_cast<NrSocketBase*>(*objp);
1703   *objp = nullptr;
1704 
1705   sock->close();    // Signal STS that we want not to listen
1706   sock->Release();  // Decrement the ref count
1707 
1708   return 0;
1709 }
1710 
nr_socket_local_sendto(void * obj,const void * msg,size_t len,int flags,nr_transport_addr * addr)1711 static int nr_socket_local_sendto(void* obj, const void* msg, size_t len,
1712                                   int flags, nr_transport_addr* addr) {
1713   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1714 
1715   return sock->sendto(msg, len, flags, addr);
1716 }
1717 
nr_socket_local_recvfrom(void * obj,void * restrict buf,size_t maxlen,size_t * len,int flags,nr_transport_addr * addr)1718 static int nr_socket_local_recvfrom(void* obj, void* restrict buf,
1719                                     size_t maxlen, size_t* len, int flags,
1720                                     nr_transport_addr* addr) {
1721   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1722 
1723   return sock->recvfrom(buf, maxlen, len, flags, addr);
1724 }
1725 
nr_socket_local_getfd(void * obj,NR_SOCKET * fd)1726 static int nr_socket_local_getfd(void* obj, NR_SOCKET* fd) {
1727   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1728 
1729   *fd = sock;
1730 
1731   return 0;
1732 }
1733 
nr_socket_local_getaddr(void * obj,nr_transport_addr * addrp)1734 static int nr_socket_local_getaddr(void* obj, nr_transport_addr* addrp) {
1735   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1736 
1737   return sock->getaddr(addrp);
1738 }
1739 
nr_socket_local_close(void * obj)1740 static int nr_socket_local_close(void* obj) {
1741   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1742 
1743   sock->close();
1744 
1745   return 0;
1746 }
1747 
nr_socket_local_write(void * obj,const void * msg,size_t len,size_t * written)1748 static int nr_socket_local_write(void* obj, const void* msg, size_t len,
1749                                  size_t* written) {
1750   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1751 
1752   return sock->write(msg, len, written);
1753 }
1754 
nr_socket_local_read(void * obj,void * restrict buf,size_t maxlen,size_t * len)1755 static int nr_socket_local_read(void* obj, void* restrict buf, size_t maxlen,
1756                                 size_t* len) {
1757   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1758 
1759   return sock->read(buf, maxlen, len);
1760 }
1761 
nr_socket_local_connect(void * obj,nr_transport_addr * addr)1762 static int nr_socket_local_connect(void* obj, nr_transport_addr* addr) {
1763   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1764 
1765   return sock->connect(addr);
1766 }
1767 
nr_socket_local_listen(void * obj,int backlog)1768 static int nr_socket_local_listen(void* obj, int backlog) {
1769   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1770 
1771   return sock->listen(backlog);
1772 }
1773 
nr_socket_local_accept(void * obj,nr_transport_addr * addrp,nr_socket ** sockp)1774 static int nr_socket_local_accept(void* obj, nr_transport_addr* addrp,
1775                                   nr_socket** sockp) {
1776   NrSocketBase* sock = static_cast<NrSocketBase*>(obj);
1777 
1778   return sock->accept(addrp, sockp);
1779 }
1780 
1781 // Implement async api
NR_async_wait(NR_SOCKET sock,int how,NR_async_cb cb,void * cb_arg,char * function,int line)1782 int NR_async_wait(NR_SOCKET sock, int how, NR_async_cb cb, void* cb_arg,
1783                   char* function, int line) {
1784   NrSocketBase* s = static_cast<NrSocketBase*>(sock);
1785 
1786   return s->async_wait(how, cb, cb_arg, function, line);
1787 }
1788 
NR_async_cancel(NR_SOCKET sock,int how)1789 int NR_async_cancel(NR_SOCKET sock, int how) {
1790   NrSocketBase* s = static_cast<NrSocketBase*>(sock);
1791 
1792   return s->cancel(how);
1793 }
1794 
vtbl()1795 nr_socket_vtbl* NrSocketBase::vtbl() { return &nr_socket_local_vtbl; }
1796