Coverage Report

Created: 2018-09-25 14:53

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