Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/media/mtransport/test_nr_socket.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
*/
8
9
/*
10
Based partially on original code from nICEr and nrappkit.
11
12
nICEr copyright:
13
14
Copyright (c) 2007, Adobe Systems, Incorporated
15
All rights reserved.
16
17
Redistribution and use in source and binary forms, with or without
18
modification, are permitted provided that the following conditions are
19
met:
20
21
* Redistributions of source code must retain the above copyright
22
  notice, this list of conditions and the following disclaimer.
23
24
* Redistributions in binary form must reproduce the above copyright
25
  notice, this list of conditions and the following disclaimer in the
26
  documentation and/or other materials provided with the distribution.
27
28
* Neither the name of Adobe Systems, Network Resonance nor the names of its
29
  contributors may be used to endorse or promote products derived from
30
  this software without specific prior written permission.
31
32
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
35
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
39
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
40
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
42
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
44
45
nrappkit copyright:
46
47
   Copyright (C) 2001-2003, Network Resonance, Inc.
48
   Copyright (C) 2006, Network Resonance, Inc.
49
   All Rights Reserved
50
51
   Redistribution and use in source and binary forms, with or without
52
   modification, are permitted provided that the following conditions
53
   are met:
54
55
   1. Redistributions of source code must retain the above copyright
56
      notice, this list of conditions and the following disclaimer.
57
   2. Redistributions in binary form must reproduce the above copyright
58
      notice, this list of conditions and the following disclaimer in the
59
      documentation and/or other materials provided with the distribution.
60
   3. Neither the name of Network Resonance, Inc. nor the name of any
61
      contributors to this software may be used to endorse or promote
62
      products derived from this software without specific prior written
63
      permission.
64
65
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
66
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68
   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
69
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
70
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
71
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
72
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
73
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
74
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
75
   POSSIBILITY OF SUCH DAMAGE.
76
77
78
   ekr@rtfm.com  Thu Dec 20 20:14:49 2001
79
*/
80
81
// Original author: bcampen@mozilla.com [:bwc]
82
83
extern "C" {
84
#include "stun_msg.h" // for NR_STUN_MAX_MESSAGE_SIZE
85
#include "nr_api.h"
86
#include "async_wait.h"
87
#include "async_timer.h"
88
#include "nr_socket.h"
89
#include "nr_socket_local.h"
90
#include "stun_hint.h"
91
#include "transport_addr.h"
92
}
93
94
#include "mozilla/RefPtr.h"
95
#include "test_nr_socket.h"
96
#include "runnable_utils.h"
97
98
namespace mozilla {
99
100
static int test_nat_socket_create(void *obj,
101
                                  nr_transport_addr *addr,
102
0
                                  nr_socket **sockp) {
103
0
  RefPtr<NrSocketBase> sock = new TestNrSocket(static_cast<TestNat*>(obj));
104
0
105
0
  int r, _status;
106
0
107
0
  r = sock->create(addr);
108
0
  if (r)
109
0
    ABORT(r);
110
0
111
0
  r = nr_socket_create_int(static_cast<void *>(sock),
112
0
                           sock->vtbl(), sockp);
113
0
  if (r)
114
0
    ABORT(r);
115
0
116
0
  _status = 0;
117
0
118
0
  {
119
0
    // We will release this reference in destroy(), not exactly the normal
120
0
    // ownership model, but it is what it is.
121
0
    NrSocketBase *dummy = sock.forget().take();
122
0
    (void)dummy;
123
0
  }
124
0
125
0
abort:
126
0
  return _status;
127
0
}
128
129
0
static int test_nat_socket_factory_destroy(void **obj) {
130
0
  TestNat *nat = static_cast<TestNat*>(*obj);
131
0
  *obj = nullptr;
132
0
  nat->Release();
133
0
  return 0;
134
0
}
135
136
static nr_socket_factory_vtbl test_nat_socket_factory_vtbl = {
137
  test_nat_socket_create,
138
  test_nat_socket_factory_destroy
139
};
140
141
/* static */
142
TestNat::NatBehavior
143
0
TestNat::ToNatBehavior(const std::string& type) {
144
0
  if (!type.compare("ENDPOINT_INDEPENDENT")) {
145
0
    return TestNat::ENDPOINT_INDEPENDENT;
146
0
  }
147
0
  if (!type.compare("ADDRESS_DEPENDENT")) {
148
0
    return TestNat::ADDRESS_DEPENDENT;
149
0
  }
150
0
  if (!type.compare("PORT_DEPENDENT")) {
151
0
    return TestNat::PORT_DEPENDENT;
152
0
  }
153
0
154
0
  MOZ_ASSERT(false, "Invalid NAT behavior");
155
0
  return TestNat::ENDPOINT_INDEPENDENT;
156
0
}
157
158
0
bool TestNat::has_port_mappings() const {
159
0
  for (TestNrSocket *sock : sockets_) {
160
0
    if (sock->has_port_mappings()) {
161
0
      return true;
162
0
    }
163
0
  }
164
0
  return false;
165
0
}
166
167
0
bool TestNat::is_my_external_tuple(const nr_transport_addr &addr) const {
168
0
  for (TestNrSocket *sock : sockets_) {
169
0
    if (sock->is_my_external_tuple(addr)) {
170
0
      return true;
171
0
    }
172
0
  }
173
0
174
0
  return false;
175
0
}
176
177
0
bool TestNat::is_an_internal_tuple(const nr_transport_addr &addr) const {
178
0
  for (TestNrSocket *sock : sockets_) {
179
0
    nr_transport_addr addr_behind_nat;
180
0
    if (sock->getaddr(&addr_behind_nat)) {
181
0
      MOZ_CRASH("TestNrSocket::getaddr failed!");
182
0
    }
183
0
184
0
    // TODO(bug 1170299): Remove const_cast when no longer necessary
185
0
    if (!nr_transport_addr_cmp(const_cast<nr_transport_addr*>(&addr),
186
0
                               &addr_behind_nat,
187
0
                               NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
188
0
      return true;
189
0
    }
190
0
  }
191
0
  return false;
192
0
}
193
194
0
int TestNat::create_socket_factory(nr_socket_factory **factorypp) {
195
0
  int r = nr_socket_factory_create_int(this,
196
0
                                       &test_nat_socket_factory_vtbl,
197
0
                                       factorypp);
198
0
  if (!r) {
199
0
    AddRef();
200
0
  }
201
0
  return r;
202
0
}
203
204
TestNrSocket::TestNrSocket(TestNat *nat)
205
  : nat_(nat),
206
    tls_(false),
207
0
    timer_handle_(nullptr) {
208
0
  nat_->insert_socket(this);
209
0
}
210
211
0
TestNrSocket::~TestNrSocket() {
212
0
  nat_->erase_socket(this);
213
0
}
214
215
RefPtr<NrSocketBase> TestNrSocket::create_external_socket(
216
0
    const nr_transport_addr &dest_addr) const {
217
0
  MOZ_ASSERT(nat_->enabled_);
218
0
  MOZ_ASSERT(!nat_->is_an_internal_tuple(dest_addr));
219
0
220
0
  int r;
221
0
  nr_transport_addr nat_external_addr;
222
0
223
0
  // Open the socket on an arbitrary port, on the same address.
224
0
  // TODO(bug 1170299): Remove const_cast when no longer necessary
225
0
  if ((r = nr_transport_addr_copy(
226
0
             &nat_external_addr,
227
0
             const_cast<nr_transport_addr*>(&internal_socket_->my_addr())))) {
228
0
    r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in nr_transport_addr_copy: %d",
229
0
                                __FUNCTION__, r);
230
0
    return nullptr;
231
0
  }
232
0
233
0
  if ((r = nr_transport_addr_set_port(&nat_external_addr, 0))) {
234
0
    r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in nr_transport_addr_set_port: %d",
235
0
                                __FUNCTION__, r);
236
0
    return nullptr;
237
0
  }
238
0
239
0
  RefPtr<NrSocketBase> external_socket;
240
0
  r = NrSocketBase::CreateSocket(&nat_external_addr, &external_socket);
241
0
242
0
  if (r) {
243
0
    r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in NrSocket::create: %d",
244
0
                                __FUNCTION__, r);
245
0
    return nullptr;
246
0
  }
247
0
248
0
  return external_socket;
249
0
}
250
251
0
int TestNrSocket::create(nr_transport_addr *addr) {
252
0
  if (addr->tls_host[0] != '\0') {
253
0
    tls_ = true;
254
0
  }
255
0
256
0
  return NrSocketBase::CreateSocket(addr, &internal_socket_);
257
0
}
258
259
0
int TestNrSocket::getaddr(nr_transport_addr *addrp) {
260
0
  return internal_socket_->getaddr(addrp);
261
0
}
262
263
0
void TestNrSocket::close() {
264
0
  if (timer_handle_) {
265
0
    NR_async_timer_cancel(timer_handle_);
266
0
    timer_handle_ = nullptr;
267
0
  }
268
0
  internal_socket_->close();
269
0
  for (RefPtr<PortMapping>& port_mapping : port_mappings_) {
270
0
    port_mapping->external_socket_->close();
271
0
  }
272
0
}
273
274
0
int TestNrSocket::listen(int backlog) {
275
0
  MOZ_ASSERT(internal_socket_->my_addr().protocol == IPPROTO_TCP);
276
0
  r_log(LOG_GENERIC, LOG_DEBUG,
277
0
        "TestNrSocket %s listening",
278
0
        internal_socket_->my_addr().as_string);
279
0
280
0
  return internal_socket_->listen(backlog);
281
0
}
282
283
0
int TestNrSocket::accept(nr_transport_addr *addrp, nr_socket **sockp) {
284
0
  MOZ_ASSERT(internal_socket_->my_addr().protocol == IPPROTO_TCP);
285
0
  int r = internal_socket_->accept(addrp, sockp);
286
0
  if (r) {
287
0
    return r;
288
0
  }
289
0
290
0
  if (nat_->enabled_ && !nat_->is_an_internal_tuple(*addrp)) {
291
0
    nr_socket_destroy(sockp);
292
0
    return R_IO_ERROR;
293
0
  }
294
0
295
0
  return 0;
296
0
}
297
298
0
void TestNrSocket::process_delayed_cb(NR_SOCKET s, int how, void *cb_arg) {
299
0
  DeferredPacket *op = static_cast<DeferredPacket *>(cb_arg);
300
0
  op->socket_->timer_handle_ = nullptr;
301
0
  r_log(LOG_GENERIC, LOG_DEBUG,
302
0
        "TestNrSocket %s sending delayed STUN response",
303
0
        op->internal_socket_->my_addr().as_string);
304
0
  op->internal_socket_->sendto(op->buffer_.data(), op->buffer_.len(),
305
0
                               op->flags_, &op->to_);
306
0
307
0
  delete op;
308
0
}
309
310
int TestNrSocket::sendto(const void *msg, size_t len,
311
0
                         int flags, nr_transport_addr *to) {
312
0
  MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
313
0
314
0
  if (nat_->nat_delegate_ && nat_->nat_delegate_->on_sendto(nat_, msg, len, flags, to)) {
315
0
    return 0;
316
0
  }
317
0
318
0
  UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg));
319
0
  if (nat_->block_stun_ &&
320
0
      nr_is_stun_message(buf, len)) {
321
0
    return 0;
322
0
  }
323
0
324
0
  /* TODO: improve the functionality of this in bug 1253657 */
325
0
  if (!nat_->enabled_ || nat_->is_an_internal_tuple(*to)) {
326
0
    if (nat_->delay_stun_resp_ms_ &&
327
0
        nr_is_stun_response_message(buf, len)) {
328
0
      NR_ASYNC_TIMER_SET(nat_->delay_stun_resp_ms_,
329
0
                         process_delayed_cb,
330
0
                         new DeferredPacket(this, msg, len, flags, to,
331
0
                                            internal_socket_),
332
0
                         &timer_handle_);
333
0
      return 0;
334
0
    }
335
0
    return internal_socket_->sendto(msg, len, flags, to);
336
0
  }
337
0
338
0
  destroy_stale_port_mappings();
339
0
340
0
  if (to->protocol == IPPROTO_UDP && nat_->block_udp_) {
341
0
    // Silently eat the packet
342
0
    return 0;
343
0
  }
344
0
345
0
  // Choose our port mapping based on our most selective criteria
346
0
  PortMapping *port_mapping = get_port_mapping(*to,
347
0
                                               std::max(nat_->filtering_type_,
348
0
                                                        nat_->mapping_type_));
349
0
350
0
  if (!port_mapping) {
351
0
    // See if we have already made the external socket we need to use.
352
0
    PortMapping *similar_port_mapping =
353
0
      get_port_mapping(*to, nat_->mapping_type_);
354
0
    RefPtr<NrSocketBase> external_socket;
355
0
356
0
    if (similar_port_mapping) {
357
0
      external_socket = similar_port_mapping->external_socket_;
358
0
    } else {
359
0
      external_socket = create_external_socket(*to);
360
0
      if (!external_socket) {
361
0
        MOZ_ASSERT(false);
362
0
        return R_INTERNAL;
363
0
      }
364
0
    }
365
0
366
0
    port_mapping = create_port_mapping(*to, external_socket);
367
0
    port_mappings_.push_back(port_mapping);
368
0
369
0
    if (poll_flags() & PR_POLL_READ) {
370
0
      // Make sure the new port mapping is ready to receive traffic if the
371
0
      // TestNrSocket is already waiting.
372
0
      port_mapping->async_wait(NR_ASYNC_WAIT_READ,
373
0
                              socket_readable_callback,
374
0
                              this,
375
0
                              (char*)__FUNCTION__,
376
0
                              __LINE__);
377
0
    }
378
0
  }
379
0
380
0
  // We probably don't want to propagate the flags, since this is a simulated
381
0
  // external IP address.
382
0
  return port_mapping->sendto(msg, len, *to);
383
0
}
384
385
int TestNrSocket::recvfrom(void *buf, size_t maxlen,
386
                           size_t *len, int flags,
387
0
                           nr_transport_addr *from) {
388
0
  MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
389
0
390
0
  int r;
391
0
  bool ingress_allowed = false;
392
0
393
0
  if (readable_socket_) {
394
0
    // If any of the external sockets got data, see if it will be passed through
395
0
    r = readable_socket_->recvfrom(buf, maxlen, len, 0, from);
396
0
    readable_socket_ = nullptr;
397
0
    if (!r) {
398
0
      PortMapping *port_mapping_used;
399
0
      ingress_allowed = allow_ingress(*from, &port_mapping_used);
400
0
      if (ingress_allowed) {
401
0
        r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s received from %s via %s",
402
0
              internal_socket_->my_addr().as_string,
403
0
              from->as_string,
404
0
              port_mapping_used->external_socket_->my_addr().as_string);
405
0
        if (nat_->refresh_on_ingress_) {
406
0
          port_mapping_used->last_used_ = PR_IntervalNow();
407
0
        }
408
0
      }
409
0
    }
410
0
  } else {
411
0
    // If no external socket has data, see if there's any data that was sent
412
0
    // directly to the TestNrSocket, and eat it if it isn't supposed to get
413
0
    // through.
414
0
    r = internal_socket_->recvfrom(buf, maxlen, len, flags, from);
415
0
    if (!r) {
416
0
      // We do not use allow_ingress() here because that only handles traffic
417
0
      // landing on an external port.
418
0
      ingress_allowed = (!nat_->enabled_ ||
419
0
                         nat_->is_an_internal_tuple(*from));
420
0
      if (!ingress_allowed) {
421
0
        r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: "
422
0
              "Not behind the same NAT",
423
0
              internal_socket_->my_addr().as_string,
424
0
              from->as_string);
425
0
      } else {
426
0
        r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s received from %s",
427
0
              internal_socket_->my_addr().as_string,
428
0
              from->as_string);
429
0
      }
430
0
    }
431
0
  }
432
0
433
0
  // Kinda lame that we are forced to give the app a readable callback and then
434
0
  // say "Oh, never mind...", but the alternative is to totally decouple the
435
0
  // callbacks from STS and the callbacks the app sets. On the bright side, this
436
0
  // speeds up unit tests where we are verifying that ingress is forbidden,
437
0
  // since they'll get a readable callback and then an error, instead of having
438
0
  // to wait for a timeout.
439
0
  if (!ingress_allowed) {
440
0
    *len = 0;
441
0
    r = R_WOULDBLOCK;
442
0
  }
443
0
444
0
  return r;
445
0
}
446
447
bool TestNrSocket::allow_ingress(const nr_transport_addr &from,
448
0
                                 PortMapping **port_mapping_used) const {
449
0
  // This is only called for traffic arriving at a port mapping
450
0
  MOZ_ASSERT(nat_->enabled_);
451
0
  MOZ_ASSERT(!nat_->is_an_internal_tuple(from));
452
0
453
0
  *port_mapping_used = get_port_mapping(from, nat_->filtering_type_);
454
0
  if (!(*port_mapping_used)) {
455
0
    r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: "
456
0
                                 "Filtered",
457
0
                                 internal_socket_->my_addr().as_string,
458
0
                                 from.as_string);
459
0
    return false;
460
0
  }
461
0
462
0
  if (is_port_mapping_stale(**port_mapping_used)) {
463
0
    r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: "
464
0
                                 "Stale port mapping",
465
0
                                 internal_socket_->my_addr().as_string,
466
0
                                 from.as_string);
467
0
    return false;
468
0
  }
469
0
470
0
  if (!nat_->allow_hairpinning_ && nat_->is_my_external_tuple(from)) {
471
0
    r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: "
472
0
                                 "Hairpinning disallowed",
473
0
                                 internal_socket_->my_addr().as_string,
474
0
                                 from.as_string);
475
0
    return false;
476
0
  }
477
0
478
0
  return true;
479
0
}
480
481
0
int TestNrSocket::connect(nr_transport_addr *addr) {
482
0
483
0
  if (connect_invoked_ || !port_mappings_.empty()) {
484
0
    MOZ_CRASH("TestNrSocket::connect() called more than once!");
485
0
    return R_INTERNAL;
486
0
  }
487
0
488
0
  if (!nat_->enabled_
489
0
      || addr->protocol==IPPROTO_UDP  // Horrible hack to allow default address
490
0
                                      // discovery to work. Only works because
491
0
                                      // we don't normally connect on UDP.
492
0
      || nat_->is_an_internal_tuple(*addr)) {
493
0
    // This will set connect_invoked_
494
0
    return internal_socket_->connect(addr);
495
0
  }
496
0
497
0
  RefPtr<NrSocketBase> external_socket(create_external_socket(*addr));
498
0
  if (!external_socket) {
499
0
    return R_INTERNAL;
500
0
  }
501
0
502
0
  PortMapping *port_mapping = create_port_mapping(*addr, external_socket);
503
0
  port_mappings_.push_back(port_mapping);
504
0
  int r = port_mapping->external_socket_->connect(addr);
505
0
  if (r && r != R_WOULDBLOCK) {
506
0
    return r;
507
0
  }
508
0
509
0
  port_mapping->last_used_ = PR_IntervalNow();
510
0
511
0
  if (poll_flags() & PR_POLL_READ) {
512
0
    port_mapping->async_wait(NR_ASYNC_WAIT_READ,
513
0
                             port_mapping_tcp_passthrough_callback,
514
0
                             this,
515
0
                             (char*)__FUNCTION__,
516
0
                             __LINE__);
517
0
  }
518
0
519
0
  return r;
520
0
}
521
522
0
int TestNrSocket::write(const void *msg, size_t len, size_t *written) {
523
0
  UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg));
524
0
525
0
  if (nat_->nat_delegate_ && nat_->nat_delegate_->on_write(nat_, msg, len, written)) {
526
0
    return R_INTERNAL;
527
0
  }
528
0
529
0
  if (nat_->block_stun_ && nr_is_stun_message(buf, len)) {
530
0
    // Should cause this socket to be abandoned
531
0
    r_log(LOG_GENERIC, LOG_DEBUG,
532
0
          "TestNrSocket %s dropping outgoing TCP "
533
0
          "because it is configured to drop STUN",
534
0
          my_addr().as_string);
535
0
    return R_INTERNAL;
536
0
  }
537
0
538
0
  if (nat_->block_tcp_ && !tls_) {
539
0
    // Should cause this socket to be abandoned
540
0
    r_log(LOG_GENERIC, LOG_DEBUG,
541
0
          "TestNrSocket %s dropping outgoing TCP "
542
0
          "because it is configured to drop TCP",
543
0
          my_addr().as_string);
544
0
    return R_INTERNAL;
545
0
  }
546
0
547
0
  if (port_mappings_.empty()) {
548
0
    // The no-nat case, just pass call through.
549
0
    r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s writing",
550
0
          my_addr().as_string);
551
0
552
0
    return internal_socket_->write(msg, len, written);
553
0
  }
554
0
  destroy_stale_port_mappings();
555
0
  if (port_mappings_.empty()) {
556
0
    r_log(LOG_GENERIC, LOG_DEBUG,
557
0
          "TestNrSocket %s dropping outgoing TCP "
558
0
          "because the port mapping was stale",
559
0
          my_addr().as_string);
560
0
    return R_INTERNAL;
561
0
  }
562
0
  // This is TCP only
563
0
  MOZ_ASSERT(port_mappings_.size() == 1);
564
0
  r_log(LOG_GENERIC, LOG_DEBUG,
565
0
        "PortMapping %s -> %s writing",
566
0
        port_mappings_.front()->external_socket_->my_addr().as_string,
567
0
        port_mappings_.front()->remote_address_.as_string);
568
0
  port_mappings_.front()->last_used_ = PR_IntervalNow();
569
0
  return port_mappings_.front()->external_socket_->write(msg, len, written);
570
0
}
571
572
0
int TestNrSocket::read(void *buf, size_t maxlen, size_t *len) {
573
0
  int r;
574
0
575
0
  if (port_mappings_.empty()) {
576
0
    r = internal_socket_->read(buf, maxlen, len);
577
0
  } else {
578
0
    MOZ_ASSERT(port_mappings_.size() == 1);
579
0
    r = port_mappings_.front()->external_socket_->read(buf, maxlen, len);
580
0
    if (!r && nat_->refresh_on_ingress_) {
581
0
      port_mappings_.front()->last_used_ = PR_IntervalNow();
582
0
    }
583
0
  }
584
0
585
0
  if (r) {
586
0
    return r;
587
0
  }
588
0
589
0
  if (nat_->nat_delegate_ && nat_->nat_delegate_->on_read(nat_, buf, maxlen, len)) {
590
0
    return R_INTERNAL;
591
0
  }
592
0
593
0
  if (nat_->block_tcp_ && !tls_) {
594
0
    // Should cause this socket to be abandoned
595
0
    return R_INTERNAL;
596
0
  }
597
0
598
0
  UCHAR *cbuf = static_cast<UCHAR*>(const_cast<void*>(buf));
599
0
  if (nat_->block_stun_ && nr_is_stun_message(cbuf, *len)) {
600
0
    // Should cause this socket to be abandoned
601
0
    return R_INTERNAL;
602
0
  }
603
0
604
0
  return r;
605
0
}
606
607
int TestNrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg,
608
0
                             char *function, int line) {
609
0
  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s waiting for %s",
610
0
                                internal_socket_->my_addr().as_string,
611
0
                                how == NR_ASYNC_WAIT_READ ? "read" : "write");
612
0
613
0
  int r;
614
0
615
0
  if (how == NR_ASYNC_WAIT_READ) {
616
0
    NrSocketBase::async_wait(how, cb, cb_arg, function, line);
617
0
618
0
    // Make sure we're waiting on the socket for the internal address
619
0
    r = internal_socket_->async_wait(how,
620
0
                                     socket_readable_callback,
621
0
                                     this,
622
0
                                     function,
623
0
                                     line);
624
0
  } else {
625
0
    // For write, just use the readiness of the internal socket, since we queue
626
0
    // everything for the port mappings.
627
0
    r = internal_socket_->async_wait(how,
628
0
                                     cb,
629
0
                                     cb_arg,
630
0
                                     function,
631
0
                                     line);
632
0
  }
633
0
634
0
  if (r) {
635
0
    r_log(LOG_GENERIC, LOG_ERR, "TestNrSocket %s failed to async_wait for "
636
0
                                "internal socket: %d\n",
637
0
                                internal_socket_->my_addr().as_string,
638
0
                                r);
639
0
    return r;
640
0
  }
641
0
642
0
  if (is_tcp_connection_behind_nat()) {
643
0
    // Bypass all port-mapping related logic
644
0
    return 0;
645
0
  }
646
0
647
0
  if (internal_socket_->my_addr().protocol == IPPROTO_TCP) {
648
0
    // For a TCP connection through a simulated NAT, these signals are
649
0
    // just passed through.
650
0
    MOZ_ASSERT(port_mappings_.size() == 1);
651
0
652
0
    return port_mappings_.front()->async_wait(
653
0
        how,
654
0
        port_mapping_tcp_passthrough_callback,
655
0
        this,
656
0
        function,
657
0
        line);
658
0
  }
659
0
  if (how == NR_ASYNC_WAIT_READ) {
660
0
    // For UDP port mappings, we decouple the writeable callbacks
661
0
    for (PortMapping *port_mapping : port_mappings_) {
662
0
      // Be ready to receive traffic on our port mappings
663
0
      r = port_mapping->async_wait(how,
664
0
                                   socket_readable_callback,
665
0
                                   this,
666
0
                                   function,
667
0
                                   line);
668
0
      if (r) {
669
0
        r_log(LOG_GENERIC, LOG_ERR, "TestNrSocket %s failed to async_wait for "
670
0
                                    "port mapping: %d\n",
671
0
                                    internal_socket_->my_addr().as_string,
672
0
                                    r);
673
0
        return r;
674
0
      }
675
0
    }
676
0
  }
677
0
678
0
  return 0;
679
0
}
680
681
0
void TestNrSocket::cancel_port_mapping_async_wait(int how) {
682
0
  for (PortMapping *port_mapping : port_mappings_) {
683
0
    port_mapping->cancel(how);
684
0
  }
685
0
}
686
687
0
int TestNrSocket::cancel(int how) {
688
0
689
0
  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s stop waiting for %s",
690
0
        internal_socket_->my_addr().as_string,
691
0
        how == NR_ASYNC_WAIT_READ ? "read" : "write");
692
0
693
0
  // Writable callbacks are decoupled except for the TCP case
694
0
  if (how == NR_ASYNC_WAIT_READ ||
695
0
      internal_socket_->my_addr().protocol == IPPROTO_TCP) {
696
0
    cancel_port_mapping_async_wait(how);
697
0
  }
698
0
699
0
  return internal_socket_->cancel(how);
700
0
}
701
702
0
bool TestNrSocket::has_port_mappings() const {
703
0
  return !port_mappings_.empty();
704
0
}
705
706
0
bool TestNrSocket::is_my_external_tuple(const nr_transport_addr &addr) const {
707
0
  for (PortMapping *port_mapping : port_mappings_) {
708
0
    nr_transport_addr port_mapping_addr;
709
0
    if (port_mapping->external_socket_->getaddr(&port_mapping_addr)) {
710
0
      MOZ_CRASH("NrSocket::getaddr failed!");
711
0
    }
712
0
713
0
    // TODO(bug 1170299): Remove const_cast when no longer necessary
714
0
    if (!nr_transport_addr_cmp(const_cast<nr_transport_addr*>(&addr),
715
0
                               &port_mapping_addr,
716
0
                               NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
717
0
      return true;
718
0
    }
719
0
  }
720
0
  return false;
721
0
}
722
723
bool TestNrSocket::is_port_mapping_stale(
724
0
    const PortMapping &port_mapping) const {
725
0
  PRIntervalTime now = PR_IntervalNow();
726
0
  PRIntervalTime elapsed_ticks = now - port_mapping.last_used_;
727
0
  uint32_t idle_duration = PR_IntervalToMilliseconds(elapsed_ticks);
728
0
  return idle_duration > nat_->mapping_timeout_;
729
0
}
730
731
0
void TestNrSocket::destroy_stale_port_mappings() {
732
0
  for (auto i = port_mappings_.begin(); i != port_mappings_.end();) {
733
0
    auto temp = i;
734
0
    ++i;
735
0
    if (is_port_mapping_stale(**temp)) {
736
0
      r_log(LOG_GENERIC, LOG_INFO,
737
0
            "TestNrSocket %s destroying port mapping %s -> %s",
738
0
            internal_socket_->my_addr().as_string,
739
0
            (*temp)->external_socket_->my_addr().as_string,
740
0
            (*temp)->remote_address_.as_string);
741
0
742
0
      port_mappings_.erase(temp);
743
0
    }
744
0
  }
745
0
}
746
747
void TestNrSocket::socket_readable_callback(void *real_sock_v,
748
                                             int how,
749
0
                                             void *test_sock_v) {
750
0
  TestNrSocket *test_socket = static_cast<TestNrSocket*>(test_sock_v);
751
0
  NrSocketBase *real_socket = static_cast<NrSocketBase*>(real_sock_v);
752
0
753
0
  test_socket->on_socket_readable(real_socket);
754
0
}
755
756
0
void TestNrSocket::on_socket_readable(NrSocketBase *real_socket) {
757
0
  if (!readable_socket_ && (real_socket != internal_socket_)) {
758
0
    readable_socket_ = real_socket;
759
0
  }
760
0
761
0
  fire_readable_callback();
762
0
}
763
764
0
void TestNrSocket::fire_readable_callback() {
765
0
  MOZ_ASSERT(poll_flags() & PR_POLL_READ);
766
0
  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s ready for read",
767
0
        internal_socket_->my_addr().as_string);
768
0
  fire_callback(NR_ASYNC_WAIT_READ);
769
0
}
770
771
void TestNrSocket::port_mapping_writeable_callback(void *ext_sock_v,
772
                                                   int how,
773
0
                                                   void *test_sock_v) {
774
0
  TestNrSocket *test_socket = static_cast<TestNrSocket*>(test_sock_v);
775
0
  NrSocketBase *external_socket = static_cast<NrSocketBase*>(ext_sock_v);
776
0
777
0
  test_socket->write_to_port_mapping(external_socket);
778
0
}
779
780
0
void TestNrSocket::write_to_port_mapping(NrSocketBase *external_socket) {
781
0
  MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
782
0
783
0
  int r = 0;
784
0
  for (PortMapping *port_mapping : port_mappings_) {
785
0
    if (port_mapping->external_socket_ == external_socket) {
786
0
      // If the send succeeds, or if there was nothing to send, we keep going
787
0
      r = port_mapping->send_from_queue();
788
0
      if (r) {
789
0
        break;
790
0
      }
791
0
    }
792
0
  }
793
0
794
0
  if (r == R_WOULDBLOCK) {
795
0
    // Re-register for writeable callbacks, since we still have stuff to send
796
0
    NR_ASYNC_WAIT(external_socket,
797
0
                  NR_ASYNC_WAIT_WRITE,
798
0
                  &TestNrSocket::port_mapping_writeable_callback,
799
0
                  this);
800
0
  }
801
0
}
802
803
void TestNrSocket::port_mapping_tcp_passthrough_callback(void *ext_sock_v,
804
                                                         int how,
805
0
                                                         void *test_sock_v) {
806
0
  TestNrSocket *test_socket = static_cast<TestNrSocket*>(test_sock_v);
807
0
  r_log(LOG_GENERIC, LOG_DEBUG,
808
0
        "TestNrSocket %s firing %s callback",
809
0
        test_socket->internal_socket_->my_addr().as_string,
810
0
        how == NR_ASYNC_WAIT_READ ? "readable" : "writeable");
811
0
812
0
813
0
  test_socket->internal_socket_->fire_callback(how);
814
0
}
815
816
0
bool TestNrSocket::is_tcp_connection_behind_nat() const {
817
0
  return internal_socket_->my_addr().protocol == IPPROTO_TCP &&
818
0
         port_mappings_.empty();
819
0
}
820
821
TestNrSocket::PortMapping* TestNrSocket::get_port_mapping(
822
    const nr_transport_addr &remote_address,
823
0
    TestNat::NatBehavior filter) const {
824
0
  int compare_flags;
825
0
  switch (filter) {
826
0
    case TestNat::ENDPOINT_INDEPENDENT:
827
0
      compare_flags = NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL;
828
0
      break;
829
0
    case TestNat::ADDRESS_DEPENDENT:
830
0
      compare_flags = NR_TRANSPORT_ADDR_CMP_MODE_ADDR;
831
0
      break;
832
0
    case TestNat::PORT_DEPENDENT:
833
0
      compare_flags = NR_TRANSPORT_ADDR_CMP_MODE_ALL;
834
0
      break;
835
0
  }
836
0
837
0
  for (PortMapping *port_mapping : port_mappings_) {
838
0
    // TODO(bug 1170299): Remove const_cast when no longer necessary
839
0
    if (!nr_transport_addr_cmp(const_cast<nr_transport_addr*>(&remote_address),
840
0
                               &port_mapping->remote_address_,
841
0
                               compare_flags))
842
0
      return port_mapping;
843
0
  }
844
0
  return nullptr;
845
0
}
846
847
TestNrSocket::PortMapping* TestNrSocket::create_port_mapping(
848
    const nr_transport_addr &remote_address,
849
0
    const RefPtr<NrSocketBase> &external_socket) const {
850
0
  r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s creating port mapping %s -> %s",
851
0
        internal_socket_->my_addr().as_string,
852
0
        external_socket->my_addr().as_string,
853
0
        remote_address.as_string);
854
0
855
0
  return new PortMapping(remote_address, external_socket);
856
0
}
857
858
TestNrSocket::PortMapping::PortMapping(
859
    const nr_transport_addr &remote_address,
860
    const RefPtr<NrSocketBase> &external_socket) :
861
0
  external_socket_(external_socket) {
862
0
  // TODO(bug 1170299): Remove const_cast when no longer necessary
863
0
  nr_transport_addr_copy(&remote_address_,
864
0
                         const_cast<nr_transport_addr*>(&remote_address));
865
0
}
866
867
0
int TestNrSocket::PortMapping::send_from_queue() {
868
0
  MOZ_ASSERT(remote_address_.protocol != IPPROTO_TCP);
869
0
  int r = 0;
870
0
871
0
  while (!send_queue_.empty()) {
872
0
    UdpPacket &packet = *send_queue_.front();
873
0
    r_log(LOG_GENERIC, LOG_DEBUG,
874
0
          "PortMapping %s -> %s sending from queue to %s",
875
0
          external_socket_->my_addr().as_string,
876
0
          remote_address_.as_string,
877
0
          packet.remote_address_.as_string);
878
0
879
0
    r = external_socket_->sendto(packet.buffer_->data(),
880
0
                                 packet.buffer_->len(),
881
0
                                 0,
882
0
                                 &packet.remote_address_);
883
0
884
0
    if (r) {
885
0
      if (r != R_WOULDBLOCK) {
886
0
        r_log(LOG_GENERIC, LOG_ERR, "%s: Fatal error %d, stop trying",
887
0
              __FUNCTION__, r);
888
0
        send_queue_.clear();
889
0
      } else {
890
0
        r_log(LOG_GENERIC, LOG_DEBUG, "Would block, will retry later");
891
0
      }
892
0
      break;
893
0
    }
894
0
895
0
    send_queue_.pop_front();
896
0
  }
897
0
898
0
  return r;
899
0
}
900
901
int TestNrSocket::PortMapping::sendto(const void *msg,
902
                                      size_t len,
903
0
                                      const nr_transport_addr &to) {
904
0
  MOZ_ASSERT(remote_address_.protocol != IPPROTO_TCP);
905
0
  r_log(LOG_GENERIC, LOG_DEBUG,
906
0
        "PortMapping %s -> %s sending to %s",
907
0
        external_socket_->my_addr().as_string,
908
0
        remote_address_.as_string,
909
0
        to.as_string);
910
0
911
0
  last_used_ = PR_IntervalNow();
912
0
  int r = external_socket_->sendto(msg, len, 0,
913
0
      // TODO(bug 1170299): Remove const_cast when no longer necessary
914
0
      const_cast<nr_transport_addr*>(&to));
915
0
916
0
  if (r == R_WOULDBLOCK) {
917
0
    r_log(LOG_GENERIC, LOG_DEBUG, "Enqueueing UDP packet to %s", to.as_string);
918
0
    send_queue_.push_back(RefPtr<UdpPacket>(new UdpPacket(msg, len, to)));
919
0
    return 0;
920
0
  }
921
0
  if (r) {
922
0
    r_log(LOG_GENERIC,LOG_ERR, "Error: %d", r);
923
0
  }
924
0
925
0
  return r;
926
0
}
927
928
int TestNrSocket::PortMapping::async_wait(int how, NR_async_cb cb, void *cb_arg,
929
0
                                          char *function, int line) {
930
0
  r_log(LOG_GENERIC, LOG_DEBUG,
931
0
        "PortMapping %s -> %s waiting for %s",
932
0
        external_socket_->my_addr().as_string,
933
0
        remote_address_.as_string,
934
0
        how == NR_ASYNC_WAIT_READ ? "read" : "write");
935
0
936
0
  return external_socket_->async_wait(how, cb, cb_arg, function, line);
937
0
}
938
939
0
int TestNrSocket::PortMapping::cancel(int how) {
940
0
  r_log(LOG_GENERIC, LOG_DEBUG,
941
0
        "PortMapping %s -> %s stop waiting for %s",
942
0
        external_socket_->my_addr().as_string,
943
0
        remote_address_.as_string,
944
0
        how == NR_ASYNC_WAIT_READ ? "read" : "write");
945
0
946
0
  return external_socket_->cancel(how);
947
0
}
948
949
} // namespace mozilla
950