1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/mtransport/test/ice_unittest.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1650 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +// Original author: ekr@rtfm.com 1.11 + 1.12 +#include <algorithm> 1.13 +#include <deque> 1.14 +#include <iostream> 1.15 +#include <limits> 1.16 +#include <map> 1.17 +#include <string> 1.18 +#include <vector> 1.19 + 1.20 +#include "sigslot.h" 1.21 + 1.22 +#include "logging.h" 1.23 +#include "nspr.h" 1.24 +#include "nss.h" 1.25 +#include "ssl.h" 1.26 + 1.27 +#include "mozilla/Scoped.h" 1.28 +#include "nsThreadUtils.h" 1.29 +#include "nsXPCOM.h" 1.30 + 1.31 +#include "nricectx.h" 1.32 +#include "nricemediastream.h" 1.33 +#include "nriceresolverfake.h" 1.34 +#include "nriceresolver.h" 1.35 +#include "nrinterfaceprioritizer.h" 1.36 +#include "mtransport_test_utils.h" 1.37 +#include "gtest_ringbuffer_dumper.h" 1.38 +#include "rlogringbuffer.h" 1.39 +#include "runnable_utils.h" 1.40 +#include "stunserver.h" 1.41 +// TODO(bcampen@mozilla.com): Big fat hack since the build system doesn't give 1.42 +// us a clean way to add object files to a single executable. 1.43 +#include "stunserver.cpp" 1.44 +#include "stun_udp_socket_filter.h" 1.45 +#include "mozilla/net/DNS.h" 1.46 + 1.47 +#define GTEST_HAS_RTTI 0 1.48 +#include "gtest/gtest.h" 1.49 +#include "gtest_utils.h" 1.50 + 1.51 +using namespace mozilla; 1.52 +MtransportTestUtils *test_utils; 1.53 + 1.54 +bool stream_added = false; 1.55 + 1.56 +static int kDefaultTimeout = 7000; 1.57 + 1.58 +const std::string kDefaultStunServerAddress((char *)"23.21.150.121"); 1.59 +const std::string kDefaultStunServerHostname( 1.60 + (char *)"ec2-23-21-150-121.compute-1.amazonaws.com"); 1.61 +const std::string kBogusStunServerHostname( 1.62 + (char *)"stun-server-nonexistent.invalid"); 1.63 +const uint16_t kDefaultStunServerPort=3478; 1.64 +const std::string kBogusIceCandidate( 1.65 + (char *)"candidate:0 2 UDP 2113601790 192.168.178.20 50769 typ"); 1.66 + 1.67 +std::string g_stun_server_address(kDefaultStunServerAddress); 1.68 +std::string g_stun_server_hostname(kDefaultStunServerHostname); 1.69 +std::string g_turn_server; 1.70 +std::string g_turn_user; 1.71 +std::string g_turn_password; 1.72 + 1.73 +namespace { 1.74 + 1.75 +enum TrickleMode { TRICKLE_NONE, TRICKLE_SIMULATE, TRICKLE_REAL }; 1.76 + 1.77 +typedef bool (*CandidateFilter)(const std::string& candidate); 1.78 + 1.79 +static bool IsRelayCandidate(const std::string& candidate) { 1.80 + return candidate.find("typ relay") != std::string::npos; 1.81 +} 1.82 + 1.83 +bool ContainsSucceededPair(const std::vector<NrIceCandidatePair>& pairs) { 1.84 + for (size_t i = 0; i < pairs.size(); ++i) { 1.85 + if (pairs[i].state == NrIceCandidatePair::STATE_SUCCEEDED) { 1.86 + return true; 1.87 + } 1.88 + } 1.89 + return false; 1.90 +} 1.91 + 1.92 +// Note: Does not correspond to any notion of prioritization; this is just 1.93 +// so we can use stl containers/algorithms that need a comparator 1.94 +bool operator<(const NrIceCandidate& lhs, 1.95 + const NrIceCandidate& rhs) { 1.96 + if (lhs.cand_addr.host == rhs.cand_addr.host) { 1.97 + if (lhs.cand_addr.port == rhs.cand_addr.port) { 1.98 + if (lhs.cand_addr.transport == rhs.cand_addr.transport) { 1.99 + return lhs.type < rhs.type; 1.100 + } 1.101 + return lhs.cand_addr.transport < rhs.cand_addr.transport; 1.102 + } 1.103 + return lhs.cand_addr.port < rhs.cand_addr.port; 1.104 + } 1.105 + return lhs.cand_addr.host < rhs.cand_addr.host; 1.106 +} 1.107 + 1.108 +bool operator==(const NrIceCandidate& lhs, 1.109 + const NrIceCandidate& rhs) { 1.110 + return !((lhs < rhs) || (rhs < lhs)); 1.111 +} 1.112 + 1.113 +class IceCandidatePairCompare { 1.114 + public: 1.115 + bool operator()(const NrIceCandidatePair& lhs, 1.116 + const NrIceCandidatePair& rhs) const { 1.117 + if (lhs.priority == rhs.priority) { 1.118 + if (lhs.local == rhs.local) { 1.119 + if (lhs.remote == rhs.remote) { 1.120 + return lhs.codeword < rhs.codeword; 1.121 + } 1.122 + return lhs.remote < rhs.remote; 1.123 + } 1.124 + return lhs.local < rhs.local; 1.125 + } 1.126 + return lhs.priority < rhs.priority; 1.127 + } 1.128 +}; 1.129 + 1.130 +class IceTestPeer : public sigslot::has_slots<> { 1.131 + public: 1.132 + 1.133 + IceTestPeer(const std::string& name, bool offerer, bool set_priorities) : 1.134 + name_(name), 1.135 + ice_ctx_(NrIceCtx::Create(name, offerer, set_priorities)), 1.136 + streams_(), 1.137 + candidates_(), 1.138 + gathering_complete_(false), 1.139 + ready_ct_(0), 1.140 + ice_complete_(false), 1.141 + received_(0), 1.142 + sent_(0), 1.143 + fake_resolver_(), 1.144 + dns_resolver_(new NrIceResolver()), 1.145 + remote_(nullptr), 1.146 + candidate_filter_(nullptr), 1.147 + expected_local_type_(NrIceCandidate::ICE_HOST), 1.148 + expected_local_transport_(kNrIceTransportUdp), 1.149 + expected_remote_type_(NrIceCandidate::ICE_HOST), 1.150 + trickle_mode_(TRICKLE_NONE), 1.151 + trickled_(0) { 1.152 + ice_ctx_->SignalGatheringStateChange.connect( 1.153 + this, 1.154 + &IceTestPeer::GatheringStateChange); 1.155 + ice_ctx_->SignalConnectionStateChange.connect( 1.156 + this, 1.157 + &IceTestPeer::ConnectionStateChange); 1.158 + } 1.159 + 1.160 + ~IceTestPeer() { 1.161 + test_utils->sts_target()->Dispatch(WrapRunnable(this, 1.162 + &IceTestPeer::Shutdown), 1.163 + NS_DISPATCH_SYNC); 1.164 + 1.165 + // Give the ICE destruction callback time to fire before 1.166 + // we destroy the resolver. 1.167 + PR_Sleep(1000); 1.168 + } 1.169 + 1.170 + void AddStream(int components) { 1.171 + char name[100]; 1.172 + snprintf(name, sizeof(name), "%s:stream%d", name_.c_str(), 1.173 + (int)streams_.size()); 1.174 + 1.175 + mozilla::RefPtr<NrIceMediaStream> stream = 1.176 + ice_ctx_->CreateStream(static_cast<char *>(name), components); 1.177 + 1.178 + ASSERT_TRUE(stream); 1.179 + streams_.push_back(stream); 1.180 + stream->SignalCandidate.connect(this, &IceTestPeer::CandidateInitialized); 1.181 + stream->SignalReady.connect(this, &IceTestPeer::StreamReady); 1.182 + stream->SignalFailed.connect(this, &IceTestPeer::StreamFailed); 1.183 + stream->SignalPacketReceived.connect(this, &IceTestPeer::PacketReceived); 1.184 + } 1.185 + 1.186 + void SetStunServer(const std::string addr, uint16_t port) { 1.187 + std::vector<NrIceStunServer> stun_servers; 1.188 + ScopedDeletePtr<NrIceStunServer> server(NrIceStunServer::Create(addr, 1.189 + port)); 1.190 + stun_servers.push_back(*server); 1.191 + ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers))); 1.192 + } 1.193 + 1.194 + void SetTurnServer(const std::string addr, uint16_t port, 1.195 + const std::string username, 1.196 + const std::string password, 1.197 + const char* transport) { 1.198 + std::vector<unsigned char> password_vec(password.begin(), password.end()); 1.199 + SetTurnServer(addr, port, username, password_vec, transport); 1.200 + } 1.201 + 1.202 + 1.203 + void SetTurnServer(const std::string addr, uint16_t port, 1.204 + const std::string username, 1.205 + const std::vector<unsigned char> password, 1.206 + const char* transport) { 1.207 + std::vector<NrIceTurnServer> turn_servers; 1.208 + ScopedDeletePtr<NrIceTurnServer> server(NrIceTurnServer::Create( 1.209 + addr, port, username, password, transport)); 1.210 + turn_servers.push_back(*server); 1.211 + ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(turn_servers))); 1.212 + } 1.213 + 1.214 + void SetTurnServers(const std::vector<NrIceTurnServer> servers) { 1.215 + ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(servers))); 1.216 + } 1.217 + 1.218 + void SetFakeResolver() { 1.219 + ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init())); 1.220 + PRNetAddr addr; 1.221 + PRStatus status = PR_StringToNetAddr(g_stun_server_address.c_str(), 1.222 + &addr); 1.223 + addr.inet.port = kDefaultStunServerPort; 1.224 + ASSERT_EQ(PR_SUCCESS, status); 1.225 + fake_resolver_.SetAddr(g_stun_server_hostname, addr); 1.226 + ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver( 1.227 + fake_resolver_.AllocateResolver()))); 1.228 + } 1.229 + 1.230 + void SetDNSResolver() { 1.231 + ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init())); 1.232 + ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver( 1.233 + dns_resolver_->AllocateResolver()))); 1.234 + } 1.235 + 1.236 + void Gather() { 1.237 + nsresult res; 1.238 + 1.239 + test_utils->sts_target()->Dispatch( 1.240 + WrapRunnableRet(ice_ctx_, &NrIceCtx::StartGathering, &res), 1.241 + NS_DISPATCH_SYNC); 1.242 + 1.243 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.244 + } 1.245 + 1.246 + // Get various pieces of state 1.247 + std::vector<std::string> GetGlobalAttributes() { 1.248 + return ice_ctx_->GetGlobalAttributes(); 1.249 + } 1.250 + 1.251 + std::vector<std::string> GetCandidates(size_t stream) { 1.252 + std::vector<std::string> v; 1.253 + 1.254 + RUN_ON_THREAD( 1.255 + test_utils->sts_target(), 1.256 + WrapRunnableRet(this, &IceTestPeer::GetCandidates_s, stream, &v), 1.257 + NS_DISPATCH_SYNC); 1.258 + 1.259 + return v; 1.260 + } 1.261 + 1.262 + std::vector<std::string> GetCandidates_s(size_t stream) { 1.263 + std::vector<std::string> candidates; 1.264 + 1.265 + if (stream >= streams_.size()) 1.266 + return candidates; 1.267 + 1.268 + std::vector<std::string> candidates_in = 1.269 + streams_[stream]->GetCandidates(); 1.270 + 1.271 + 1.272 + for (size_t i=0; i < candidates_in.size(); i++) { 1.273 + if ((!candidate_filter_) || candidate_filter_(candidates_in[i])) { 1.274 + std::cerr << "Returning candidate: " << candidates_in[i] << std::endl; 1.275 + candidates.push_back(candidates_in[i]); 1.276 + } 1.277 + } 1.278 + 1.279 + return candidates; 1.280 + } 1.281 + 1.282 + void SetExpectedTypes(NrIceCandidate::Type local, 1.283 + NrIceCandidate::Type remote, 1.284 + std::string local_transport = kNrIceTransportUdp) { 1.285 + expected_local_type_ = local; 1.286 + expected_local_transport_ = local_transport; 1.287 + expected_remote_type_ = remote; 1.288 + } 1.289 + 1.290 + bool gathering_complete() { return gathering_complete_; } 1.291 + int ready_ct() { return ready_ct_; } 1.292 + bool is_ready(size_t stream) { 1.293 + return streams_[stream]->state() == NrIceMediaStream::ICE_OPEN; 1.294 + } 1.295 + bool ice_complete() { return ice_complete_; } 1.296 + size_t received() { return received_; } 1.297 + size_t sent() { return sent_; } 1.298 + 1.299 + // Start connecting to another peer 1.300 + void Connect_s(IceTestPeer *remote, TrickleMode trickle_mode, 1.301 + bool start = true) { 1.302 + nsresult res; 1.303 + 1.304 + remote_ = remote; 1.305 + 1.306 + trickle_mode_ = trickle_mode; 1.307 + res = ice_ctx_->ParseGlobalAttributes(remote->GetGlobalAttributes()); 1.308 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.309 + 1.310 + if (trickle_mode == TRICKLE_NONE || 1.311 + trickle_mode == TRICKLE_REAL) { 1.312 + for (size_t i=0; i<streams_.size(); ++i) { 1.313 + std::vector<std::string> candidates = 1.314 + remote->GetCandidates(i); 1.315 + 1.316 + for (size_t j=0; j<candidates.size(); ++j) { 1.317 + std::cerr << "Candidate: " + candidates[j] << std::endl; 1.318 + } 1.319 + res = streams_[i]->ParseAttributes(candidates); 1.320 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.321 + } 1.322 + } else { 1.323 + // Parse empty attributes and then trickle them out later 1.324 + for (size_t i=0; i<streams_.size(); ++i) { 1.325 + std::vector<std::string> empty_attrs; 1.326 + res = streams_[i]->ParseAttributes(empty_attrs); 1.327 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.328 + } 1.329 + } 1.330 + 1.331 + if (start) { 1.332 + // Now start checks 1.333 + res = ice_ctx_->StartChecks(); 1.334 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.335 + } 1.336 + } 1.337 + 1.338 + void Connect(IceTestPeer *remote, TrickleMode trickle_mode, 1.339 + bool start = true) { 1.340 + test_utils->sts_target()->Dispatch( 1.341 + WrapRunnable( 1.342 + this, &IceTestPeer::Connect_s, remote, trickle_mode, start), 1.343 + NS_DISPATCH_SYNC); 1.344 + } 1.345 + 1.346 + void SimulateTrickle(size_t stream) { 1.347 + std::cerr << "Doing trickle for stream " << stream << std::endl; 1.348 + // If we are in trickle deferred mode, now trickle in the candidates 1.349 + // for |stream} 1.350 + nsresult res; 1.351 + 1.352 + ASSERT_GT(remote_->streams_.size(), stream); 1.353 + 1.354 + std::vector<std::string> candidates = 1.355 + remote_->GetCandidates(stream); 1.356 + 1.357 + for (size_t j=0; j<candidates.size(); j++) { 1.358 + test_utils->sts_target()->Dispatch( 1.359 + WrapRunnableRet(streams_[stream], 1.360 + &NrIceMediaStream::ParseTrickleCandidate, 1.361 + candidates[j], 1.362 + &res), NS_DISPATCH_SYNC); 1.363 + 1.364 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.365 + } 1.366 + } 1.367 + 1.368 + void DumpCandidate(std::string which, const NrIceCandidate& cand) { 1.369 + std::string type; 1.370 + 1.371 + switch(cand.type) { 1.372 + case NrIceCandidate::ICE_HOST: 1.373 + type = "host"; 1.374 + break; 1.375 + case NrIceCandidate::ICE_SERVER_REFLEXIVE: 1.376 + type = "srflx"; 1.377 + break; 1.378 + case NrIceCandidate::ICE_PEER_REFLEXIVE: 1.379 + type = "prflx"; 1.380 + break; 1.381 + case NrIceCandidate::ICE_RELAYED: 1.382 + type = "relay"; 1.383 + if (which.find("Local") != std::string::npos) { 1.384 + type += "(" + cand.local_addr.transport + ")"; 1.385 + } 1.386 + break; 1.387 + default: 1.388 + FAIL(); 1.389 + }; 1.390 + 1.391 + std::cerr << which 1.392 + << " --> " 1.393 + << type 1.394 + << " " 1.395 + << cand.local_addr.host 1.396 + << ":" 1.397 + << cand.local_addr.port 1.398 + << " codeword=" 1.399 + << cand.codeword 1.400 + << std::endl; 1.401 + } 1.402 + 1.403 + void DumpAndCheckActiveCandidates_s() { 1.404 + std::cerr << "Active candidates:" << std::endl; 1.405 + for (size_t i=0; i < streams_.size(); ++i) { 1.406 + for (int j=0; j < streams_[i]->components(); ++j) { 1.407 + std::cerr << "Stream " << i << " component " << j+1 << std::endl; 1.408 + 1.409 + NrIceCandidate *local; 1.410 + NrIceCandidate *remote; 1.411 + 1.412 + nsresult res = streams_[i]->GetActivePair(j+1, &local, &remote); 1.413 + if (res == NS_ERROR_NOT_AVAILABLE) { 1.414 + std::cerr << "Component unpaired or disabled." << std::endl; 1.415 + } else { 1.416 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.417 + DumpCandidate("Local ", *local); 1.418 + ASSERT_EQ(expected_local_type_, local->type); 1.419 + ASSERT_EQ(expected_local_transport_, local->local_addr.transport); 1.420 + DumpCandidate("Remote ", *remote); 1.421 + ASSERT_EQ(expected_remote_type_, remote->type); 1.422 + delete local; 1.423 + delete remote; 1.424 + } 1.425 + } 1.426 + } 1.427 + } 1.428 + 1.429 + void DumpAndCheckActiveCandidates() { 1.430 + test_utils->sts_target()->Dispatch( 1.431 + WrapRunnable(this, &IceTestPeer::DumpAndCheckActiveCandidates_s), 1.432 + NS_DISPATCH_SYNC); 1.433 + } 1.434 + 1.435 + void Close() { 1.436 + test_utils->sts_target()->Dispatch( 1.437 + WrapRunnable(ice_ctx_, &NrIceCtx::destroy_peer_ctx), 1.438 + NS_DISPATCH_SYNC); 1.439 + } 1.440 + 1.441 + void Shutdown() { 1.442 + ice_ctx_ = nullptr; 1.443 + } 1.444 + 1.445 + void StartChecks() { 1.446 + nsresult res; 1.447 + 1.448 + // Now start checks 1.449 + test_utils->sts_target()->Dispatch( 1.450 + WrapRunnableRet(ice_ctx_, &NrIceCtx::StartChecks, &res), 1.451 + NS_DISPATCH_SYNC); 1.452 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.453 + } 1.454 + 1.455 + // Handle events 1.456 + void GatheringStateChange(NrIceCtx* ctx, 1.457 + NrIceCtx::GatheringState state) { 1.458 + (void)ctx; 1.459 + if (state != NrIceCtx::ICE_CTX_GATHER_COMPLETE) { 1.460 + return; 1.461 + } 1.462 + 1.463 + std::cerr << "Gathering complete for " << name_ << std::endl; 1.464 + gathering_complete_ = true; 1.465 + 1.466 + std::cerr << "CANDIDATES:" << std::endl; 1.467 + for (size_t i=0; i<streams_.size(); ++i) { 1.468 + std::cerr << "Stream " << name_ << std::endl; 1.469 + std::vector<std::string> candidates = 1.470 + streams_[i]->GetCandidates(); 1.471 + 1.472 + for(size_t j=0; j<candidates.size(); ++j) { 1.473 + std::cerr << candidates[j] << std::endl; 1.474 + } 1.475 + } 1.476 + std::cerr << std::endl; 1.477 + 1.478 + } 1.479 + 1.480 + void CandidateInitialized(NrIceMediaStream *stream, const std::string &candidate) { 1.481 + std::cerr << "Candidate initialized: " << candidate << std::endl; 1.482 + candidates_[stream->name()].push_back(candidate); 1.483 + 1.484 + // If we are connected, then try to trickle to the 1.485 + // other side. 1.486 + if (remote_ && remote_->remote_) { 1.487 + std::vector<mozilla::RefPtr<NrIceMediaStream> >::iterator it = 1.488 + std::find(streams_.begin(), streams_.end(), stream); 1.489 + ASSERT_NE(streams_.end(), it); 1.490 + size_t index = it - streams_.begin(); 1.491 + 1.492 + ASSERT_GT(remote_->streams_.size(), index); 1.493 + nsresult res = remote_->streams_[index]->ParseTrickleCandidate( 1.494 + candidate); 1.495 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.496 + ++trickled_; 1.497 + } 1.498 + } 1.499 + 1.500 + nsresult GetCandidatePairs(size_t stream_index, 1.501 + std::vector<NrIceCandidatePair>* pairs) { 1.502 + MOZ_ASSERT(pairs); 1.503 + if (stream_index >= streams_.size()) { 1.504 + // Is there a better error for "no such index"? 1.505 + ADD_FAILURE() << "No such media stream index: " << stream_index; 1.506 + return NS_ERROR_INVALID_ARG; 1.507 + } 1.508 + 1.509 + nsresult res; 1.510 + test_utils->sts_target()->Dispatch( 1.511 + WrapRunnableRet(streams_[stream_index], 1.512 + &NrIceMediaStream::GetCandidatePairs, 1.513 + pairs, 1.514 + &res), 1.515 + NS_DISPATCH_SYNC); 1.516 + return res; 1.517 + } 1.518 + 1.519 + void DumpCandidatePair(const NrIceCandidatePair& pair) { 1.520 + std::cerr << std::endl; 1.521 + DumpCandidate("Local", pair.local); 1.522 + DumpCandidate("Remote", pair.remote); 1.523 + std::cerr << "state = " << pair.state 1.524 + << " priority = " << pair.priority 1.525 + << " nominated = " << pair.nominated 1.526 + << " selected = " << pair.selected 1.527 + << " codeword = " << pair.codeword << std::endl; 1.528 + } 1.529 + 1.530 + void DumpCandidatePairs(NrIceMediaStream *stream) { 1.531 + std::vector<NrIceCandidatePair> pairs; 1.532 + nsresult res = stream->GetCandidatePairs(&pairs); 1.533 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.534 + 1.535 + std::cerr << "Begin list of candidate pairs [" << std::endl; 1.536 + 1.537 + for (std::vector<NrIceCandidatePair>::iterator p = pairs.begin(); 1.538 + p != pairs.end(); ++p) { 1.539 + DumpCandidatePair(*p); 1.540 + } 1.541 + std::cerr << "]" << std::endl; 1.542 + } 1.543 + 1.544 + void DumpCandidatePairs() { 1.545 + std::cerr << "Dumping candidate pairs for all streams [" << std::endl; 1.546 + for (size_t s = 0; s < streams_.size(); ++s) { 1.547 + DumpCandidatePairs(streams_[s]); 1.548 + } 1.549 + std::cerr << "]" << std::endl; 1.550 + } 1.551 + 1.552 + bool CandidatePairsPriorityDescending(const std::vector<NrIceCandidatePair>& 1.553 + pairs) { 1.554 + // Verify that priority is descending 1.555 + uint64_t priority = std::numeric_limits<uint64_t>::max(); 1.556 + 1.557 + for (size_t p = 0; p < pairs.size(); ++p) { 1.558 + if (priority < pairs[p].priority) { 1.559 + std::cerr << "Priority increased in subsequent pairs:" << std::endl; 1.560 + DumpCandidatePair(pairs[p-1]); 1.561 + DumpCandidatePair(pairs[p]); 1.562 + return false; 1.563 + } else if (priority == pairs[p].priority) { 1.564 + std::cerr << "Duplicate priority in subseqent pairs:" << std::endl; 1.565 + DumpCandidatePair(pairs[p-1]); 1.566 + DumpCandidatePair(pairs[p]); 1.567 + return false; 1.568 + } 1.569 + priority = pairs[p].priority; 1.570 + } 1.571 + return true; 1.572 + } 1.573 + 1.574 + void UpdateAndValidateCandidatePairs(size_t stream_index, 1.575 + std::vector<NrIceCandidatePair>* 1.576 + new_pairs) { 1.577 + std::vector<NrIceCandidatePair> old_pairs = *new_pairs; 1.578 + GetCandidatePairs(stream_index, new_pairs); 1.579 + ASSERT_TRUE(CandidatePairsPriorityDescending(*new_pairs)) << "New list of " 1.580 + "candidate pairs is either not sorted in priority order, or has " 1.581 + "duplicate priorities."; 1.582 + ASSERT_TRUE(CandidatePairsPriorityDescending(old_pairs)) << "Old list of " 1.583 + "candidate pairs is either not sorted in priority order, or has " 1.584 + "duplicate priorities. This indicates some bug in the test case."; 1.585 + std::vector<NrIceCandidatePair> added_pairs; 1.586 + std::vector<NrIceCandidatePair> removed_pairs; 1.587 + 1.588 + // set_difference computes the set of elements that are present in the 1.589 + // first set, but not the second 1.590 + // NrIceCandidatePair::operator< compares based on the priority, local 1.591 + // candidate, and remote candidate in that order. This means this will 1.592 + // catch cases where the priority has remained the same, but one of the 1.593 + // candidates has changed. 1.594 + std::set_difference((*new_pairs).begin(), 1.595 + (*new_pairs).end(), 1.596 + old_pairs.begin(), 1.597 + old_pairs.end(), 1.598 + std::inserter(added_pairs, added_pairs.begin()), 1.599 + IceCandidatePairCompare()); 1.600 + 1.601 + std::set_difference(old_pairs.begin(), 1.602 + old_pairs.end(), 1.603 + (*new_pairs).begin(), 1.604 + (*new_pairs).end(), 1.605 + std::inserter(removed_pairs, removed_pairs.begin()), 1.606 + IceCandidatePairCompare()); 1.607 + 1.608 + for (std::vector<NrIceCandidatePair>::iterator a = added_pairs.begin(); 1.609 + a != added_pairs.end(); ++a) { 1.610 + std::cerr << "Found new candidate pair." << std::endl; 1.611 + DumpCandidatePair(*a); 1.612 + } 1.613 + 1.614 + for (std::vector<NrIceCandidatePair>::iterator r = removed_pairs.begin(); 1.615 + r != removed_pairs.end(); ++r) { 1.616 + std::cerr << "Pre-existing candidate pair is now missing:" << std::endl; 1.617 + DumpCandidatePair(*r); 1.618 + } 1.619 + 1.620 + ASSERT_TRUE(removed_pairs.empty()) << "At least one candidate pair has " 1.621 + "gone missing."; 1.622 + } 1.623 + 1.624 + void StreamReady(NrIceMediaStream *stream) { 1.625 + ++ready_ct_; 1.626 + std::cerr << "Stream ready " << stream->name() << " ct=" << ready_ct_ << std::endl; 1.627 + DumpCandidatePairs(stream); 1.628 + } 1.629 + void StreamFailed(NrIceMediaStream *stream) { 1.630 + std::cerr << "Stream failed " << stream->name() << " ct=" << ready_ct_ << std::endl; 1.631 + DumpCandidatePairs(stream); 1.632 + } 1.633 + 1.634 + void ConnectionStateChange(NrIceCtx* ctx, 1.635 + NrIceCtx::ConnectionState state) { 1.636 + (void)ctx; 1.637 + if (state != NrIceCtx::ICE_CTX_OPEN) { 1.638 + return; 1.639 + } 1.640 + std::cerr << "ICE completed " << name_ << std::endl; 1.641 + ice_complete_ = true; 1.642 + } 1.643 + 1.644 + void PacketReceived(NrIceMediaStream *stream, int component, const unsigned char *data, 1.645 + int len) { 1.646 + std::cerr << "Received " << len << " bytes" << std::endl; 1.647 + ++received_; 1.648 + } 1.649 + 1.650 + void SendPacket(int stream, int component, const unsigned char *data, 1.651 + int len) { 1.652 + ASSERT_TRUE(NS_SUCCEEDED(streams_[stream]->SendPacket(component, data, len))); 1.653 + 1.654 + ++sent_; 1.655 + std::cerr << "Sent " << len << " bytes" << std::endl; 1.656 + } 1.657 + 1.658 + void SetCandidateFilter(CandidateFilter filter) { 1.659 + candidate_filter_ = filter; 1.660 + } 1.661 + 1.662 + // Allow us to parse candidates directly on the current thread. 1.663 + void ParseCandidate(size_t i, const std::string& candidate) { 1.664 + std::vector<std::string> attributes; 1.665 + 1.666 + attributes.push_back(candidate); 1.667 + streams_[i]->ParseAttributes(attributes); 1.668 + } 1.669 + 1.670 + void DisableComponent(size_t stream, int component_id) { 1.671 + ASSERT_LT(stream, streams_.size()); 1.672 + nsresult res = streams_[stream]->DisableComponent(component_id); 1.673 + ASSERT_TRUE(NS_SUCCEEDED(res)); 1.674 + } 1.675 + 1.676 + int trickled() { return trickled_; } 1.677 + 1.678 + private: 1.679 + std::string name_; 1.680 + nsRefPtr<NrIceCtx> ice_ctx_; 1.681 + std::vector<mozilla::RefPtr<NrIceMediaStream> > streams_; 1.682 + std::map<std::string, std::vector<std::string> > candidates_; 1.683 + bool gathering_complete_; 1.684 + int ready_ct_; 1.685 + bool ice_complete_; 1.686 + size_t received_; 1.687 + size_t sent_; 1.688 + NrIceResolverFake fake_resolver_; 1.689 + nsRefPtr<NrIceResolver> dns_resolver_; 1.690 + IceTestPeer *remote_; 1.691 + CandidateFilter candidate_filter_; 1.692 + NrIceCandidate::Type expected_local_type_; 1.693 + std::string expected_local_transport_; 1.694 + NrIceCandidate::Type expected_remote_type_; 1.695 + TrickleMode trickle_mode_; 1.696 + int trickled_; 1.697 +}; 1.698 + 1.699 +class IceGatherTest : public ::testing::Test { 1.700 + public: 1.701 + void SetUp() { 1.702 + test_utils->sts_target()->Dispatch(WrapRunnable(TestStunServer::GetInstance(), 1.703 + &TestStunServer::Reset), 1.704 + NS_DISPATCH_SYNC); 1.705 + peer_ = new IceTestPeer("P1", true, false); 1.706 + peer_->AddStream(1); 1.707 + } 1.708 + 1.709 + void Gather(bool wait = true) { 1.710 + peer_->Gather(); 1.711 + 1.712 + if (wait) { 1.713 + WaitForGather(); 1.714 + } 1.715 + } 1.716 + 1.717 + void WaitForGather() { 1.718 + ASSERT_TRUE_WAIT(peer_->gathering_complete(), kDefaultTimeout); 1.719 + } 1.720 + 1.721 + void UseFakeStunServerWithResponse(const std::string& fake_addr, 1.722 + uint16_t fake_port) { 1.723 + TestStunServer::GetInstance()->SetResponseAddr(fake_addr, fake_port); 1.724 + // Sets an additional stun server 1.725 + peer_->SetStunServer(TestStunServer::GetInstance()->addr(), 1.726 + TestStunServer::GetInstance()->port()); 1.727 + } 1.728 + 1.729 + // NB: Only does substring matching, watch out for stuff like "1.2.3.4" 1.730 + // matching "21.2.3.47". " 1.2.3.4 " should not have false positives. 1.731 + bool StreamHasMatchingCandidate(unsigned int stream, 1.732 + const std::string& match) { 1.733 + std::vector<std::string> candidates = peer_->GetCandidates(stream); 1.734 + for (size_t c = 0; c < candidates.size(); ++c) { 1.735 + if (std::string::npos != candidates[c].find(match)) { 1.736 + return true; 1.737 + } 1.738 + } 1.739 + return false; 1.740 + } 1.741 + 1.742 + protected: 1.743 + mozilla::ScopedDeletePtr<IceTestPeer> peer_; 1.744 +}; 1.745 + 1.746 +class IceConnectTest : public ::testing::Test { 1.747 + public: 1.748 + IceConnectTest() : initted_(false) {} 1.749 + 1.750 + void SetUp() { 1.751 + nsresult rv; 1.752 + target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 1.753 + ASSERT_TRUE(NS_SUCCEEDED(rv)); 1.754 + } 1.755 + 1.756 + void AddStream(const std::string& name, int components) { 1.757 + Init(false); 1.758 + p1_->AddStream(components); 1.759 + p2_->AddStream(components); 1.760 + } 1.761 + 1.762 + void Init(bool set_priorities) { 1.763 + if (!initted_) { 1.764 + p1_ = new IceTestPeer("P1", true, set_priorities); 1.765 + p2_ = new IceTestPeer("P2", false, set_priorities); 1.766 + } 1.767 + initted_ = true; 1.768 + } 1.769 + 1.770 + bool Gather(bool wait) { 1.771 + Init(false); 1.772 + p1_->SetStunServer(g_stun_server_address, kDefaultStunServerPort); 1.773 + p2_->SetStunServer(g_stun_server_address, kDefaultStunServerPort); 1.774 + p1_->Gather(); 1.775 + p2_->Gather(); 1.776 + 1.777 + if (wait) { 1.778 + EXPECT_TRUE_WAIT(p1_->gathering_complete(), kDefaultTimeout); 1.779 + if (!p1_->gathering_complete()) 1.780 + return false; 1.781 + EXPECT_TRUE_WAIT(p2_->gathering_complete(), kDefaultTimeout); 1.782 + if (!p2_->gathering_complete()) 1.783 + return false; 1.784 + } 1.785 + return true; 1.786 + } 1.787 + 1.788 + void SetTurnServer(const std::string addr, uint16_t port, 1.789 + const std::string username, 1.790 + const std::string password, 1.791 + const char* transport = kNrIceTransportUdp) { 1.792 + p1_->SetTurnServer(addr, port, username, password, transport); 1.793 + p2_->SetTurnServer(addr, port, username, password, transport); 1.794 + } 1.795 + 1.796 + void SetTurnServers(const std::vector<NrIceTurnServer>& servers) { 1.797 + p1_->SetTurnServers(servers); 1.798 + p2_->SetTurnServers(servers); 1.799 + } 1.800 + 1.801 + void SetCandidateFilter(CandidateFilter filter, bool both=true) { 1.802 + p1_->SetCandidateFilter(filter); 1.803 + if (both) { 1.804 + p2_->SetCandidateFilter(filter); 1.805 + } 1.806 + } 1.807 + 1.808 + void Connect() { 1.809 + p1_->Connect(p2_, TRICKLE_NONE); 1.810 + p2_->Connect(p1_, TRICKLE_NONE); 1.811 + 1.812 + ASSERT_TRUE_WAIT(p1_->ready_ct() == 1 && p2_->ready_ct() == 1, 1.813 + kDefaultTimeout); 1.814 + ASSERT_TRUE_WAIT(p1_->ice_complete() && p2_->ice_complete(), 1.815 + kDefaultTimeout); 1.816 + 1.817 + p1_->DumpAndCheckActiveCandidates(); 1.818 + p2_->DumpAndCheckActiveCandidates(); 1.819 + } 1.820 + 1.821 + void SetExpectedTypes(NrIceCandidate::Type local, NrIceCandidate::Type remote, 1.822 + std::string transport = kNrIceTransportUdp) { 1.823 + p1_->SetExpectedTypes(local, remote, transport); 1.824 + p2_->SetExpectedTypes(local, remote, transport); 1.825 + } 1.826 + 1.827 + void SetExpectedTypes(NrIceCandidate::Type local1, NrIceCandidate::Type remote1, 1.828 + NrIceCandidate::Type local2, NrIceCandidate::Type remote2) { 1.829 + p1_->SetExpectedTypes(local1, remote1); 1.830 + p2_->SetExpectedTypes(local2, remote2); 1.831 + } 1.832 + 1.833 + void ConnectP1(TrickleMode mode = TRICKLE_NONE) { 1.834 + p1_->Connect(p2_, mode); 1.835 + } 1.836 + 1.837 + void ConnectP2(TrickleMode mode = TRICKLE_NONE) { 1.838 + p2_->Connect(p1_, mode); 1.839 + } 1.840 + 1.841 + void WaitForComplete(int expected_streams = 1) { 1.842 + ASSERT_TRUE_WAIT(p1_->ready_ct() == expected_streams && 1.843 + p2_->ready_ct() == expected_streams, kDefaultTimeout); 1.844 + ASSERT_TRUE_WAIT(p1_->ice_complete() && p2_->ice_complete(), 1.845 + kDefaultTimeout); 1.846 + } 1.847 + 1.848 + void WaitForGather() { 1.849 + ASSERT_TRUE_WAIT(p1_->gathering_complete(), kDefaultTimeout); 1.850 + ASSERT_TRUE_WAIT(p2_->gathering_complete(), kDefaultTimeout); 1.851 + } 1.852 + 1.853 + void ConnectTrickle(TrickleMode trickle = TRICKLE_SIMULATE) { 1.854 + p1_->Connect(p2_, trickle); 1.855 + p2_->Connect(p1_, trickle); 1.856 + } 1.857 + 1.858 + void SimulateTrickle(size_t stream) { 1.859 + p1_->SimulateTrickle(stream); 1.860 + p2_->SimulateTrickle(stream); 1.861 + ASSERT_TRUE_WAIT(p1_->is_ready(stream), kDefaultTimeout); 1.862 + ASSERT_TRUE_WAIT(p2_->is_ready(stream), kDefaultTimeout); 1.863 + } 1.864 + 1.865 + void SimulateTrickleP1(size_t stream) { 1.866 + p1_->SimulateTrickle(stream); 1.867 + } 1.868 + 1.869 + void SimulateTrickleP2(size_t stream) { 1.870 + p2_->SimulateTrickle(stream); 1.871 + } 1.872 + 1.873 + void VerifyConnected() { 1.874 + } 1.875 + 1.876 + void CloseP1() { 1.877 + p1_->Close(); 1.878 + } 1.879 + 1.880 + void ConnectThenDelete() { 1.881 + p1_->Connect(p2_, TRICKLE_NONE, true); 1.882 + p2_->Connect(p1_, TRICKLE_NONE, false); 1.883 + test_utils->sts_target()->Dispatch(WrapRunnable(this, 1.884 + &IceConnectTest::CloseP1), 1.885 + NS_DISPATCH_SYNC); 1.886 + p2_->StartChecks(); 1.887 + 1.888 + // Wait to see if we crash 1.889 + PR_Sleep(PR_MillisecondsToInterval(kDefaultTimeout)); 1.890 + } 1.891 + 1.892 + void SendReceive() { 1.893 + // p1_->Send(2); 1.894 + test_utils->sts_target()->Dispatch( 1.895 + WrapRunnable(p1_.get(), 1.896 + &IceTestPeer::SendPacket, 0, 1, 1.897 + reinterpret_cast<const unsigned char *>("TEST"), 4), 1.898 + NS_DISPATCH_SYNC); 1.899 + ASSERT_EQ(1u, p1_->sent()); 1.900 + ASSERT_TRUE_WAIT(p2_->received() == 1, 1000); 1.901 + } 1.902 + 1.903 + protected: 1.904 + bool initted_; 1.905 + nsCOMPtr<nsIEventTarget> target_; 1.906 + mozilla::ScopedDeletePtr<IceTestPeer> p1_; 1.907 + mozilla::ScopedDeletePtr<IceTestPeer> p2_; 1.908 +}; 1.909 + 1.910 +class PrioritizerTest : public ::testing::Test { 1.911 + public: 1.912 + PrioritizerTest(): 1.913 + prioritizer_(nullptr) {} 1.914 + 1.915 + ~PrioritizerTest() { 1.916 + if (prioritizer_) { 1.917 + nr_interface_prioritizer_destroy(&prioritizer_); 1.918 + } 1.919 + } 1.920 + 1.921 + void SetPriorizer(nr_interface_prioritizer *prioritizer) { 1.922 + prioritizer_ = prioritizer; 1.923 + } 1.924 + 1.925 + void AddInterface(const std::string& num, int type, int estimated_speed) { 1.926 + std::string str_addr = "10.0.0." + num; 1.927 + std::string ifname = "eth" + num; 1.928 + nr_local_addr local_addr; 1.929 + local_addr.interface.type = type; 1.930 + local_addr.interface.estimated_speed = estimated_speed; 1.931 + 1.932 + int r = nr_ip4_str_port_to_transport_addr(str_addr.c_str(), 0, 1.933 + IPPROTO_UDP, &(local_addr.addr)); 1.934 + ASSERT_EQ(0, r); 1.935 + strncpy(local_addr.addr.ifname, ifname.c_str(), MAXIFNAME); 1.936 + 1.937 + r = nr_interface_prioritizer_add_interface(prioritizer_, &local_addr); 1.938 + ASSERT_EQ(0, r); 1.939 + r = nr_interface_prioritizer_sort_preference(prioritizer_); 1.940 + ASSERT_EQ(0, r); 1.941 + } 1.942 + 1.943 + void HasLowerPreference(const std::string& num1, const std::string& num2) { 1.944 + std::string key1 = "eth" + num1 + ":10.0.0." + num1; 1.945 + std::string key2 = "eth" + num2 + ":10.0.0." + num2; 1.946 + UCHAR pref1, pref2; 1.947 + int r = nr_interface_prioritizer_get_priority(prioritizer_, key1.c_str(), &pref1); 1.948 + ASSERT_EQ(0, r); 1.949 + r = nr_interface_prioritizer_get_priority(prioritizer_, key2.c_str(), &pref2); 1.950 + ASSERT_EQ(0, r); 1.951 + ASSERT_LE(pref1, pref2); 1.952 + } 1.953 + 1.954 + private: 1.955 + nr_interface_prioritizer *prioritizer_; 1.956 +}; 1.957 + 1.958 +class PacketFilterTest : public ::testing::Test { 1.959 + public: 1.960 + PacketFilterTest(): filter_(nullptr) {} 1.961 + 1.962 + void SetUp() { 1.963 + nsCOMPtr<nsIUDPSocketFilterHandler> handler = 1.964 + do_GetService(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID); 1.965 + handler->NewFilter(getter_AddRefs(filter_)); 1.966 + } 1.967 + 1.968 + void TestIncoming(const uint8_t* data, uint32_t len, 1.969 + uint8_t from_addr, int from_port, 1.970 + bool expected_result) { 1.971 + mozilla::net::NetAddr addr; 1.972 + MakeNetAddr(&addr, from_addr, from_port); 1.973 + bool result; 1.974 + nsresult rv = filter_->FilterPacket(&addr, data, len, 1.975 + nsIUDPSocketFilter::SF_INCOMING, 1.976 + &result); 1.977 + ASSERT_EQ(NS_OK, rv); 1.978 + ASSERT_EQ(expected_result, result); 1.979 + } 1.980 + 1.981 + void TestOutgoing(const uint8_t* data, uint32_t len, 1.982 + uint8_t to_addr, int to_port, 1.983 + bool expected_result) { 1.984 + mozilla::net::NetAddr addr; 1.985 + MakeNetAddr(&addr, to_addr, to_port); 1.986 + bool result; 1.987 + nsresult rv = filter_->FilterPacket(&addr, data, len, 1.988 + nsIUDPSocketFilter::SF_OUTGOING, 1.989 + &result); 1.990 + ASSERT_EQ(NS_OK, rv); 1.991 + ASSERT_EQ(expected_result, result); 1.992 + } 1.993 + 1.994 + private: 1.995 + void MakeNetAddr(mozilla::net::NetAddr* net_addr, 1.996 + uint8_t last_digit, uint16_t port) { 1.997 + net_addr->inet.family = AF_INET; 1.998 + net_addr->inet.ip = 192 << 24 | 168 << 16 | 1 << 8 | last_digit; 1.999 + net_addr->inet.port = port; 1.1000 + } 1.1001 + 1.1002 + nsCOMPtr<nsIUDPSocketFilter> filter_; 1.1003 +}; 1.1004 +} // end namespace 1.1005 + 1.1006 +TEST_F(IceGatherTest, TestGatherFakeStunServerHostnameNoResolver) { 1.1007 + peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort); 1.1008 + Gather(); 1.1009 +} 1.1010 + 1.1011 +TEST_F(IceGatherTest, TestGatherFakeStunServerIpAddress) { 1.1012 + peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort); 1.1013 + peer_->SetFakeResolver(); 1.1014 + Gather(); 1.1015 +} 1.1016 + 1.1017 +TEST_F(IceGatherTest, TestGatherFakeStunServerHostname) { 1.1018 + peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort); 1.1019 + peer_->SetFakeResolver(); 1.1020 + Gather(); 1.1021 +} 1.1022 + 1.1023 +TEST_F(IceGatherTest, TestGatherFakeStunBogusHostname) { 1.1024 + peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort); 1.1025 + peer_->SetFakeResolver(); 1.1026 + Gather(); 1.1027 +} 1.1028 + 1.1029 +TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddress) { 1.1030 + peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort); 1.1031 + peer_->SetDNSResolver(); 1.1032 + Gather(); 1.1033 + // TODO(jib@mozilla.com): ensure we get server reflexive candidates Bug 848094 1.1034 +} 1.1035 + 1.1036 +TEST_F(IceGatherTest, TestGatherDNSStunServerHostname) { 1.1037 + peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort); 1.1038 + peer_->SetDNSResolver(); 1.1039 + Gather(); 1.1040 +} 1.1041 + 1.1042 +TEST_F(IceGatherTest, TestGatherDNSStunBogusHostname) { 1.1043 + peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort); 1.1044 + peer_->SetDNSResolver(); 1.1045 + Gather(); 1.1046 +} 1.1047 + 1.1048 +TEST_F(IceGatherTest, TestGatherTurn) { 1.1049 + if (g_turn_server.empty()) 1.1050 + return; 1.1051 + peer_->SetTurnServer(g_turn_server, kDefaultStunServerPort, 1.1052 + g_turn_user, g_turn_password, kNrIceTransportUdp); 1.1053 + Gather(); 1.1054 +} 1.1055 + 1.1056 +TEST_F(IceGatherTest, TestGatherTurnTcp) { 1.1057 + if (g_turn_server.empty()) 1.1058 + return; 1.1059 + peer_->SetTurnServer(g_turn_server, kDefaultStunServerPort, 1.1060 + g_turn_user, g_turn_password, kNrIceTransportTcp); 1.1061 + Gather(); 1.1062 +} 1.1063 + 1.1064 +TEST_F(IceGatherTest, TestGatherDisableComponent) { 1.1065 + peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort); 1.1066 + peer_->AddStream(2); 1.1067 + peer_->DisableComponent(1, 2); 1.1068 + Gather(); 1.1069 + std::vector<std::string> candidates = 1.1070 + peer_->GetCandidates(1); 1.1071 + 1.1072 + for (size_t i=0; i<candidates.size(); ++i) { 1.1073 + size_t sp1 = candidates[i].find(' '); 1.1074 + ASSERT_EQ(0, candidates[i].compare(sp1+1, 1, "1", 1)); 1.1075 + } 1.1076 +} 1.1077 + 1.1078 + 1.1079 +// Verify that a bogus candidate doesn't cause crashes on the 1.1080 +// main thread. See bug 856433. 1.1081 +TEST_F(IceGatherTest, TestBogusCandidate) { 1.1082 + Gather(); 1.1083 + peer_->ParseCandidate(0, kBogusIceCandidate); 1.1084 +} 1.1085 + 1.1086 +TEST_F(IceGatherTest, VerifyTestStunServer) { 1.1087 + UseFakeStunServerWithResponse("192.0.2.133", 3333); 1.1088 + Gather(); 1.1089 + ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.133 3333 ")); 1.1090 +} 1.1091 + 1.1092 +TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddr) { 1.1093 + UseFakeStunServerWithResponse("0.0.0.0", 3333); 1.1094 + Gather(); 1.1095 + ASSERT_FALSE(StreamHasMatchingCandidate(0, " 0.0.0.0 ")); 1.1096 +} 1.1097 + 1.1098 +TEST_F(IceGatherTest, TestStunServerReturnsPort0) { 1.1099 + UseFakeStunServerWithResponse("192.0.2.133", 0); 1.1100 + Gather(); 1.1101 + ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.2.133 0 ")); 1.1102 +} 1.1103 + 1.1104 +TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddr) { 1.1105 + UseFakeStunServerWithResponse("127.0.0.133", 3333); 1.1106 + Gather(); 1.1107 + ASSERT_FALSE(StreamHasMatchingCandidate(0, " 127.0.0.133 ")); 1.1108 +} 1.1109 + 1.1110 +TEST_F(IceGatherTest, TestStunServerTrickle) { 1.1111 + UseFakeStunServerWithResponse("192.0.2.1", 3333); 1.1112 + TestStunServer::GetInstance()->SetActive(false); 1.1113 + Gather(false); 1.1114 + ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1")); 1.1115 + TestStunServer::GetInstance()->SetActive(true); 1.1116 + WaitForGather(); 1.1117 + ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1")); 1.1118 +} 1.1119 + 1.1120 +TEST_F(IceConnectTest, TestGather) { 1.1121 + AddStream("first", 1); 1.1122 + ASSERT_TRUE(Gather(true)); 1.1123 +} 1.1124 + 1.1125 +TEST_F(IceConnectTest, TestGatherAutoPrioritize) { 1.1126 + Init(false); 1.1127 + AddStream("first", 1); 1.1128 + ASSERT_TRUE(Gather(true)); 1.1129 +} 1.1130 + 1.1131 + 1.1132 +TEST_F(IceConnectTest, TestConnect) { 1.1133 + AddStream("first", 1); 1.1134 + ASSERT_TRUE(Gather(true)); 1.1135 + Connect(); 1.1136 +} 1.1137 + 1.1138 +TEST_F(IceConnectTest, TestConnectTwoComponents) { 1.1139 + AddStream("first", 2); 1.1140 + ASSERT_TRUE(Gather(true)); 1.1141 + Connect(); 1.1142 +} 1.1143 + 1.1144 +TEST_F(IceConnectTest, TestConnectTwoComponentsDisableSecond) { 1.1145 + AddStream("first", 2); 1.1146 + ASSERT_TRUE(Gather(true)); 1.1147 + p1_->DisableComponent(0, 2); 1.1148 + p2_->DisableComponent(0, 2); 1.1149 + Connect(); 1.1150 +} 1.1151 + 1.1152 + 1.1153 +TEST_F(IceConnectTest, TestConnectP2ThenP1) { 1.1154 + AddStream("first", 1); 1.1155 + ASSERT_TRUE(Gather(true)); 1.1156 + ConnectP2(); 1.1157 + PR_Sleep(1000); 1.1158 + ConnectP1(); 1.1159 + WaitForComplete(); 1.1160 +} 1.1161 + 1.1162 +TEST_F(IceConnectTest, TestConnectP2ThenP1Trickle) { 1.1163 + AddStream("first", 1); 1.1164 + ASSERT_TRUE(Gather(true)); 1.1165 + ConnectP2(); 1.1166 + PR_Sleep(1000); 1.1167 + ConnectP1(TRICKLE_SIMULATE); 1.1168 + SimulateTrickleP1(0); 1.1169 + WaitForComplete(); 1.1170 +} 1.1171 + 1.1172 +TEST_F(IceConnectTest, TestConnectP2ThenP1TrickleTwoComponents) { 1.1173 + AddStream("first", 1); 1.1174 + AddStream("second", 2); 1.1175 + ASSERT_TRUE(Gather(true)); 1.1176 + ConnectP2(); 1.1177 + PR_Sleep(1000); 1.1178 + ConnectP1(TRICKLE_SIMULATE); 1.1179 + SimulateTrickleP1(0); 1.1180 + std::cerr << "Sleeping between trickle streams" << std::endl; 1.1181 + PR_Sleep(1000); // Give this some time to settle but not complete 1.1182 + // all of ICE. 1.1183 + SimulateTrickleP1(1); 1.1184 + WaitForComplete(2); 1.1185 +} 1.1186 + 1.1187 +TEST_F(IceConnectTest, TestConnectAutoPrioritize) { 1.1188 + Init(false); 1.1189 + AddStream("first", 1); 1.1190 + ASSERT_TRUE(Gather(true)); 1.1191 + Connect(); 1.1192 +} 1.1193 + 1.1194 +TEST_F(IceConnectTest, TestConnectTrickleOneStreamOneComponent) { 1.1195 + AddStream("first", 1); 1.1196 + ASSERT_TRUE(Gather(true)); 1.1197 + ConnectTrickle(); 1.1198 + SimulateTrickle(0); 1.1199 + ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000); 1.1200 + ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000); 1.1201 +} 1.1202 + 1.1203 +TEST_F(IceConnectTest, TestConnectTrickleTwoStreamsOneComponent) { 1.1204 + AddStream("first", 1); 1.1205 + AddStream("second", 1); 1.1206 + ASSERT_TRUE(Gather(true)); 1.1207 + ConnectTrickle(); 1.1208 + SimulateTrickle(0); 1.1209 + SimulateTrickle(1); 1.1210 + ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000); 1.1211 + ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000); 1.1212 +} 1.1213 + 1.1214 +TEST_F(IceConnectTest, TestConnectRealTrickleOneStreamOneComponent) { 1.1215 + AddStream("first", 1); 1.1216 + AddStream("second", 1); 1.1217 + ASSERT_TRUE(Gather(false)); 1.1218 + ConnectTrickle(TRICKLE_REAL); 1.1219 + ASSERT_TRUE_WAIT(p1_->ice_complete(), kDefaultTimeout); 1.1220 + ASSERT_TRUE_WAIT(p2_->ice_complete(), kDefaultTimeout); 1.1221 + WaitForGather(); // ICE can complete before we finish gathering. 1.1222 +} 1.1223 + 1.1224 +TEST_F(IceConnectTest, TestSendReceive) { 1.1225 + AddStream("first", 1); 1.1226 + ASSERT_TRUE(Gather(true)); 1.1227 + Connect(); 1.1228 + SendReceive(); 1.1229 +} 1.1230 + 1.1231 +TEST_F(IceConnectTest, TestConnectTurn) { 1.1232 + if (g_turn_server.empty()) 1.1233 + return; 1.1234 + 1.1235 + AddStream("first", 1); 1.1236 + SetTurnServer(g_turn_server, kDefaultStunServerPort, 1.1237 + g_turn_user, g_turn_password); 1.1238 + ASSERT_TRUE(Gather(true)); 1.1239 + Connect(); 1.1240 +} 1.1241 + 1.1242 +TEST_F(IceConnectTest, TestConnectTurnTcp) { 1.1243 + if (g_turn_server.empty()) 1.1244 + return; 1.1245 + 1.1246 + AddStream("first", 1); 1.1247 + SetTurnServer(g_turn_server, kDefaultStunServerPort, 1.1248 + g_turn_user, g_turn_password, kNrIceTransportTcp); 1.1249 + ASSERT_TRUE(Gather(true)); 1.1250 + Connect(); 1.1251 +} 1.1252 + 1.1253 +TEST_F(IceConnectTest, TestConnectTurnOnly) { 1.1254 + if (g_turn_server.empty()) 1.1255 + return; 1.1256 + 1.1257 + AddStream("first", 1); 1.1258 + SetTurnServer(g_turn_server, kDefaultStunServerPort, 1.1259 + g_turn_user, g_turn_password); 1.1260 + ASSERT_TRUE(Gather(true)); 1.1261 + SetCandidateFilter(IsRelayCandidate); 1.1262 + SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED, 1.1263 + NrIceCandidate::Type::ICE_RELAYED); 1.1264 + Connect(); 1.1265 +} 1.1266 + 1.1267 +TEST_F(IceConnectTest, TestConnectTurnTcpOnly) { 1.1268 + if (g_turn_server.empty()) 1.1269 + return; 1.1270 + 1.1271 + AddStream("first", 1); 1.1272 + SetTurnServer(g_turn_server, kDefaultStunServerPort, 1.1273 + g_turn_user, g_turn_password, kNrIceTransportTcp); 1.1274 + ASSERT_TRUE(Gather(true)); 1.1275 + SetCandidateFilter(IsRelayCandidate); 1.1276 + SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED, 1.1277 + NrIceCandidate::Type::ICE_RELAYED, 1.1278 + kNrIceTransportTcp); 1.1279 + Connect(); 1.1280 +} 1.1281 + 1.1282 +TEST_F(IceConnectTest, TestSendReceiveTurnOnly) { 1.1283 + if (g_turn_server.empty()) 1.1284 + return; 1.1285 + 1.1286 + AddStream("first", 1); 1.1287 + SetTurnServer(g_turn_server, kDefaultStunServerPort, 1.1288 + g_turn_user, g_turn_password); 1.1289 + ASSERT_TRUE(Gather(true)); 1.1290 + SetCandidateFilter(IsRelayCandidate); 1.1291 + SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED, 1.1292 + NrIceCandidate::Type::ICE_RELAYED); 1.1293 + Connect(); 1.1294 + SendReceive(); 1.1295 +} 1.1296 + 1.1297 +TEST_F(IceConnectTest, TestSendReceiveTurnTcpOnly) { 1.1298 + if (g_turn_server.empty()) 1.1299 + return; 1.1300 + 1.1301 + AddStream("first", 1); 1.1302 + SetTurnServer(g_turn_server, kDefaultStunServerPort, 1.1303 + g_turn_user, g_turn_password, kNrIceTransportTcp); 1.1304 + ASSERT_TRUE(Gather(true)); 1.1305 + SetCandidateFilter(IsRelayCandidate); 1.1306 + SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED, 1.1307 + NrIceCandidate::Type::ICE_RELAYED, 1.1308 + kNrIceTransportTcp); 1.1309 + Connect(); 1.1310 + SendReceive(); 1.1311 +} 1.1312 + 1.1313 +TEST_F(IceConnectTest, TestSendReceiveTurnBothOnly) { 1.1314 + if (g_turn_server.empty()) 1.1315 + return; 1.1316 + 1.1317 + AddStream("first", 1); 1.1318 + std::vector<NrIceTurnServer> turn_servers; 1.1319 + std::vector<unsigned char> password_vec(g_turn_password.begin(), 1.1320 + g_turn_password.end()); 1.1321 + turn_servers.push_back(*NrIceTurnServer::Create( 1.1322 + g_turn_server, kDefaultStunServerPort, 1.1323 + g_turn_user, password_vec, kNrIceTransportTcp)); 1.1324 + turn_servers.push_back(*NrIceTurnServer::Create( 1.1325 + g_turn_server, kDefaultStunServerPort, 1.1326 + g_turn_user, password_vec, kNrIceTransportUdp)); 1.1327 + SetTurnServers(turn_servers); 1.1328 + ASSERT_TRUE(Gather(true)); 1.1329 + SetCandidateFilter(IsRelayCandidate); 1.1330 + // UDP is preferred. 1.1331 + SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED, 1.1332 + NrIceCandidate::Type::ICE_RELAYED, 1.1333 + kNrIceTransportUdp); 1.1334 + Connect(); 1.1335 + SendReceive(); 1.1336 +} 1.1337 + 1.1338 +TEST_F(IceConnectTest, TestConnectShutdownOneSide) { 1.1339 + AddStream("first", 1); 1.1340 + ASSERT_TRUE(Gather(true)); 1.1341 + ConnectThenDelete(); 1.1342 +} 1.1343 + 1.1344 +TEST_F(IceConnectTest, TestPollCandPairsBeforeConnect) { 1.1345 + AddStream("first", 1); 1.1346 + ASSERT_TRUE(Gather(true)); 1.1347 + 1.1348 + std::vector<NrIceCandidatePair> pairs; 1.1349 + nsresult res = p1_->GetCandidatePairs(0, &pairs); 1.1350 + // There should be no candidate pairs prior to calling Connect() 1.1351 + ASSERT_TRUE(NS_FAILED(res)); 1.1352 + ASSERT_EQ(0U, pairs.size()); 1.1353 + 1.1354 + res = p2_->GetCandidatePairs(0, &pairs); 1.1355 + ASSERT_TRUE(NS_FAILED(res)); 1.1356 + ASSERT_EQ(0U, pairs.size()); 1.1357 +} 1.1358 + 1.1359 +TEST_F(IceConnectTest, TestPollCandPairsAfterConnect) { 1.1360 + AddStream("first", 1); 1.1361 + ASSERT_TRUE(Gather(true)); 1.1362 + Connect(); 1.1363 + 1.1364 + std::vector<NrIceCandidatePair> pairs; 1.1365 + nsresult r = p1_->GetCandidatePairs(0, &pairs); 1.1366 + ASSERT_EQ(NS_OK, r); 1.1367 + // How detailed of a check do we want to do here? If the turn server is 1.1368 + // functioning, we'll get at least two pairs, but this is probably not 1.1369 + // something we should assume. 1.1370 + ASSERT_NE(0U, pairs.size()); 1.1371 + ASSERT_TRUE(p1_->CandidatePairsPriorityDescending(pairs)); 1.1372 + ASSERT_TRUE(ContainsSucceededPair(pairs)); 1.1373 + pairs.clear(); 1.1374 + 1.1375 + r = p2_->GetCandidatePairs(0, &pairs); 1.1376 + ASSERT_EQ(NS_OK, r); 1.1377 + ASSERT_NE(0U, pairs.size()); 1.1378 + ASSERT_TRUE(p2_->CandidatePairsPriorityDescending(pairs)); 1.1379 + ASSERT_TRUE(ContainsSucceededPair(pairs)); 1.1380 +} 1.1381 + 1.1382 +TEST_F(IceConnectTest, TestPollCandPairsDuringConnect) { 1.1383 + AddStream("first", 1); 1.1384 + ASSERT_TRUE(Gather(true)); 1.1385 + 1.1386 + p1_->Connect(p2_, TRICKLE_NONE, false); 1.1387 + p2_->Connect(p1_, TRICKLE_NONE, false); 1.1388 + 1.1389 + std::vector<NrIceCandidatePair> pairs1; 1.1390 + std::vector<NrIceCandidatePair> pairs2; 1.1391 + 1.1392 + p1_->StartChecks(); 1.1393 + p1_->UpdateAndValidateCandidatePairs(0, &pairs1); 1.1394 + p2_->UpdateAndValidateCandidatePairs(0, &pairs2); 1.1395 + 1.1396 + p2_->StartChecks(); 1.1397 + p1_->UpdateAndValidateCandidatePairs(0, &pairs1); 1.1398 + p2_->UpdateAndValidateCandidatePairs(0, &pairs2); 1.1399 + 1.1400 + WaitForComplete(); 1.1401 + p1_->UpdateAndValidateCandidatePairs(0, &pairs1); 1.1402 + p2_->UpdateAndValidateCandidatePairs(0, &pairs2); 1.1403 + ASSERT_TRUE(ContainsSucceededPair(pairs1)); 1.1404 + ASSERT_TRUE(ContainsSucceededPair(pairs2)); 1.1405 +} 1.1406 + 1.1407 +TEST_F(IceConnectTest, TestRLogRingBuffer) { 1.1408 + RLogRingBuffer::CreateInstance(); 1.1409 + AddStream("first", 1); 1.1410 + ASSERT_TRUE(Gather(true)); 1.1411 + 1.1412 + p1_->Connect(p2_, TRICKLE_NONE, false); 1.1413 + p2_->Connect(p1_, TRICKLE_NONE, false); 1.1414 + 1.1415 + std::vector<NrIceCandidatePair> pairs1; 1.1416 + std::vector<NrIceCandidatePair> pairs2; 1.1417 + 1.1418 + p1_->StartChecks(); 1.1419 + p1_->UpdateAndValidateCandidatePairs(0, &pairs1); 1.1420 + p2_->UpdateAndValidateCandidatePairs(0, &pairs2); 1.1421 + 1.1422 + p2_->StartChecks(); 1.1423 + p1_->UpdateAndValidateCandidatePairs(0, &pairs1); 1.1424 + p2_->UpdateAndValidateCandidatePairs(0, &pairs2); 1.1425 + 1.1426 + WaitForComplete(); 1.1427 + p1_->UpdateAndValidateCandidatePairs(0, &pairs1); 1.1428 + p2_->UpdateAndValidateCandidatePairs(0, &pairs2); 1.1429 + ASSERT_TRUE(ContainsSucceededPair(pairs1)); 1.1430 + ASSERT_TRUE(ContainsSucceededPair(pairs2)); 1.1431 + 1.1432 + for (auto p = pairs1.begin(); p != pairs1.end(); ++p) { 1.1433 + std::deque<std::string> logs; 1.1434 + std::string substring("CAND-PAIR("); 1.1435 + substring += p->codeword; 1.1436 + RLogRingBuffer::GetInstance()->Filter(substring, 0, &logs); 1.1437 + ASSERT_NE(0U, logs.size()); 1.1438 + } 1.1439 + 1.1440 + for (auto p = pairs2.begin(); p != pairs2.end(); ++p) { 1.1441 + std::deque<std::string> logs; 1.1442 + std::string substring("CAND-PAIR("); 1.1443 + substring += p->codeword; 1.1444 + RLogRingBuffer::GetInstance()->Filter(substring, 0, &logs); 1.1445 + ASSERT_NE(0U, logs.size()); 1.1446 + } 1.1447 + 1.1448 + RLogRingBuffer::DestroyInstance(); 1.1449 +} 1.1450 + 1.1451 +TEST_F(PrioritizerTest, TestPrioritizer) { 1.1452 + SetPriorizer(::mozilla::CreateInterfacePrioritizer()); 1.1453 + 1.1454 + AddInterface("0", NR_INTERFACE_TYPE_VPN, 100); // unknown vpn 1.1455 + AddInterface("1", NR_INTERFACE_TYPE_VPN | NR_INTERFACE_TYPE_WIRED, 100); // wired vpn 1.1456 + AddInterface("2", NR_INTERFACE_TYPE_VPN | NR_INTERFACE_TYPE_WIFI, 100); // wifi vpn 1.1457 + AddInterface("3", NR_INTERFACE_TYPE_VPN | NR_INTERFACE_TYPE_MOBILE, 100); // wifi vpn 1.1458 + AddInterface("4", NR_INTERFACE_TYPE_WIRED, 1000); // wired, high speed 1.1459 + AddInterface("5", NR_INTERFACE_TYPE_WIRED, 10); // wired, low speed 1.1460 + AddInterface("6", NR_INTERFACE_TYPE_WIFI, 10); // wifi, low speed 1.1461 + AddInterface("7", NR_INTERFACE_TYPE_WIFI, 1000); // wifi, high speed 1.1462 + AddInterface("8", NR_INTERFACE_TYPE_MOBILE, 10); // mobile, low speed 1.1463 + AddInterface("9", NR_INTERFACE_TYPE_MOBILE, 1000); // mobile, high speed 1.1464 + AddInterface("10", NR_INTERFACE_TYPE_UNKNOWN, 10); // unknown, low speed 1.1465 + AddInterface("11", NR_INTERFACE_TYPE_UNKNOWN, 1000); // unknown, high speed 1.1466 + 1.1467 + // expected preference "4" > "5" > "1" > "7" > "6" > "2" > "9" > "8" > "3" > "11" > "10" > "0" 1.1468 + 1.1469 + HasLowerPreference("0", "10"); 1.1470 + HasLowerPreference("10", "11"); 1.1471 + HasLowerPreference("11", "3"); 1.1472 + HasLowerPreference("3", "8"); 1.1473 + HasLowerPreference("8", "9"); 1.1474 + HasLowerPreference("9", "2"); 1.1475 + HasLowerPreference("2", "6"); 1.1476 + HasLowerPreference("6", "7"); 1.1477 + HasLowerPreference("7", "1"); 1.1478 + HasLowerPreference("1", "5"); 1.1479 + HasLowerPreference("5", "4"); 1.1480 +} 1.1481 + 1.1482 +TEST_F(PacketFilterTest, TestSendNonStunPacket) { 1.1483 + const unsigned char data[] = "12345abcde"; 1.1484 + TestOutgoing(data, sizeof(data), 123, 45, false); 1.1485 +} 1.1486 + 1.1487 +TEST_F(PacketFilterTest, TestRecvNonStunPacket) { 1.1488 + const unsigned char data[] = "12345abcde"; 1.1489 + TestIncoming(data, sizeof(data), 123, 45, false); 1.1490 +} 1.1491 + 1.1492 +TEST_F(PacketFilterTest, TestSendStunPacket) { 1.1493 + nr_stun_message *msg; 1.1494 + ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg)); 1.1495 + msg->header.type = NR_STUN_MSG_BINDING_REQUEST; 1.1496 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1497 + TestOutgoing(msg->buffer, msg->length, 123, 45, true); 1.1498 + ASSERT_EQ(0, nr_stun_message_destroy(&msg)); 1.1499 +} 1.1500 + 1.1501 +TEST_F(PacketFilterTest, TestRecvStunPacketWithoutAPendingId) { 1.1502 + nr_stun_message *msg; 1.1503 + ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg)); 1.1504 + 1.1505 + msg->header.id.octet[0] = 1; 1.1506 + msg->header.type = NR_STUN_MSG_BINDING_REQUEST; 1.1507 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1508 + TestOutgoing(msg->buffer, msg->length, 123, 45, true); 1.1509 + 1.1510 + msg->header.id.octet[0] = 0; 1.1511 + msg->header.type = NR_STUN_MSG_BINDING_RESPONSE; 1.1512 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1513 + TestIncoming(msg->buffer, msg->length, 123, 45, true); 1.1514 + 1.1515 + ASSERT_EQ(0, nr_stun_message_destroy(&msg)); 1.1516 +} 1.1517 + 1.1518 +TEST_F(PacketFilterTest, TestRecvStunPacketWithoutAPendingAddress) { 1.1519 + nr_stun_message *msg; 1.1520 + ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg)); 1.1521 + 1.1522 + msg->header.type = NR_STUN_MSG_BINDING_REQUEST; 1.1523 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1524 + TestOutgoing(msg->buffer, msg->length, 123, 45, true); 1.1525 + 1.1526 + msg->header.type = NR_STUN_MSG_BINDING_RESPONSE; 1.1527 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1528 + TestIncoming(msg->buffer, msg->length, 123, 46, false); 1.1529 + TestIncoming(msg->buffer, msg->length, 124, 45, false); 1.1530 + 1.1531 + ASSERT_EQ(0, nr_stun_message_destroy(&msg)); 1.1532 +} 1.1533 + 1.1534 +TEST_F(PacketFilterTest, TestRecvStunPacketWithPendingIdAndAddress) { 1.1535 + nr_stun_message *msg; 1.1536 + ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg)); 1.1537 + 1.1538 + msg->header.type = NR_STUN_MSG_BINDING_REQUEST; 1.1539 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1540 + TestOutgoing(msg->buffer, msg->length, 123, 45, true); 1.1541 + 1.1542 + msg->header.type = NR_STUN_MSG_BINDING_RESPONSE; 1.1543 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1544 + TestIncoming(msg->buffer, msg->length, 123, 45, true); 1.1545 + 1.1546 + // Test whitelist by filtering non-stun packets. 1.1547 + const unsigned char data[] = "12345abcde"; 1.1548 + 1.1549 + // 123:45 is white-listed. 1.1550 + TestOutgoing(data, sizeof(data), 123, 45, true); 1.1551 + TestIncoming(data, sizeof(data), 123, 45, true); 1.1552 + 1.1553 + // Indications pass as well. 1.1554 + msg->header.type = NR_STUN_MSG_BINDING_INDICATION; 1.1555 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1556 + TestOutgoing(msg->buffer, msg->length, 123, 45, true); 1.1557 + TestIncoming(msg->buffer, msg->length, 123, 45, true); 1.1558 + 1.1559 + // Packets from and to other address are still disallowed. 1.1560 + TestOutgoing(data, sizeof(data), 123, 46, false); 1.1561 + TestIncoming(data, sizeof(data), 123, 46, false); 1.1562 + TestOutgoing(data, sizeof(data), 124, 45, false); 1.1563 + TestIncoming(data, sizeof(data), 124, 45, false); 1.1564 + 1.1565 + ASSERT_EQ(0, nr_stun_message_destroy(&msg)); 1.1566 +} 1.1567 + 1.1568 +TEST_F(PacketFilterTest, TestSendNonRequestStunPacket) { 1.1569 + nr_stun_message *msg; 1.1570 + ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg)); 1.1571 + 1.1572 + msg->header.type = NR_STUN_MSG_BINDING_RESPONSE; 1.1573 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1574 + TestOutgoing(msg->buffer, msg->length, 123, 45, false); 1.1575 + 1.1576 + // Send a packet so we allow the incoming request. 1.1577 + msg->header.type = NR_STUN_MSG_BINDING_REQUEST; 1.1578 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1579 + TestOutgoing(msg->buffer, msg->length, 123, 45, true); 1.1580 + 1.1581 + // This packet makes us able to send a response. 1.1582 + msg->header.type = NR_STUN_MSG_BINDING_REQUEST; 1.1583 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1584 + TestIncoming(msg->buffer, msg->length, 123, 45, true); 1.1585 + 1.1586 + msg->header.type = NR_STUN_MSG_BINDING_RESPONSE; 1.1587 + ASSERT_EQ(0, nr_stun_encode_message(msg)); 1.1588 + TestOutgoing(msg->buffer, msg->length, 123, 45, true); 1.1589 + 1.1590 + ASSERT_EQ(0, nr_stun_message_destroy(&msg)); 1.1591 +} 1.1592 + 1.1593 +static std::string get_environment(const char *name) { 1.1594 + char *value = getenv(name); 1.1595 + 1.1596 + if (!value) 1.1597 + return ""; 1.1598 + 1.1599 + return value; 1.1600 +} 1.1601 + 1.1602 +int main(int argc, char **argv) 1.1603 +{ 1.1604 +#ifdef LINUX 1.1605 + // This test can cause intermittent oranges on the builders on Linux 1.1606 + CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_TESTS") 1.1607 +#endif 1.1608 + 1.1609 + g_turn_server = get_environment("TURN_SERVER_ADDRESS"); 1.1610 + g_turn_user = get_environment("TURN_SERVER_USER"); 1.1611 + g_turn_password = get_environment("TURN_SERVER_PASSWORD"); 1.1612 + 1.1613 + if (g_turn_server.empty() || 1.1614 + g_turn_user.empty(), 1.1615 + g_turn_password.empty()) { 1.1616 + printf( 1.1617 + "Set TURN_SERVER_ADDRESS, TURN_SERVER_USER, and TURN_SERVER_PASSWORD\n" 1.1618 + "environment variables to run this test\n"); 1.1619 + g_turn_server=""; 1.1620 + } 1.1621 + 1.1622 + std::string tmp = get_environment("STUN_SERVER_ADDRESS"); 1.1623 + if (tmp != "") 1.1624 + g_stun_server_address = tmp; 1.1625 + 1.1626 + 1.1627 + tmp = get_environment("STUN_SERVER_HOSTNAME"); 1.1628 + if (tmp != "") 1.1629 + g_stun_server_hostname = tmp; 1.1630 + 1.1631 + test_utils = new MtransportTestUtils(); 1.1632 + NSS_NoDB_Init(nullptr); 1.1633 + NSS_SetDomesticPolicy(); 1.1634 + 1.1635 + // Start the tests 1.1636 + ::testing::InitGoogleTest(&argc, argv); 1.1637 + 1.1638 + ::testing::TestEventListeners& listeners = 1.1639 + ::testing::UnitTest::GetInstance()->listeners(); 1.1640 + // Adds a listener to the end. Google Test takes the ownership. 1.1641 + 1.1642 + listeners.Append(new test::RingbufferDumper(test_utils)); 1.1643 + test_utils->sts_target()->Dispatch( 1.1644 + WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC); 1.1645 + 1.1646 + int rv = RUN_ALL_TESTS(); 1.1647 + 1.1648 + test_utils->sts_target()->Dispatch( 1.1649 + WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC); 1.1650 + 1.1651 + delete test_utils; 1.1652 + return rv; 1.1653 +}