Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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/. */
7 // Original author: ekr@rtfm.com
9 #include <algorithm>
10 #include <deque>
11 #include <iostream>
12 #include <limits>
13 #include <map>
14 #include <string>
15 #include <vector>
17 #include "sigslot.h"
19 #include "logging.h"
20 #include "nspr.h"
21 #include "nss.h"
22 #include "ssl.h"
24 #include "mozilla/Scoped.h"
25 #include "nsThreadUtils.h"
26 #include "nsXPCOM.h"
28 #include "nricectx.h"
29 #include "nricemediastream.h"
30 #include "nriceresolverfake.h"
31 #include "nriceresolver.h"
32 #include "nrinterfaceprioritizer.h"
33 #include "mtransport_test_utils.h"
34 #include "gtest_ringbuffer_dumper.h"
35 #include "rlogringbuffer.h"
36 #include "runnable_utils.h"
37 #include "stunserver.h"
38 // TODO(bcampen@mozilla.com): Big fat hack since the build system doesn't give
39 // us a clean way to add object files to a single executable.
40 #include "stunserver.cpp"
41 #include "stun_udp_socket_filter.h"
42 #include "mozilla/net/DNS.h"
44 #define GTEST_HAS_RTTI 0
45 #include "gtest/gtest.h"
46 #include "gtest_utils.h"
48 using namespace mozilla;
49 MtransportTestUtils *test_utils;
51 bool stream_added = false;
53 static int kDefaultTimeout = 7000;
55 const std::string kDefaultStunServerAddress((char *)"23.21.150.121");
56 const std::string kDefaultStunServerHostname(
57 (char *)"ec2-23-21-150-121.compute-1.amazonaws.com");
58 const std::string kBogusStunServerHostname(
59 (char *)"stun-server-nonexistent.invalid");
60 const uint16_t kDefaultStunServerPort=3478;
61 const std::string kBogusIceCandidate(
62 (char *)"candidate:0 2 UDP 2113601790 192.168.178.20 50769 typ");
64 std::string g_stun_server_address(kDefaultStunServerAddress);
65 std::string g_stun_server_hostname(kDefaultStunServerHostname);
66 std::string g_turn_server;
67 std::string g_turn_user;
68 std::string g_turn_password;
70 namespace {
72 enum TrickleMode { TRICKLE_NONE, TRICKLE_SIMULATE, TRICKLE_REAL };
74 typedef bool (*CandidateFilter)(const std::string& candidate);
76 static bool IsRelayCandidate(const std::string& candidate) {
77 return candidate.find("typ relay") != std::string::npos;
78 }
80 bool ContainsSucceededPair(const std::vector<NrIceCandidatePair>& pairs) {
81 for (size_t i = 0; i < pairs.size(); ++i) {
82 if (pairs[i].state == NrIceCandidatePair::STATE_SUCCEEDED) {
83 return true;
84 }
85 }
86 return false;
87 }
89 // Note: Does not correspond to any notion of prioritization; this is just
90 // so we can use stl containers/algorithms that need a comparator
91 bool operator<(const NrIceCandidate& lhs,
92 const NrIceCandidate& rhs) {
93 if (lhs.cand_addr.host == rhs.cand_addr.host) {
94 if (lhs.cand_addr.port == rhs.cand_addr.port) {
95 if (lhs.cand_addr.transport == rhs.cand_addr.transport) {
96 return lhs.type < rhs.type;
97 }
98 return lhs.cand_addr.transport < rhs.cand_addr.transport;
99 }
100 return lhs.cand_addr.port < rhs.cand_addr.port;
101 }
102 return lhs.cand_addr.host < rhs.cand_addr.host;
103 }
105 bool operator==(const NrIceCandidate& lhs,
106 const NrIceCandidate& rhs) {
107 return !((lhs < rhs) || (rhs < lhs));
108 }
110 class IceCandidatePairCompare {
111 public:
112 bool operator()(const NrIceCandidatePair& lhs,
113 const NrIceCandidatePair& rhs) const {
114 if (lhs.priority == rhs.priority) {
115 if (lhs.local == rhs.local) {
116 if (lhs.remote == rhs.remote) {
117 return lhs.codeword < rhs.codeword;
118 }
119 return lhs.remote < rhs.remote;
120 }
121 return lhs.local < rhs.local;
122 }
123 return lhs.priority < rhs.priority;
124 }
125 };
127 class IceTestPeer : public sigslot::has_slots<> {
128 public:
130 IceTestPeer(const std::string& name, bool offerer, bool set_priorities) :
131 name_(name),
132 ice_ctx_(NrIceCtx::Create(name, offerer, set_priorities)),
133 streams_(),
134 candidates_(),
135 gathering_complete_(false),
136 ready_ct_(0),
137 ice_complete_(false),
138 received_(0),
139 sent_(0),
140 fake_resolver_(),
141 dns_resolver_(new NrIceResolver()),
142 remote_(nullptr),
143 candidate_filter_(nullptr),
144 expected_local_type_(NrIceCandidate::ICE_HOST),
145 expected_local_transport_(kNrIceTransportUdp),
146 expected_remote_type_(NrIceCandidate::ICE_HOST),
147 trickle_mode_(TRICKLE_NONE),
148 trickled_(0) {
149 ice_ctx_->SignalGatheringStateChange.connect(
150 this,
151 &IceTestPeer::GatheringStateChange);
152 ice_ctx_->SignalConnectionStateChange.connect(
153 this,
154 &IceTestPeer::ConnectionStateChange);
155 }
157 ~IceTestPeer() {
158 test_utils->sts_target()->Dispatch(WrapRunnable(this,
159 &IceTestPeer::Shutdown),
160 NS_DISPATCH_SYNC);
162 // Give the ICE destruction callback time to fire before
163 // we destroy the resolver.
164 PR_Sleep(1000);
165 }
167 void AddStream(int components) {
168 char name[100];
169 snprintf(name, sizeof(name), "%s:stream%d", name_.c_str(),
170 (int)streams_.size());
172 mozilla::RefPtr<NrIceMediaStream> stream =
173 ice_ctx_->CreateStream(static_cast<char *>(name), components);
175 ASSERT_TRUE(stream);
176 streams_.push_back(stream);
177 stream->SignalCandidate.connect(this, &IceTestPeer::CandidateInitialized);
178 stream->SignalReady.connect(this, &IceTestPeer::StreamReady);
179 stream->SignalFailed.connect(this, &IceTestPeer::StreamFailed);
180 stream->SignalPacketReceived.connect(this, &IceTestPeer::PacketReceived);
181 }
183 void SetStunServer(const std::string addr, uint16_t port) {
184 std::vector<NrIceStunServer> stun_servers;
185 ScopedDeletePtr<NrIceStunServer> server(NrIceStunServer::Create(addr,
186 port));
187 stun_servers.push_back(*server);
188 ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
189 }
191 void SetTurnServer(const std::string addr, uint16_t port,
192 const std::string username,
193 const std::string password,
194 const char* transport) {
195 std::vector<unsigned char> password_vec(password.begin(), password.end());
196 SetTurnServer(addr, port, username, password_vec, transport);
197 }
200 void SetTurnServer(const std::string addr, uint16_t port,
201 const std::string username,
202 const std::vector<unsigned char> password,
203 const char* transport) {
204 std::vector<NrIceTurnServer> turn_servers;
205 ScopedDeletePtr<NrIceTurnServer> server(NrIceTurnServer::Create(
206 addr, port, username, password, transport));
207 turn_servers.push_back(*server);
208 ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(turn_servers)));
209 }
211 void SetTurnServers(const std::vector<NrIceTurnServer> servers) {
212 ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(servers)));
213 }
215 void SetFakeResolver() {
216 ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
217 PRNetAddr addr;
218 PRStatus status = PR_StringToNetAddr(g_stun_server_address.c_str(),
219 &addr);
220 addr.inet.port = kDefaultStunServerPort;
221 ASSERT_EQ(PR_SUCCESS, status);
222 fake_resolver_.SetAddr(g_stun_server_hostname, addr);
223 ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
224 fake_resolver_.AllocateResolver())));
225 }
227 void SetDNSResolver() {
228 ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
229 ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
230 dns_resolver_->AllocateResolver())));
231 }
233 void Gather() {
234 nsresult res;
236 test_utils->sts_target()->Dispatch(
237 WrapRunnableRet(ice_ctx_, &NrIceCtx::StartGathering, &res),
238 NS_DISPATCH_SYNC);
240 ASSERT_TRUE(NS_SUCCEEDED(res));
241 }
243 // Get various pieces of state
244 std::vector<std::string> GetGlobalAttributes() {
245 return ice_ctx_->GetGlobalAttributes();
246 }
248 std::vector<std::string> GetCandidates(size_t stream) {
249 std::vector<std::string> v;
251 RUN_ON_THREAD(
252 test_utils->sts_target(),
253 WrapRunnableRet(this, &IceTestPeer::GetCandidates_s, stream, &v),
254 NS_DISPATCH_SYNC);
256 return v;
257 }
259 std::vector<std::string> GetCandidates_s(size_t stream) {
260 std::vector<std::string> candidates;
262 if (stream >= streams_.size())
263 return candidates;
265 std::vector<std::string> candidates_in =
266 streams_[stream]->GetCandidates();
269 for (size_t i=0; i < candidates_in.size(); i++) {
270 if ((!candidate_filter_) || candidate_filter_(candidates_in[i])) {
271 std::cerr << "Returning candidate: " << candidates_in[i] << std::endl;
272 candidates.push_back(candidates_in[i]);
273 }
274 }
276 return candidates;
277 }
279 void SetExpectedTypes(NrIceCandidate::Type local,
280 NrIceCandidate::Type remote,
281 std::string local_transport = kNrIceTransportUdp) {
282 expected_local_type_ = local;
283 expected_local_transport_ = local_transport;
284 expected_remote_type_ = remote;
285 }
287 bool gathering_complete() { return gathering_complete_; }
288 int ready_ct() { return ready_ct_; }
289 bool is_ready(size_t stream) {
290 return streams_[stream]->state() == NrIceMediaStream::ICE_OPEN;
291 }
292 bool ice_complete() { return ice_complete_; }
293 size_t received() { return received_; }
294 size_t sent() { return sent_; }
296 // Start connecting to another peer
297 void Connect_s(IceTestPeer *remote, TrickleMode trickle_mode,
298 bool start = true) {
299 nsresult res;
301 remote_ = remote;
303 trickle_mode_ = trickle_mode;
304 res = ice_ctx_->ParseGlobalAttributes(remote->GetGlobalAttributes());
305 ASSERT_TRUE(NS_SUCCEEDED(res));
307 if (trickle_mode == TRICKLE_NONE ||
308 trickle_mode == TRICKLE_REAL) {
309 for (size_t i=0; i<streams_.size(); ++i) {
310 std::vector<std::string> candidates =
311 remote->GetCandidates(i);
313 for (size_t j=0; j<candidates.size(); ++j) {
314 std::cerr << "Candidate: " + candidates[j] << std::endl;
315 }
316 res = streams_[i]->ParseAttributes(candidates);
317 ASSERT_TRUE(NS_SUCCEEDED(res));
318 }
319 } else {
320 // Parse empty attributes and then trickle them out later
321 for (size_t i=0; i<streams_.size(); ++i) {
322 std::vector<std::string> empty_attrs;
323 res = streams_[i]->ParseAttributes(empty_attrs);
324 ASSERT_TRUE(NS_SUCCEEDED(res));
325 }
326 }
328 if (start) {
329 // Now start checks
330 res = ice_ctx_->StartChecks();
331 ASSERT_TRUE(NS_SUCCEEDED(res));
332 }
333 }
335 void Connect(IceTestPeer *remote, TrickleMode trickle_mode,
336 bool start = true) {
337 test_utils->sts_target()->Dispatch(
338 WrapRunnable(
339 this, &IceTestPeer::Connect_s, remote, trickle_mode, start),
340 NS_DISPATCH_SYNC);
341 }
343 void SimulateTrickle(size_t stream) {
344 std::cerr << "Doing trickle for stream " << stream << std::endl;
345 // If we are in trickle deferred mode, now trickle in the candidates
346 // for |stream}
347 nsresult res;
349 ASSERT_GT(remote_->streams_.size(), stream);
351 std::vector<std::string> candidates =
352 remote_->GetCandidates(stream);
354 for (size_t j=0; j<candidates.size(); j++) {
355 test_utils->sts_target()->Dispatch(
356 WrapRunnableRet(streams_[stream],
357 &NrIceMediaStream::ParseTrickleCandidate,
358 candidates[j],
359 &res), NS_DISPATCH_SYNC);
361 ASSERT_TRUE(NS_SUCCEEDED(res));
362 }
363 }
365 void DumpCandidate(std::string which, const NrIceCandidate& cand) {
366 std::string type;
368 switch(cand.type) {
369 case NrIceCandidate::ICE_HOST:
370 type = "host";
371 break;
372 case NrIceCandidate::ICE_SERVER_REFLEXIVE:
373 type = "srflx";
374 break;
375 case NrIceCandidate::ICE_PEER_REFLEXIVE:
376 type = "prflx";
377 break;
378 case NrIceCandidate::ICE_RELAYED:
379 type = "relay";
380 if (which.find("Local") != std::string::npos) {
381 type += "(" + cand.local_addr.transport + ")";
382 }
383 break;
384 default:
385 FAIL();
386 };
388 std::cerr << which
389 << " --> "
390 << type
391 << " "
392 << cand.local_addr.host
393 << ":"
394 << cand.local_addr.port
395 << " codeword="
396 << cand.codeword
397 << std::endl;
398 }
400 void DumpAndCheckActiveCandidates_s() {
401 std::cerr << "Active candidates:" << std::endl;
402 for (size_t i=0; i < streams_.size(); ++i) {
403 for (int j=0; j < streams_[i]->components(); ++j) {
404 std::cerr << "Stream " << i << " component " << j+1 << std::endl;
406 NrIceCandidate *local;
407 NrIceCandidate *remote;
409 nsresult res = streams_[i]->GetActivePair(j+1, &local, &remote);
410 if (res == NS_ERROR_NOT_AVAILABLE) {
411 std::cerr << "Component unpaired or disabled." << std::endl;
412 } else {
413 ASSERT_TRUE(NS_SUCCEEDED(res));
414 DumpCandidate("Local ", *local);
415 ASSERT_EQ(expected_local_type_, local->type);
416 ASSERT_EQ(expected_local_transport_, local->local_addr.transport);
417 DumpCandidate("Remote ", *remote);
418 ASSERT_EQ(expected_remote_type_, remote->type);
419 delete local;
420 delete remote;
421 }
422 }
423 }
424 }
426 void DumpAndCheckActiveCandidates() {
427 test_utils->sts_target()->Dispatch(
428 WrapRunnable(this, &IceTestPeer::DumpAndCheckActiveCandidates_s),
429 NS_DISPATCH_SYNC);
430 }
432 void Close() {
433 test_utils->sts_target()->Dispatch(
434 WrapRunnable(ice_ctx_, &NrIceCtx::destroy_peer_ctx),
435 NS_DISPATCH_SYNC);
436 }
438 void Shutdown() {
439 ice_ctx_ = nullptr;
440 }
442 void StartChecks() {
443 nsresult res;
445 // Now start checks
446 test_utils->sts_target()->Dispatch(
447 WrapRunnableRet(ice_ctx_, &NrIceCtx::StartChecks, &res),
448 NS_DISPATCH_SYNC);
449 ASSERT_TRUE(NS_SUCCEEDED(res));
450 }
452 // Handle events
453 void GatheringStateChange(NrIceCtx* ctx,
454 NrIceCtx::GatheringState state) {
455 (void)ctx;
456 if (state != NrIceCtx::ICE_CTX_GATHER_COMPLETE) {
457 return;
458 }
460 std::cerr << "Gathering complete for " << name_ << std::endl;
461 gathering_complete_ = true;
463 std::cerr << "CANDIDATES:" << std::endl;
464 for (size_t i=0; i<streams_.size(); ++i) {
465 std::cerr << "Stream " << name_ << std::endl;
466 std::vector<std::string> candidates =
467 streams_[i]->GetCandidates();
469 for(size_t j=0; j<candidates.size(); ++j) {
470 std::cerr << candidates[j] << std::endl;
471 }
472 }
473 std::cerr << std::endl;
475 }
477 void CandidateInitialized(NrIceMediaStream *stream, const std::string &candidate) {
478 std::cerr << "Candidate initialized: " << candidate << std::endl;
479 candidates_[stream->name()].push_back(candidate);
481 // If we are connected, then try to trickle to the
482 // other side.
483 if (remote_ && remote_->remote_) {
484 std::vector<mozilla::RefPtr<NrIceMediaStream> >::iterator it =
485 std::find(streams_.begin(), streams_.end(), stream);
486 ASSERT_NE(streams_.end(), it);
487 size_t index = it - streams_.begin();
489 ASSERT_GT(remote_->streams_.size(), index);
490 nsresult res = remote_->streams_[index]->ParseTrickleCandidate(
491 candidate);
492 ASSERT_TRUE(NS_SUCCEEDED(res));
493 ++trickled_;
494 }
495 }
497 nsresult GetCandidatePairs(size_t stream_index,
498 std::vector<NrIceCandidatePair>* pairs) {
499 MOZ_ASSERT(pairs);
500 if (stream_index >= streams_.size()) {
501 // Is there a better error for "no such index"?
502 ADD_FAILURE() << "No such media stream index: " << stream_index;
503 return NS_ERROR_INVALID_ARG;
504 }
506 nsresult res;
507 test_utils->sts_target()->Dispatch(
508 WrapRunnableRet(streams_[stream_index],
509 &NrIceMediaStream::GetCandidatePairs,
510 pairs,
511 &res),
512 NS_DISPATCH_SYNC);
513 return res;
514 }
516 void DumpCandidatePair(const NrIceCandidatePair& pair) {
517 std::cerr << std::endl;
518 DumpCandidate("Local", pair.local);
519 DumpCandidate("Remote", pair.remote);
520 std::cerr << "state = " << pair.state
521 << " priority = " << pair.priority
522 << " nominated = " << pair.nominated
523 << " selected = " << pair.selected
524 << " codeword = " << pair.codeword << std::endl;
525 }
527 void DumpCandidatePairs(NrIceMediaStream *stream) {
528 std::vector<NrIceCandidatePair> pairs;
529 nsresult res = stream->GetCandidatePairs(&pairs);
530 ASSERT_TRUE(NS_SUCCEEDED(res));
532 std::cerr << "Begin list of candidate pairs [" << std::endl;
534 for (std::vector<NrIceCandidatePair>::iterator p = pairs.begin();
535 p != pairs.end(); ++p) {
536 DumpCandidatePair(*p);
537 }
538 std::cerr << "]" << std::endl;
539 }
541 void DumpCandidatePairs() {
542 std::cerr << "Dumping candidate pairs for all streams [" << std::endl;
543 for (size_t s = 0; s < streams_.size(); ++s) {
544 DumpCandidatePairs(streams_[s]);
545 }
546 std::cerr << "]" << std::endl;
547 }
549 bool CandidatePairsPriorityDescending(const std::vector<NrIceCandidatePair>&
550 pairs) {
551 // Verify that priority is descending
552 uint64_t priority = std::numeric_limits<uint64_t>::max();
554 for (size_t p = 0; p < pairs.size(); ++p) {
555 if (priority < pairs[p].priority) {
556 std::cerr << "Priority increased in subsequent pairs:" << std::endl;
557 DumpCandidatePair(pairs[p-1]);
558 DumpCandidatePair(pairs[p]);
559 return false;
560 } else if (priority == pairs[p].priority) {
561 std::cerr << "Duplicate priority in subseqent pairs:" << std::endl;
562 DumpCandidatePair(pairs[p-1]);
563 DumpCandidatePair(pairs[p]);
564 return false;
565 }
566 priority = pairs[p].priority;
567 }
568 return true;
569 }
571 void UpdateAndValidateCandidatePairs(size_t stream_index,
572 std::vector<NrIceCandidatePair>*
573 new_pairs) {
574 std::vector<NrIceCandidatePair> old_pairs = *new_pairs;
575 GetCandidatePairs(stream_index, new_pairs);
576 ASSERT_TRUE(CandidatePairsPriorityDescending(*new_pairs)) << "New list of "
577 "candidate pairs is either not sorted in priority order, or has "
578 "duplicate priorities.";
579 ASSERT_TRUE(CandidatePairsPriorityDescending(old_pairs)) << "Old list of "
580 "candidate pairs is either not sorted in priority order, or has "
581 "duplicate priorities. This indicates some bug in the test case.";
582 std::vector<NrIceCandidatePair> added_pairs;
583 std::vector<NrIceCandidatePair> removed_pairs;
585 // set_difference computes the set of elements that are present in the
586 // first set, but not the second
587 // NrIceCandidatePair::operator< compares based on the priority, local
588 // candidate, and remote candidate in that order. This means this will
589 // catch cases where the priority has remained the same, but one of the
590 // candidates has changed.
591 std::set_difference((*new_pairs).begin(),
592 (*new_pairs).end(),
593 old_pairs.begin(),
594 old_pairs.end(),
595 std::inserter(added_pairs, added_pairs.begin()),
596 IceCandidatePairCompare());
598 std::set_difference(old_pairs.begin(),
599 old_pairs.end(),
600 (*new_pairs).begin(),
601 (*new_pairs).end(),
602 std::inserter(removed_pairs, removed_pairs.begin()),
603 IceCandidatePairCompare());
605 for (std::vector<NrIceCandidatePair>::iterator a = added_pairs.begin();
606 a != added_pairs.end(); ++a) {
607 std::cerr << "Found new candidate pair." << std::endl;
608 DumpCandidatePair(*a);
609 }
611 for (std::vector<NrIceCandidatePair>::iterator r = removed_pairs.begin();
612 r != removed_pairs.end(); ++r) {
613 std::cerr << "Pre-existing candidate pair is now missing:" << std::endl;
614 DumpCandidatePair(*r);
615 }
617 ASSERT_TRUE(removed_pairs.empty()) << "At least one candidate pair has "
618 "gone missing.";
619 }
621 void StreamReady(NrIceMediaStream *stream) {
622 ++ready_ct_;
623 std::cerr << "Stream ready " << stream->name() << " ct=" << ready_ct_ << std::endl;
624 DumpCandidatePairs(stream);
625 }
626 void StreamFailed(NrIceMediaStream *stream) {
627 std::cerr << "Stream failed " << stream->name() << " ct=" << ready_ct_ << std::endl;
628 DumpCandidatePairs(stream);
629 }
631 void ConnectionStateChange(NrIceCtx* ctx,
632 NrIceCtx::ConnectionState state) {
633 (void)ctx;
634 if (state != NrIceCtx::ICE_CTX_OPEN) {
635 return;
636 }
637 std::cerr << "ICE completed " << name_ << std::endl;
638 ice_complete_ = true;
639 }
641 void PacketReceived(NrIceMediaStream *stream, int component, const unsigned char *data,
642 int len) {
643 std::cerr << "Received " << len << " bytes" << std::endl;
644 ++received_;
645 }
647 void SendPacket(int stream, int component, const unsigned char *data,
648 int len) {
649 ASSERT_TRUE(NS_SUCCEEDED(streams_[stream]->SendPacket(component, data, len)));
651 ++sent_;
652 std::cerr << "Sent " << len << " bytes" << std::endl;
653 }
655 void SetCandidateFilter(CandidateFilter filter) {
656 candidate_filter_ = filter;
657 }
659 // Allow us to parse candidates directly on the current thread.
660 void ParseCandidate(size_t i, const std::string& candidate) {
661 std::vector<std::string> attributes;
663 attributes.push_back(candidate);
664 streams_[i]->ParseAttributes(attributes);
665 }
667 void DisableComponent(size_t stream, int component_id) {
668 ASSERT_LT(stream, streams_.size());
669 nsresult res = streams_[stream]->DisableComponent(component_id);
670 ASSERT_TRUE(NS_SUCCEEDED(res));
671 }
673 int trickled() { return trickled_; }
675 private:
676 std::string name_;
677 nsRefPtr<NrIceCtx> ice_ctx_;
678 std::vector<mozilla::RefPtr<NrIceMediaStream> > streams_;
679 std::map<std::string, std::vector<std::string> > candidates_;
680 bool gathering_complete_;
681 int ready_ct_;
682 bool ice_complete_;
683 size_t received_;
684 size_t sent_;
685 NrIceResolverFake fake_resolver_;
686 nsRefPtr<NrIceResolver> dns_resolver_;
687 IceTestPeer *remote_;
688 CandidateFilter candidate_filter_;
689 NrIceCandidate::Type expected_local_type_;
690 std::string expected_local_transport_;
691 NrIceCandidate::Type expected_remote_type_;
692 TrickleMode trickle_mode_;
693 int trickled_;
694 };
696 class IceGatherTest : public ::testing::Test {
697 public:
698 void SetUp() {
699 test_utils->sts_target()->Dispatch(WrapRunnable(TestStunServer::GetInstance(),
700 &TestStunServer::Reset),
701 NS_DISPATCH_SYNC);
702 peer_ = new IceTestPeer("P1", true, false);
703 peer_->AddStream(1);
704 }
706 void Gather(bool wait = true) {
707 peer_->Gather();
709 if (wait) {
710 WaitForGather();
711 }
712 }
714 void WaitForGather() {
715 ASSERT_TRUE_WAIT(peer_->gathering_complete(), kDefaultTimeout);
716 }
718 void UseFakeStunServerWithResponse(const std::string& fake_addr,
719 uint16_t fake_port) {
720 TestStunServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
721 // Sets an additional stun server
722 peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
723 TestStunServer::GetInstance()->port());
724 }
726 // NB: Only does substring matching, watch out for stuff like "1.2.3.4"
727 // matching "21.2.3.47". " 1.2.3.4 " should not have false positives.
728 bool StreamHasMatchingCandidate(unsigned int stream,
729 const std::string& match) {
730 std::vector<std::string> candidates = peer_->GetCandidates(stream);
731 for (size_t c = 0; c < candidates.size(); ++c) {
732 if (std::string::npos != candidates[c].find(match)) {
733 return true;
734 }
735 }
736 return false;
737 }
739 protected:
740 mozilla::ScopedDeletePtr<IceTestPeer> peer_;
741 };
743 class IceConnectTest : public ::testing::Test {
744 public:
745 IceConnectTest() : initted_(false) {}
747 void SetUp() {
748 nsresult rv;
749 target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
750 ASSERT_TRUE(NS_SUCCEEDED(rv));
751 }
753 void AddStream(const std::string& name, int components) {
754 Init(false);
755 p1_->AddStream(components);
756 p2_->AddStream(components);
757 }
759 void Init(bool set_priorities) {
760 if (!initted_) {
761 p1_ = new IceTestPeer("P1", true, set_priorities);
762 p2_ = new IceTestPeer("P2", false, set_priorities);
763 }
764 initted_ = true;
765 }
767 bool Gather(bool wait) {
768 Init(false);
769 p1_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
770 p2_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
771 p1_->Gather();
772 p2_->Gather();
774 if (wait) {
775 EXPECT_TRUE_WAIT(p1_->gathering_complete(), kDefaultTimeout);
776 if (!p1_->gathering_complete())
777 return false;
778 EXPECT_TRUE_WAIT(p2_->gathering_complete(), kDefaultTimeout);
779 if (!p2_->gathering_complete())
780 return false;
781 }
782 return true;
783 }
785 void SetTurnServer(const std::string addr, uint16_t port,
786 const std::string username,
787 const std::string password,
788 const char* transport = kNrIceTransportUdp) {
789 p1_->SetTurnServer(addr, port, username, password, transport);
790 p2_->SetTurnServer(addr, port, username, password, transport);
791 }
793 void SetTurnServers(const std::vector<NrIceTurnServer>& servers) {
794 p1_->SetTurnServers(servers);
795 p2_->SetTurnServers(servers);
796 }
798 void SetCandidateFilter(CandidateFilter filter, bool both=true) {
799 p1_->SetCandidateFilter(filter);
800 if (both) {
801 p2_->SetCandidateFilter(filter);
802 }
803 }
805 void Connect() {
806 p1_->Connect(p2_, TRICKLE_NONE);
807 p2_->Connect(p1_, TRICKLE_NONE);
809 ASSERT_TRUE_WAIT(p1_->ready_ct() == 1 && p2_->ready_ct() == 1,
810 kDefaultTimeout);
811 ASSERT_TRUE_WAIT(p1_->ice_complete() && p2_->ice_complete(),
812 kDefaultTimeout);
814 p1_->DumpAndCheckActiveCandidates();
815 p2_->DumpAndCheckActiveCandidates();
816 }
818 void SetExpectedTypes(NrIceCandidate::Type local, NrIceCandidate::Type remote,
819 std::string transport = kNrIceTransportUdp) {
820 p1_->SetExpectedTypes(local, remote, transport);
821 p2_->SetExpectedTypes(local, remote, transport);
822 }
824 void SetExpectedTypes(NrIceCandidate::Type local1, NrIceCandidate::Type remote1,
825 NrIceCandidate::Type local2, NrIceCandidate::Type remote2) {
826 p1_->SetExpectedTypes(local1, remote1);
827 p2_->SetExpectedTypes(local2, remote2);
828 }
830 void ConnectP1(TrickleMode mode = TRICKLE_NONE) {
831 p1_->Connect(p2_, mode);
832 }
834 void ConnectP2(TrickleMode mode = TRICKLE_NONE) {
835 p2_->Connect(p1_, mode);
836 }
838 void WaitForComplete(int expected_streams = 1) {
839 ASSERT_TRUE_WAIT(p1_->ready_ct() == expected_streams &&
840 p2_->ready_ct() == expected_streams, kDefaultTimeout);
841 ASSERT_TRUE_WAIT(p1_->ice_complete() && p2_->ice_complete(),
842 kDefaultTimeout);
843 }
845 void WaitForGather() {
846 ASSERT_TRUE_WAIT(p1_->gathering_complete(), kDefaultTimeout);
847 ASSERT_TRUE_WAIT(p2_->gathering_complete(), kDefaultTimeout);
848 }
850 void ConnectTrickle(TrickleMode trickle = TRICKLE_SIMULATE) {
851 p1_->Connect(p2_, trickle);
852 p2_->Connect(p1_, trickle);
853 }
855 void SimulateTrickle(size_t stream) {
856 p1_->SimulateTrickle(stream);
857 p2_->SimulateTrickle(stream);
858 ASSERT_TRUE_WAIT(p1_->is_ready(stream), kDefaultTimeout);
859 ASSERT_TRUE_WAIT(p2_->is_ready(stream), kDefaultTimeout);
860 }
862 void SimulateTrickleP1(size_t stream) {
863 p1_->SimulateTrickle(stream);
864 }
866 void SimulateTrickleP2(size_t stream) {
867 p2_->SimulateTrickle(stream);
868 }
870 void VerifyConnected() {
871 }
873 void CloseP1() {
874 p1_->Close();
875 }
877 void ConnectThenDelete() {
878 p1_->Connect(p2_, TRICKLE_NONE, true);
879 p2_->Connect(p1_, TRICKLE_NONE, false);
880 test_utils->sts_target()->Dispatch(WrapRunnable(this,
881 &IceConnectTest::CloseP1),
882 NS_DISPATCH_SYNC);
883 p2_->StartChecks();
885 // Wait to see if we crash
886 PR_Sleep(PR_MillisecondsToInterval(kDefaultTimeout));
887 }
889 void SendReceive() {
890 // p1_->Send(2);
891 test_utils->sts_target()->Dispatch(
892 WrapRunnable(p1_.get(),
893 &IceTestPeer::SendPacket, 0, 1,
894 reinterpret_cast<const unsigned char *>("TEST"), 4),
895 NS_DISPATCH_SYNC);
896 ASSERT_EQ(1u, p1_->sent());
897 ASSERT_TRUE_WAIT(p2_->received() == 1, 1000);
898 }
900 protected:
901 bool initted_;
902 nsCOMPtr<nsIEventTarget> target_;
903 mozilla::ScopedDeletePtr<IceTestPeer> p1_;
904 mozilla::ScopedDeletePtr<IceTestPeer> p2_;
905 };
907 class PrioritizerTest : public ::testing::Test {
908 public:
909 PrioritizerTest():
910 prioritizer_(nullptr) {}
912 ~PrioritizerTest() {
913 if (prioritizer_) {
914 nr_interface_prioritizer_destroy(&prioritizer_);
915 }
916 }
918 void SetPriorizer(nr_interface_prioritizer *prioritizer) {
919 prioritizer_ = prioritizer;
920 }
922 void AddInterface(const std::string& num, int type, int estimated_speed) {
923 std::string str_addr = "10.0.0." + num;
924 std::string ifname = "eth" + num;
925 nr_local_addr local_addr;
926 local_addr.interface.type = type;
927 local_addr.interface.estimated_speed = estimated_speed;
929 int r = nr_ip4_str_port_to_transport_addr(str_addr.c_str(), 0,
930 IPPROTO_UDP, &(local_addr.addr));
931 ASSERT_EQ(0, r);
932 strncpy(local_addr.addr.ifname, ifname.c_str(), MAXIFNAME);
934 r = nr_interface_prioritizer_add_interface(prioritizer_, &local_addr);
935 ASSERT_EQ(0, r);
936 r = nr_interface_prioritizer_sort_preference(prioritizer_);
937 ASSERT_EQ(0, r);
938 }
940 void HasLowerPreference(const std::string& num1, const std::string& num2) {
941 std::string key1 = "eth" + num1 + ":10.0.0." + num1;
942 std::string key2 = "eth" + num2 + ":10.0.0." + num2;
943 UCHAR pref1, pref2;
944 int r = nr_interface_prioritizer_get_priority(prioritizer_, key1.c_str(), &pref1);
945 ASSERT_EQ(0, r);
946 r = nr_interface_prioritizer_get_priority(prioritizer_, key2.c_str(), &pref2);
947 ASSERT_EQ(0, r);
948 ASSERT_LE(pref1, pref2);
949 }
951 private:
952 nr_interface_prioritizer *prioritizer_;
953 };
955 class PacketFilterTest : public ::testing::Test {
956 public:
957 PacketFilterTest(): filter_(nullptr) {}
959 void SetUp() {
960 nsCOMPtr<nsIUDPSocketFilterHandler> handler =
961 do_GetService(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID);
962 handler->NewFilter(getter_AddRefs(filter_));
963 }
965 void TestIncoming(const uint8_t* data, uint32_t len,
966 uint8_t from_addr, int from_port,
967 bool expected_result) {
968 mozilla::net::NetAddr addr;
969 MakeNetAddr(&addr, from_addr, from_port);
970 bool result;
971 nsresult rv = filter_->FilterPacket(&addr, data, len,
972 nsIUDPSocketFilter::SF_INCOMING,
973 &result);
974 ASSERT_EQ(NS_OK, rv);
975 ASSERT_EQ(expected_result, result);
976 }
978 void TestOutgoing(const uint8_t* data, uint32_t len,
979 uint8_t to_addr, int to_port,
980 bool expected_result) {
981 mozilla::net::NetAddr addr;
982 MakeNetAddr(&addr, to_addr, to_port);
983 bool result;
984 nsresult rv = filter_->FilterPacket(&addr, data, len,
985 nsIUDPSocketFilter::SF_OUTGOING,
986 &result);
987 ASSERT_EQ(NS_OK, rv);
988 ASSERT_EQ(expected_result, result);
989 }
991 private:
992 void MakeNetAddr(mozilla::net::NetAddr* net_addr,
993 uint8_t last_digit, uint16_t port) {
994 net_addr->inet.family = AF_INET;
995 net_addr->inet.ip = 192 << 24 | 168 << 16 | 1 << 8 | last_digit;
996 net_addr->inet.port = port;
997 }
999 nsCOMPtr<nsIUDPSocketFilter> filter_;
1000 };
1001 } // end namespace
1003 TEST_F(IceGatherTest, TestGatherFakeStunServerHostnameNoResolver) {
1004 peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
1005 Gather();
1006 }
1008 TEST_F(IceGatherTest, TestGatherFakeStunServerIpAddress) {
1009 peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
1010 peer_->SetFakeResolver();
1011 Gather();
1012 }
1014 TEST_F(IceGatherTest, TestGatherFakeStunServerHostname) {
1015 peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
1016 peer_->SetFakeResolver();
1017 Gather();
1018 }
1020 TEST_F(IceGatherTest, TestGatherFakeStunBogusHostname) {
1021 peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
1022 peer_->SetFakeResolver();
1023 Gather();
1024 }
1026 TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddress) {
1027 peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
1028 peer_->SetDNSResolver();
1029 Gather();
1030 // TODO(jib@mozilla.com): ensure we get server reflexive candidates Bug 848094
1031 }
1033 TEST_F(IceGatherTest, TestGatherDNSStunServerHostname) {
1034 peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort);
1035 peer_->SetDNSResolver();
1036 Gather();
1037 }
1039 TEST_F(IceGatherTest, TestGatherDNSStunBogusHostname) {
1040 peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
1041 peer_->SetDNSResolver();
1042 Gather();
1043 }
1045 TEST_F(IceGatherTest, TestGatherTurn) {
1046 if (g_turn_server.empty())
1047 return;
1048 peer_->SetTurnServer(g_turn_server, kDefaultStunServerPort,
1049 g_turn_user, g_turn_password, kNrIceTransportUdp);
1050 Gather();
1051 }
1053 TEST_F(IceGatherTest, TestGatherTurnTcp) {
1054 if (g_turn_server.empty())
1055 return;
1056 peer_->SetTurnServer(g_turn_server, kDefaultStunServerPort,
1057 g_turn_user, g_turn_password, kNrIceTransportTcp);
1058 Gather();
1059 }
1061 TEST_F(IceGatherTest, TestGatherDisableComponent) {
1062 peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort);
1063 peer_->AddStream(2);
1064 peer_->DisableComponent(1, 2);
1065 Gather();
1066 std::vector<std::string> candidates =
1067 peer_->GetCandidates(1);
1069 for (size_t i=0; i<candidates.size(); ++i) {
1070 size_t sp1 = candidates[i].find(' ');
1071 ASSERT_EQ(0, candidates[i].compare(sp1+1, 1, "1", 1));
1072 }
1073 }
1076 // Verify that a bogus candidate doesn't cause crashes on the
1077 // main thread. See bug 856433.
1078 TEST_F(IceGatherTest, TestBogusCandidate) {
1079 Gather();
1080 peer_->ParseCandidate(0, kBogusIceCandidate);
1081 }
1083 TEST_F(IceGatherTest, VerifyTestStunServer) {
1084 UseFakeStunServerWithResponse("192.0.2.133", 3333);
1085 Gather();
1086 ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.133 3333 "));
1087 }
1089 TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddr) {
1090 UseFakeStunServerWithResponse("0.0.0.0", 3333);
1091 Gather();
1092 ASSERT_FALSE(StreamHasMatchingCandidate(0, " 0.0.0.0 "));
1093 }
1095 TEST_F(IceGatherTest, TestStunServerReturnsPort0) {
1096 UseFakeStunServerWithResponse("192.0.2.133", 0);
1097 Gather();
1098 ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.2.133 0 "));
1099 }
1101 TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddr) {
1102 UseFakeStunServerWithResponse("127.0.0.133", 3333);
1103 Gather();
1104 ASSERT_FALSE(StreamHasMatchingCandidate(0, " 127.0.0.133 "));
1105 }
1107 TEST_F(IceGatherTest, TestStunServerTrickle) {
1108 UseFakeStunServerWithResponse("192.0.2.1", 3333);
1109 TestStunServer::GetInstance()->SetActive(false);
1110 Gather(false);
1111 ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1"));
1112 TestStunServer::GetInstance()->SetActive(true);
1113 WaitForGather();
1114 ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1"));
1115 }
1117 TEST_F(IceConnectTest, TestGather) {
1118 AddStream("first", 1);
1119 ASSERT_TRUE(Gather(true));
1120 }
1122 TEST_F(IceConnectTest, TestGatherAutoPrioritize) {
1123 Init(false);
1124 AddStream("first", 1);
1125 ASSERT_TRUE(Gather(true));
1126 }
1129 TEST_F(IceConnectTest, TestConnect) {
1130 AddStream("first", 1);
1131 ASSERT_TRUE(Gather(true));
1132 Connect();
1133 }
1135 TEST_F(IceConnectTest, TestConnectTwoComponents) {
1136 AddStream("first", 2);
1137 ASSERT_TRUE(Gather(true));
1138 Connect();
1139 }
1141 TEST_F(IceConnectTest, TestConnectTwoComponentsDisableSecond) {
1142 AddStream("first", 2);
1143 ASSERT_TRUE(Gather(true));
1144 p1_->DisableComponent(0, 2);
1145 p2_->DisableComponent(0, 2);
1146 Connect();
1147 }
1150 TEST_F(IceConnectTest, TestConnectP2ThenP1) {
1151 AddStream("first", 1);
1152 ASSERT_TRUE(Gather(true));
1153 ConnectP2();
1154 PR_Sleep(1000);
1155 ConnectP1();
1156 WaitForComplete();
1157 }
1159 TEST_F(IceConnectTest, TestConnectP2ThenP1Trickle) {
1160 AddStream("first", 1);
1161 ASSERT_TRUE(Gather(true));
1162 ConnectP2();
1163 PR_Sleep(1000);
1164 ConnectP1(TRICKLE_SIMULATE);
1165 SimulateTrickleP1(0);
1166 WaitForComplete();
1167 }
1169 TEST_F(IceConnectTest, TestConnectP2ThenP1TrickleTwoComponents) {
1170 AddStream("first", 1);
1171 AddStream("second", 2);
1172 ASSERT_TRUE(Gather(true));
1173 ConnectP2();
1174 PR_Sleep(1000);
1175 ConnectP1(TRICKLE_SIMULATE);
1176 SimulateTrickleP1(0);
1177 std::cerr << "Sleeping between trickle streams" << std::endl;
1178 PR_Sleep(1000); // Give this some time to settle but not complete
1179 // all of ICE.
1180 SimulateTrickleP1(1);
1181 WaitForComplete(2);
1182 }
1184 TEST_F(IceConnectTest, TestConnectAutoPrioritize) {
1185 Init(false);
1186 AddStream("first", 1);
1187 ASSERT_TRUE(Gather(true));
1188 Connect();
1189 }
1191 TEST_F(IceConnectTest, TestConnectTrickleOneStreamOneComponent) {
1192 AddStream("first", 1);
1193 ASSERT_TRUE(Gather(true));
1194 ConnectTrickle();
1195 SimulateTrickle(0);
1196 ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
1197 ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
1198 }
1200 TEST_F(IceConnectTest, TestConnectTrickleTwoStreamsOneComponent) {
1201 AddStream("first", 1);
1202 AddStream("second", 1);
1203 ASSERT_TRUE(Gather(true));
1204 ConnectTrickle();
1205 SimulateTrickle(0);
1206 SimulateTrickle(1);
1207 ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
1208 ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
1209 }
1211 TEST_F(IceConnectTest, TestConnectRealTrickleOneStreamOneComponent) {
1212 AddStream("first", 1);
1213 AddStream("second", 1);
1214 ASSERT_TRUE(Gather(false));
1215 ConnectTrickle(TRICKLE_REAL);
1216 ASSERT_TRUE_WAIT(p1_->ice_complete(), kDefaultTimeout);
1217 ASSERT_TRUE_WAIT(p2_->ice_complete(), kDefaultTimeout);
1218 WaitForGather(); // ICE can complete before we finish gathering.
1219 }
1221 TEST_F(IceConnectTest, TestSendReceive) {
1222 AddStream("first", 1);
1223 ASSERT_TRUE(Gather(true));
1224 Connect();
1225 SendReceive();
1226 }
1228 TEST_F(IceConnectTest, TestConnectTurn) {
1229 if (g_turn_server.empty())
1230 return;
1232 AddStream("first", 1);
1233 SetTurnServer(g_turn_server, kDefaultStunServerPort,
1234 g_turn_user, g_turn_password);
1235 ASSERT_TRUE(Gather(true));
1236 Connect();
1237 }
1239 TEST_F(IceConnectTest, TestConnectTurnTcp) {
1240 if (g_turn_server.empty())
1241 return;
1243 AddStream("first", 1);
1244 SetTurnServer(g_turn_server, kDefaultStunServerPort,
1245 g_turn_user, g_turn_password, kNrIceTransportTcp);
1246 ASSERT_TRUE(Gather(true));
1247 Connect();
1248 }
1250 TEST_F(IceConnectTest, TestConnectTurnOnly) {
1251 if (g_turn_server.empty())
1252 return;
1254 AddStream("first", 1);
1255 SetTurnServer(g_turn_server, kDefaultStunServerPort,
1256 g_turn_user, g_turn_password);
1257 ASSERT_TRUE(Gather(true));
1258 SetCandidateFilter(IsRelayCandidate);
1259 SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
1260 NrIceCandidate::Type::ICE_RELAYED);
1261 Connect();
1262 }
1264 TEST_F(IceConnectTest, TestConnectTurnTcpOnly) {
1265 if (g_turn_server.empty())
1266 return;
1268 AddStream("first", 1);
1269 SetTurnServer(g_turn_server, kDefaultStunServerPort,
1270 g_turn_user, g_turn_password, kNrIceTransportTcp);
1271 ASSERT_TRUE(Gather(true));
1272 SetCandidateFilter(IsRelayCandidate);
1273 SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
1274 NrIceCandidate::Type::ICE_RELAYED,
1275 kNrIceTransportTcp);
1276 Connect();
1277 }
1279 TEST_F(IceConnectTest, TestSendReceiveTurnOnly) {
1280 if (g_turn_server.empty())
1281 return;
1283 AddStream("first", 1);
1284 SetTurnServer(g_turn_server, kDefaultStunServerPort,
1285 g_turn_user, g_turn_password);
1286 ASSERT_TRUE(Gather(true));
1287 SetCandidateFilter(IsRelayCandidate);
1288 SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
1289 NrIceCandidate::Type::ICE_RELAYED);
1290 Connect();
1291 SendReceive();
1292 }
1294 TEST_F(IceConnectTest, TestSendReceiveTurnTcpOnly) {
1295 if (g_turn_server.empty())
1296 return;
1298 AddStream("first", 1);
1299 SetTurnServer(g_turn_server, kDefaultStunServerPort,
1300 g_turn_user, g_turn_password, kNrIceTransportTcp);
1301 ASSERT_TRUE(Gather(true));
1302 SetCandidateFilter(IsRelayCandidate);
1303 SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
1304 NrIceCandidate::Type::ICE_RELAYED,
1305 kNrIceTransportTcp);
1306 Connect();
1307 SendReceive();
1308 }
1310 TEST_F(IceConnectTest, TestSendReceiveTurnBothOnly) {
1311 if (g_turn_server.empty())
1312 return;
1314 AddStream("first", 1);
1315 std::vector<NrIceTurnServer> turn_servers;
1316 std::vector<unsigned char> password_vec(g_turn_password.begin(),
1317 g_turn_password.end());
1318 turn_servers.push_back(*NrIceTurnServer::Create(
1319 g_turn_server, kDefaultStunServerPort,
1320 g_turn_user, password_vec, kNrIceTransportTcp));
1321 turn_servers.push_back(*NrIceTurnServer::Create(
1322 g_turn_server, kDefaultStunServerPort,
1323 g_turn_user, password_vec, kNrIceTransportUdp));
1324 SetTurnServers(turn_servers);
1325 ASSERT_TRUE(Gather(true));
1326 SetCandidateFilter(IsRelayCandidate);
1327 // UDP is preferred.
1328 SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
1329 NrIceCandidate::Type::ICE_RELAYED,
1330 kNrIceTransportUdp);
1331 Connect();
1332 SendReceive();
1333 }
1335 TEST_F(IceConnectTest, TestConnectShutdownOneSide) {
1336 AddStream("first", 1);
1337 ASSERT_TRUE(Gather(true));
1338 ConnectThenDelete();
1339 }
1341 TEST_F(IceConnectTest, TestPollCandPairsBeforeConnect) {
1342 AddStream("first", 1);
1343 ASSERT_TRUE(Gather(true));
1345 std::vector<NrIceCandidatePair> pairs;
1346 nsresult res = p1_->GetCandidatePairs(0, &pairs);
1347 // There should be no candidate pairs prior to calling Connect()
1348 ASSERT_TRUE(NS_FAILED(res));
1349 ASSERT_EQ(0U, pairs.size());
1351 res = p2_->GetCandidatePairs(0, &pairs);
1352 ASSERT_TRUE(NS_FAILED(res));
1353 ASSERT_EQ(0U, pairs.size());
1354 }
1356 TEST_F(IceConnectTest, TestPollCandPairsAfterConnect) {
1357 AddStream("first", 1);
1358 ASSERT_TRUE(Gather(true));
1359 Connect();
1361 std::vector<NrIceCandidatePair> pairs;
1362 nsresult r = p1_->GetCandidatePairs(0, &pairs);
1363 ASSERT_EQ(NS_OK, r);
1364 // How detailed of a check do we want to do here? If the turn server is
1365 // functioning, we'll get at least two pairs, but this is probably not
1366 // something we should assume.
1367 ASSERT_NE(0U, pairs.size());
1368 ASSERT_TRUE(p1_->CandidatePairsPriorityDescending(pairs));
1369 ASSERT_TRUE(ContainsSucceededPair(pairs));
1370 pairs.clear();
1372 r = p2_->GetCandidatePairs(0, &pairs);
1373 ASSERT_EQ(NS_OK, r);
1374 ASSERT_NE(0U, pairs.size());
1375 ASSERT_TRUE(p2_->CandidatePairsPriorityDescending(pairs));
1376 ASSERT_TRUE(ContainsSucceededPair(pairs));
1377 }
1379 TEST_F(IceConnectTest, TestPollCandPairsDuringConnect) {
1380 AddStream("first", 1);
1381 ASSERT_TRUE(Gather(true));
1383 p1_->Connect(p2_, TRICKLE_NONE, false);
1384 p2_->Connect(p1_, TRICKLE_NONE, false);
1386 std::vector<NrIceCandidatePair> pairs1;
1387 std::vector<NrIceCandidatePair> pairs2;
1389 p1_->StartChecks();
1390 p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
1391 p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
1393 p2_->StartChecks();
1394 p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
1395 p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
1397 WaitForComplete();
1398 p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
1399 p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
1400 ASSERT_TRUE(ContainsSucceededPair(pairs1));
1401 ASSERT_TRUE(ContainsSucceededPair(pairs2));
1402 }
1404 TEST_F(IceConnectTest, TestRLogRingBuffer) {
1405 RLogRingBuffer::CreateInstance();
1406 AddStream("first", 1);
1407 ASSERT_TRUE(Gather(true));
1409 p1_->Connect(p2_, TRICKLE_NONE, false);
1410 p2_->Connect(p1_, TRICKLE_NONE, false);
1412 std::vector<NrIceCandidatePair> pairs1;
1413 std::vector<NrIceCandidatePair> pairs2;
1415 p1_->StartChecks();
1416 p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
1417 p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
1419 p2_->StartChecks();
1420 p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
1421 p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
1423 WaitForComplete();
1424 p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
1425 p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
1426 ASSERT_TRUE(ContainsSucceededPair(pairs1));
1427 ASSERT_TRUE(ContainsSucceededPair(pairs2));
1429 for (auto p = pairs1.begin(); p != pairs1.end(); ++p) {
1430 std::deque<std::string> logs;
1431 std::string substring("CAND-PAIR(");
1432 substring += p->codeword;
1433 RLogRingBuffer::GetInstance()->Filter(substring, 0, &logs);
1434 ASSERT_NE(0U, logs.size());
1435 }
1437 for (auto p = pairs2.begin(); p != pairs2.end(); ++p) {
1438 std::deque<std::string> logs;
1439 std::string substring("CAND-PAIR(");
1440 substring += p->codeword;
1441 RLogRingBuffer::GetInstance()->Filter(substring, 0, &logs);
1442 ASSERT_NE(0U, logs.size());
1443 }
1445 RLogRingBuffer::DestroyInstance();
1446 }
1448 TEST_F(PrioritizerTest, TestPrioritizer) {
1449 SetPriorizer(::mozilla::CreateInterfacePrioritizer());
1451 AddInterface("0", NR_INTERFACE_TYPE_VPN, 100); // unknown vpn
1452 AddInterface("1", NR_INTERFACE_TYPE_VPN | NR_INTERFACE_TYPE_WIRED, 100); // wired vpn
1453 AddInterface("2", NR_INTERFACE_TYPE_VPN | NR_INTERFACE_TYPE_WIFI, 100); // wifi vpn
1454 AddInterface("3", NR_INTERFACE_TYPE_VPN | NR_INTERFACE_TYPE_MOBILE, 100); // wifi vpn
1455 AddInterface("4", NR_INTERFACE_TYPE_WIRED, 1000); // wired, high speed
1456 AddInterface("5", NR_INTERFACE_TYPE_WIRED, 10); // wired, low speed
1457 AddInterface("6", NR_INTERFACE_TYPE_WIFI, 10); // wifi, low speed
1458 AddInterface("7", NR_INTERFACE_TYPE_WIFI, 1000); // wifi, high speed
1459 AddInterface("8", NR_INTERFACE_TYPE_MOBILE, 10); // mobile, low speed
1460 AddInterface("9", NR_INTERFACE_TYPE_MOBILE, 1000); // mobile, high speed
1461 AddInterface("10", NR_INTERFACE_TYPE_UNKNOWN, 10); // unknown, low speed
1462 AddInterface("11", NR_INTERFACE_TYPE_UNKNOWN, 1000); // unknown, high speed
1464 // expected preference "4" > "5" > "1" > "7" > "6" > "2" > "9" > "8" > "3" > "11" > "10" > "0"
1466 HasLowerPreference("0", "10");
1467 HasLowerPreference("10", "11");
1468 HasLowerPreference("11", "3");
1469 HasLowerPreference("3", "8");
1470 HasLowerPreference("8", "9");
1471 HasLowerPreference("9", "2");
1472 HasLowerPreference("2", "6");
1473 HasLowerPreference("6", "7");
1474 HasLowerPreference("7", "1");
1475 HasLowerPreference("1", "5");
1476 HasLowerPreference("5", "4");
1477 }
1479 TEST_F(PacketFilterTest, TestSendNonStunPacket) {
1480 const unsigned char data[] = "12345abcde";
1481 TestOutgoing(data, sizeof(data), 123, 45, false);
1482 }
1484 TEST_F(PacketFilterTest, TestRecvNonStunPacket) {
1485 const unsigned char data[] = "12345abcde";
1486 TestIncoming(data, sizeof(data), 123, 45, false);
1487 }
1489 TEST_F(PacketFilterTest, TestSendStunPacket) {
1490 nr_stun_message *msg;
1491 ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
1492 msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
1493 ASSERT_EQ(0, nr_stun_encode_message(msg));
1494 TestOutgoing(msg->buffer, msg->length, 123, 45, true);
1495 ASSERT_EQ(0, nr_stun_message_destroy(&msg));
1496 }
1498 TEST_F(PacketFilterTest, TestRecvStunPacketWithoutAPendingId) {
1499 nr_stun_message *msg;
1500 ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
1502 msg->header.id.octet[0] = 1;
1503 msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
1504 ASSERT_EQ(0, nr_stun_encode_message(msg));
1505 TestOutgoing(msg->buffer, msg->length, 123, 45, true);
1507 msg->header.id.octet[0] = 0;
1508 msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
1509 ASSERT_EQ(0, nr_stun_encode_message(msg));
1510 TestIncoming(msg->buffer, msg->length, 123, 45, true);
1512 ASSERT_EQ(0, nr_stun_message_destroy(&msg));
1513 }
1515 TEST_F(PacketFilterTest, TestRecvStunPacketWithoutAPendingAddress) {
1516 nr_stun_message *msg;
1517 ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
1519 msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
1520 ASSERT_EQ(0, nr_stun_encode_message(msg));
1521 TestOutgoing(msg->buffer, msg->length, 123, 45, true);
1523 msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
1524 ASSERT_EQ(0, nr_stun_encode_message(msg));
1525 TestIncoming(msg->buffer, msg->length, 123, 46, false);
1526 TestIncoming(msg->buffer, msg->length, 124, 45, false);
1528 ASSERT_EQ(0, nr_stun_message_destroy(&msg));
1529 }
1531 TEST_F(PacketFilterTest, TestRecvStunPacketWithPendingIdAndAddress) {
1532 nr_stun_message *msg;
1533 ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
1535 msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
1536 ASSERT_EQ(0, nr_stun_encode_message(msg));
1537 TestOutgoing(msg->buffer, msg->length, 123, 45, true);
1539 msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
1540 ASSERT_EQ(0, nr_stun_encode_message(msg));
1541 TestIncoming(msg->buffer, msg->length, 123, 45, true);
1543 // Test whitelist by filtering non-stun packets.
1544 const unsigned char data[] = "12345abcde";
1546 // 123:45 is white-listed.
1547 TestOutgoing(data, sizeof(data), 123, 45, true);
1548 TestIncoming(data, sizeof(data), 123, 45, true);
1550 // Indications pass as well.
1551 msg->header.type = NR_STUN_MSG_BINDING_INDICATION;
1552 ASSERT_EQ(0, nr_stun_encode_message(msg));
1553 TestOutgoing(msg->buffer, msg->length, 123, 45, true);
1554 TestIncoming(msg->buffer, msg->length, 123, 45, true);
1556 // Packets from and to other address are still disallowed.
1557 TestOutgoing(data, sizeof(data), 123, 46, false);
1558 TestIncoming(data, sizeof(data), 123, 46, false);
1559 TestOutgoing(data, sizeof(data), 124, 45, false);
1560 TestIncoming(data, sizeof(data), 124, 45, false);
1562 ASSERT_EQ(0, nr_stun_message_destroy(&msg));
1563 }
1565 TEST_F(PacketFilterTest, TestSendNonRequestStunPacket) {
1566 nr_stun_message *msg;
1567 ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg));
1569 msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
1570 ASSERT_EQ(0, nr_stun_encode_message(msg));
1571 TestOutgoing(msg->buffer, msg->length, 123, 45, false);
1573 // Send a packet so we allow the incoming request.
1574 msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
1575 ASSERT_EQ(0, nr_stun_encode_message(msg));
1576 TestOutgoing(msg->buffer, msg->length, 123, 45, true);
1578 // This packet makes us able to send a response.
1579 msg->header.type = NR_STUN_MSG_BINDING_REQUEST;
1580 ASSERT_EQ(0, nr_stun_encode_message(msg));
1581 TestIncoming(msg->buffer, msg->length, 123, 45, true);
1583 msg->header.type = NR_STUN_MSG_BINDING_RESPONSE;
1584 ASSERT_EQ(0, nr_stun_encode_message(msg));
1585 TestOutgoing(msg->buffer, msg->length, 123, 45, true);
1587 ASSERT_EQ(0, nr_stun_message_destroy(&msg));
1588 }
1590 static std::string get_environment(const char *name) {
1591 char *value = getenv(name);
1593 if (!value)
1594 return "";
1596 return value;
1597 }
1599 int main(int argc, char **argv)
1600 {
1601 #ifdef LINUX
1602 // This test can cause intermittent oranges on the builders on Linux
1603 CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_TESTS")
1604 #endif
1606 g_turn_server = get_environment("TURN_SERVER_ADDRESS");
1607 g_turn_user = get_environment("TURN_SERVER_USER");
1608 g_turn_password = get_environment("TURN_SERVER_PASSWORD");
1610 if (g_turn_server.empty() ||
1611 g_turn_user.empty(),
1612 g_turn_password.empty()) {
1613 printf(
1614 "Set TURN_SERVER_ADDRESS, TURN_SERVER_USER, and TURN_SERVER_PASSWORD\n"
1615 "environment variables to run this test\n");
1616 g_turn_server="";
1617 }
1619 std::string tmp = get_environment("STUN_SERVER_ADDRESS");
1620 if (tmp != "")
1621 g_stun_server_address = tmp;
1624 tmp = get_environment("STUN_SERVER_HOSTNAME");
1625 if (tmp != "")
1626 g_stun_server_hostname = tmp;
1628 test_utils = new MtransportTestUtils();
1629 NSS_NoDB_Init(nullptr);
1630 NSS_SetDomesticPolicy();
1632 // Start the tests
1633 ::testing::InitGoogleTest(&argc, argv);
1635 ::testing::TestEventListeners& listeners =
1636 ::testing::UnitTest::GetInstance()->listeners();
1637 // Adds a listener to the end. Google Test takes the ownership.
1639 listeners.Append(new test::RingbufferDumper(test_utils));
1640 test_utils->sts_target()->Dispatch(
1641 WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
1643 int rv = RUN_ALL_TESTS();
1645 test_utils->sts_target()->Dispatch(
1646 WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC);
1648 delete test_utils;
1649 return rv;
1650 }