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