|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 // Original author: ekr@rtfm.com |
|
8 |
|
9 #include <algorithm> |
|
10 #include <deque> |
|
11 #include <iostream> |
|
12 #include <limits> |
|
13 #include <map> |
|
14 #include <string> |
|
15 #include <vector> |
|
16 |
|
17 #include "sigslot.h" |
|
18 |
|
19 #include "logging.h" |
|
20 #include "nspr.h" |
|
21 #include "nss.h" |
|
22 #include "ssl.h" |
|
23 |
|
24 #include "mozilla/Scoped.h" |
|
25 #include "nsThreadUtils.h" |
|
26 #include "nsXPCOM.h" |
|
27 |
|
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" |
|
43 |
|
44 #define GTEST_HAS_RTTI 0 |
|
45 #include "gtest/gtest.h" |
|
46 #include "gtest_utils.h" |
|
47 |
|
48 using namespace mozilla; |
|
49 MtransportTestUtils *test_utils; |
|
50 |
|
51 bool stream_added = false; |
|
52 |
|
53 static int kDefaultTimeout = 7000; |
|
54 |
|
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"); |
|
63 |
|
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; |
|
69 |
|
70 namespace { |
|
71 |
|
72 enum TrickleMode { TRICKLE_NONE, TRICKLE_SIMULATE, TRICKLE_REAL }; |
|
73 |
|
74 typedef bool (*CandidateFilter)(const std::string& candidate); |
|
75 |
|
76 static bool IsRelayCandidate(const std::string& candidate) { |
|
77 return candidate.find("typ relay") != std::string::npos; |
|
78 } |
|
79 |
|
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 } |
|
88 |
|
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 } |
|
104 |
|
105 bool operator==(const NrIceCandidate& lhs, |
|
106 const NrIceCandidate& rhs) { |
|
107 return !((lhs < rhs) || (rhs < lhs)); |
|
108 } |
|
109 |
|
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 }; |
|
126 |
|
127 class IceTestPeer : public sigslot::has_slots<> { |
|
128 public: |
|
129 |
|
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 } |
|
156 |
|
157 ~IceTestPeer() { |
|
158 test_utils->sts_target()->Dispatch(WrapRunnable(this, |
|
159 &IceTestPeer::Shutdown), |
|
160 NS_DISPATCH_SYNC); |
|
161 |
|
162 // Give the ICE destruction callback time to fire before |
|
163 // we destroy the resolver. |
|
164 PR_Sleep(1000); |
|
165 } |
|
166 |
|
167 void AddStream(int components) { |
|
168 char name[100]; |
|
169 snprintf(name, sizeof(name), "%s:stream%d", name_.c_str(), |
|
170 (int)streams_.size()); |
|
171 |
|
172 mozilla::RefPtr<NrIceMediaStream> stream = |
|
173 ice_ctx_->CreateStream(static_cast<char *>(name), components); |
|
174 |
|
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 } |
|
182 |
|
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 } |
|
190 |
|
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 } |
|
198 |
|
199 |
|
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 } |
|
210 |
|
211 void SetTurnServers(const std::vector<NrIceTurnServer> servers) { |
|
212 ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(servers))); |
|
213 } |
|
214 |
|
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 } |
|
226 |
|
227 void SetDNSResolver() { |
|
228 ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init())); |
|
229 ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver( |
|
230 dns_resolver_->AllocateResolver()))); |
|
231 } |
|
232 |
|
233 void Gather() { |
|
234 nsresult res; |
|
235 |
|
236 test_utils->sts_target()->Dispatch( |
|
237 WrapRunnableRet(ice_ctx_, &NrIceCtx::StartGathering, &res), |
|
238 NS_DISPATCH_SYNC); |
|
239 |
|
240 ASSERT_TRUE(NS_SUCCEEDED(res)); |
|
241 } |
|
242 |
|
243 // Get various pieces of state |
|
244 std::vector<std::string> GetGlobalAttributes() { |
|
245 return ice_ctx_->GetGlobalAttributes(); |
|
246 } |
|
247 |
|
248 std::vector<std::string> GetCandidates(size_t stream) { |
|
249 std::vector<std::string> v; |
|
250 |
|
251 RUN_ON_THREAD( |
|
252 test_utils->sts_target(), |
|
253 WrapRunnableRet(this, &IceTestPeer::GetCandidates_s, stream, &v), |
|
254 NS_DISPATCH_SYNC); |
|
255 |
|
256 return v; |
|
257 } |
|
258 |
|
259 std::vector<std::string> GetCandidates_s(size_t stream) { |
|
260 std::vector<std::string> candidates; |
|
261 |
|
262 if (stream >= streams_.size()) |
|
263 return candidates; |
|
264 |
|
265 std::vector<std::string> candidates_in = |
|
266 streams_[stream]->GetCandidates(); |
|
267 |
|
268 |
|
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 } |
|
275 |
|
276 return candidates; |
|
277 } |
|
278 |
|
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 } |
|
286 |
|
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_; } |
|
295 |
|
296 // Start connecting to another peer |
|
297 void Connect_s(IceTestPeer *remote, TrickleMode trickle_mode, |
|
298 bool start = true) { |
|
299 nsresult res; |
|
300 |
|
301 remote_ = remote; |
|
302 |
|
303 trickle_mode_ = trickle_mode; |
|
304 res = ice_ctx_->ParseGlobalAttributes(remote->GetGlobalAttributes()); |
|
305 ASSERT_TRUE(NS_SUCCEEDED(res)); |
|
306 |
|
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); |
|
312 |
|
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 } |
|
327 |
|
328 if (start) { |
|
329 // Now start checks |
|
330 res = ice_ctx_->StartChecks(); |
|
331 ASSERT_TRUE(NS_SUCCEEDED(res)); |
|
332 } |
|
333 } |
|
334 |
|
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 } |
|
342 |
|
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; |
|
348 |
|
349 ASSERT_GT(remote_->streams_.size(), stream); |
|
350 |
|
351 std::vector<std::string> candidates = |
|
352 remote_->GetCandidates(stream); |
|
353 |
|
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); |
|
360 |
|
361 ASSERT_TRUE(NS_SUCCEEDED(res)); |
|
362 } |
|
363 } |
|
364 |
|
365 void DumpCandidate(std::string which, const NrIceCandidate& cand) { |
|
366 std::string type; |
|
367 |
|
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 }; |
|
387 |
|
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 } |
|
399 |
|
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; |
|
405 |
|
406 NrIceCandidate *local; |
|
407 NrIceCandidate *remote; |
|
408 |
|
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 } |
|
425 |
|
426 void DumpAndCheckActiveCandidates() { |
|
427 test_utils->sts_target()->Dispatch( |
|
428 WrapRunnable(this, &IceTestPeer::DumpAndCheckActiveCandidates_s), |
|
429 NS_DISPATCH_SYNC); |
|
430 } |
|
431 |
|
432 void Close() { |
|
433 test_utils->sts_target()->Dispatch( |
|
434 WrapRunnable(ice_ctx_, &NrIceCtx::destroy_peer_ctx), |
|
435 NS_DISPATCH_SYNC); |
|
436 } |
|
437 |
|
438 void Shutdown() { |
|
439 ice_ctx_ = nullptr; |
|
440 } |
|
441 |
|
442 void StartChecks() { |
|
443 nsresult res; |
|
444 |
|
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 } |
|
451 |
|
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 } |
|
459 |
|
460 std::cerr << "Gathering complete for " << name_ << std::endl; |
|
461 gathering_complete_ = true; |
|
462 |
|
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(); |
|
468 |
|
469 for(size_t j=0; j<candidates.size(); ++j) { |
|
470 std::cerr << candidates[j] << std::endl; |
|
471 } |
|
472 } |
|
473 std::cerr << std::endl; |
|
474 |
|
475 } |
|
476 |
|
477 void CandidateInitialized(NrIceMediaStream *stream, const std::string &candidate) { |
|
478 std::cerr << "Candidate initialized: " << candidate << std::endl; |
|
479 candidates_[stream->name()].push_back(candidate); |
|
480 |
|
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(); |
|
488 |
|
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 } |
|
496 |
|
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 } |
|
505 |
|
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 } |
|
515 |
|
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 } |
|
526 |
|
527 void DumpCandidatePairs(NrIceMediaStream *stream) { |
|
528 std::vector<NrIceCandidatePair> pairs; |
|
529 nsresult res = stream->GetCandidatePairs(&pairs); |
|
530 ASSERT_TRUE(NS_SUCCEEDED(res)); |
|
531 |
|
532 std::cerr << "Begin list of candidate pairs [" << std::endl; |
|
533 |
|
534 for (std::vector<NrIceCandidatePair>::iterator p = pairs.begin(); |
|
535 p != pairs.end(); ++p) { |
|
536 DumpCandidatePair(*p); |
|
537 } |
|
538 std::cerr << "]" << std::endl; |
|
539 } |
|
540 |
|
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 } |
|
548 |
|
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(); |
|
553 |
|
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 } |
|
570 |
|
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; |
|
584 |
|
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()); |
|
597 |
|
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()); |
|
604 |
|
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 } |
|
610 |
|
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 } |
|
616 |
|
617 ASSERT_TRUE(removed_pairs.empty()) << "At least one candidate pair has " |
|
618 "gone missing."; |
|
619 } |
|
620 |
|
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 } |
|
630 |
|
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 } |
|
640 |
|
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 } |
|
646 |
|
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))); |
|
650 |
|
651 ++sent_; |
|
652 std::cerr << "Sent " << len << " bytes" << std::endl; |
|
653 } |
|
654 |
|
655 void SetCandidateFilter(CandidateFilter filter) { |
|
656 candidate_filter_ = filter; |
|
657 } |
|
658 |
|
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; |
|
662 |
|
663 attributes.push_back(candidate); |
|
664 streams_[i]->ParseAttributes(attributes); |
|
665 } |
|
666 |
|
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 } |
|
672 |
|
673 int trickled() { return trickled_; } |
|
674 |
|
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 }; |
|
695 |
|
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 } |
|
705 |
|
706 void Gather(bool wait = true) { |
|
707 peer_->Gather(); |
|
708 |
|
709 if (wait) { |
|
710 WaitForGather(); |
|
711 } |
|
712 } |
|
713 |
|
714 void WaitForGather() { |
|
715 ASSERT_TRUE_WAIT(peer_->gathering_complete(), kDefaultTimeout); |
|
716 } |
|
717 |
|
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 } |
|
725 |
|
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 } |
|
738 |
|
739 protected: |
|
740 mozilla::ScopedDeletePtr<IceTestPeer> peer_; |
|
741 }; |
|
742 |
|
743 class IceConnectTest : public ::testing::Test { |
|
744 public: |
|
745 IceConnectTest() : initted_(false) {} |
|
746 |
|
747 void SetUp() { |
|
748 nsresult rv; |
|
749 target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); |
|
750 ASSERT_TRUE(NS_SUCCEEDED(rv)); |
|
751 } |
|
752 |
|
753 void AddStream(const std::string& name, int components) { |
|
754 Init(false); |
|
755 p1_->AddStream(components); |
|
756 p2_->AddStream(components); |
|
757 } |
|
758 |
|
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 } |
|
766 |
|
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(); |
|
773 |
|
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 } |
|
784 |
|
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 } |
|
792 |
|
793 void SetTurnServers(const std::vector<NrIceTurnServer>& servers) { |
|
794 p1_->SetTurnServers(servers); |
|
795 p2_->SetTurnServers(servers); |
|
796 } |
|
797 |
|
798 void SetCandidateFilter(CandidateFilter filter, bool both=true) { |
|
799 p1_->SetCandidateFilter(filter); |
|
800 if (both) { |
|
801 p2_->SetCandidateFilter(filter); |
|
802 } |
|
803 } |
|
804 |
|
805 void Connect() { |
|
806 p1_->Connect(p2_, TRICKLE_NONE); |
|
807 p2_->Connect(p1_, TRICKLE_NONE); |
|
808 |
|
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); |
|
813 |
|
814 p1_->DumpAndCheckActiveCandidates(); |
|
815 p2_->DumpAndCheckActiveCandidates(); |
|
816 } |
|
817 |
|
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 } |
|
823 |
|
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 } |
|
829 |
|
830 void ConnectP1(TrickleMode mode = TRICKLE_NONE) { |
|
831 p1_->Connect(p2_, mode); |
|
832 } |
|
833 |
|
834 void ConnectP2(TrickleMode mode = TRICKLE_NONE) { |
|
835 p2_->Connect(p1_, mode); |
|
836 } |
|
837 |
|
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 } |
|
844 |
|
845 void WaitForGather() { |
|
846 ASSERT_TRUE_WAIT(p1_->gathering_complete(), kDefaultTimeout); |
|
847 ASSERT_TRUE_WAIT(p2_->gathering_complete(), kDefaultTimeout); |
|
848 } |
|
849 |
|
850 void ConnectTrickle(TrickleMode trickle = TRICKLE_SIMULATE) { |
|
851 p1_->Connect(p2_, trickle); |
|
852 p2_->Connect(p1_, trickle); |
|
853 } |
|
854 |
|
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 } |
|
861 |
|
862 void SimulateTrickleP1(size_t stream) { |
|
863 p1_->SimulateTrickle(stream); |
|
864 } |
|
865 |
|
866 void SimulateTrickleP2(size_t stream) { |
|
867 p2_->SimulateTrickle(stream); |
|
868 } |
|
869 |
|
870 void VerifyConnected() { |
|
871 } |
|
872 |
|
873 void CloseP1() { |
|
874 p1_->Close(); |
|
875 } |
|
876 |
|
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(); |
|
884 |
|
885 // Wait to see if we crash |
|
886 PR_Sleep(PR_MillisecondsToInterval(kDefaultTimeout)); |
|
887 } |
|
888 |
|
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 } |
|
899 |
|
900 protected: |
|
901 bool initted_; |
|
902 nsCOMPtr<nsIEventTarget> target_; |
|
903 mozilla::ScopedDeletePtr<IceTestPeer> p1_; |
|
904 mozilla::ScopedDeletePtr<IceTestPeer> p2_; |
|
905 }; |
|
906 |
|
907 class PrioritizerTest : public ::testing::Test { |
|
908 public: |
|
909 PrioritizerTest(): |
|
910 prioritizer_(nullptr) {} |
|
911 |
|
912 ~PrioritizerTest() { |
|
913 if (prioritizer_) { |
|
914 nr_interface_prioritizer_destroy(&prioritizer_); |
|
915 } |
|
916 } |
|
917 |
|
918 void SetPriorizer(nr_interface_prioritizer *prioritizer) { |
|
919 prioritizer_ = prioritizer; |
|
920 } |
|
921 |
|
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; |
|
928 |
|
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); |
|
933 |
|
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 } |
|
939 |
|
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 } |
|
950 |
|
951 private: |
|
952 nr_interface_prioritizer *prioritizer_; |
|
953 }; |
|
954 |
|
955 class PacketFilterTest : public ::testing::Test { |
|
956 public: |
|
957 PacketFilterTest(): filter_(nullptr) {} |
|
958 |
|
959 void SetUp() { |
|
960 nsCOMPtr<nsIUDPSocketFilterHandler> handler = |
|
961 do_GetService(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID); |
|
962 handler->NewFilter(getter_AddRefs(filter_)); |
|
963 } |
|
964 |
|
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 } |
|
977 |
|
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 } |
|
990 |
|
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 } |
|
998 |
|
999 nsCOMPtr<nsIUDPSocketFilter> filter_; |
|
1000 }; |
|
1001 } // end namespace |
|
1002 |
|
1003 TEST_F(IceGatherTest, TestGatherFakeStunServerHostnameNoResolver) { |
|
1004 peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort); |
|
1005 Gather(); |
|
1006 } |
|
1007 |
|
1008 TEST_F(IceGatherTest, TestGatherFakeStunServerIpAddress) { |
|
1009 peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort); |
|
1010 peer_->SetFakeResolver(); |
|
1011 Gather(); |
|
1012 } |
|
1013 |
|
1014 TEST_F(IceGatherTest, TestGatherFakeStunServerHostname) { |
|
1015 peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort); |
|
1016 peer_->SetFakeResolver(); |
|
1017 Gather(); |
|
1018 } |
|
1019 |
|
1020 TEST_F(IceGatherTest, TestGatherFakeStunBogusHostname) { |
|
1021 peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort); |
|
1022 peer_->SetFakeResolver(); |
|
1023 Gather(); |
|
1024 } |
|
1025 |
|
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 } |
|
1032 |
|
1033 TEST_F(IceGatherTest, TestGatherDNSStunServerHostname) { |
|
1034 peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort); |
|
1035 peer_->SetDNSResolver(); |
|
1036 Gather(); |
|
1037 } |
|
1038 |
|
1039 TEST_F(IceGatherTest, TestGatherDNSStunBogusHostname) { |
|
1040 peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort); |
|
1041 peer_->SetDNSResolver(); |
|
1042 Gather(); |
|
1043 } |
|
1044 |
|
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 } |
|
1052 |
|
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 } |
|
1060 |
|
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); |
|
1068 |
|
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 } |
|
1074 |
|
1075 |
|
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 } |
|
1082 |
|
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 } |
|
1088 |
|
1089 TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddr) { |
|
1090 UseFakeStunServerWithResponse("0.0.0.0", 3333); |
|
1091 Gather(); |
|
1092 ASSERT_FALSE(StreamHasMatchingCandidate(0, " 0.0.0.0 ")); |
|
1093 } |
|
1094 |
|
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 } |
|
1100 |
|
1101 TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddr) { |
|
1102 UseFakeStunServerWithResponse("127.0.0.133", 3333); |
|
1103 Gather(); |
|
1104 ASSERT_FALSE(StreamHasMatchingCandidate(0, " 127.0.0.133 ")); |
|
1105 } |
|
1106 |
|
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 } |
|
1116 |
|
1117 TEST_F(IceConnectTest, TestGather) { |
|
1118 AddStream("first", 1); |
|
1119 ASSERT_TRUE(Gather(true)); |
|
1120 } |
|
1121 |
|
1122 TEST_F(IceConnectTest, TestGatherAutoPrioritize) { |
|
1123 Init(false); |
|
1124 AddStream("first", 1); |
|
1125 ASSERT_TRUE(Gather(true)); |
|
1126 } |
|
1127 |
|
1128 |
|
1129 TEST_F(IceConnectTest, TestConnect) { |
|
1130 AddStream("first", 1); |
|
1131 ASSERT_TRUE(Gather(true)); |
|
1132 Connect(); |
|
1133 } |
|
1134 |
|
1135 TEST_F(IceConnectTest, TestConnectTwoComponents) { |
|
1136 AddStream("first", 2); |
|
1137 ASSERT_TRUE(Gather(true)); |
|
1138 Connect(); |
|
1139 } |
|
1140 |
|
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 } |
|
1148 |
|
1149 |
|
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 } |
|
1158 |
|
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 } |
|
1168 |
|
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 } |
|
1183 |
|
1184 TEST_F(IceConnectTest, TestConnectAutoPrioritize) { |
|
1185 Init(false); |
|
1186 AddStream("first", 1); |
|
1187 ASSERT_TRUE(Gather(true)); |
|
1188 Connect(); |
|
1189 } |
|
1190 |
|
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 } |
|
1199 |
|
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 } |
|
1210 |
|
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 } |
|
1220 |
|
1221 TEST_F(IceConnectTest, TestSendReceive) { |
|
1222 AddStream("first", 1); |
|
1223 ASSERT_TRUE(Gather(true)); |
|
1224 Connect(); |
|
1225 SendReceive(); |
|
1226 } |
|
1227 |
|
1228 TEST_F(IceConnectTest, TestConnectTurn) { |
|
1229 if (g_turn_server.empty()) |
|
1230 return; |
|
1231 |
|
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 } |
|
1238 |
|
1239 TEST_F(IceConnectTest, TestConnectTurnTcp) { |
|
1240 if (g_turn_server.empty()) |
|
1241 return; |
|
1242 |
|
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 } |
|
1249 |
|
1250 TEST_F(IceConnectTest, TestConnectTurnOnly) { |
|
1251 if (g_turn_server.empty()) |
|
1252 return; |
|
1253 |
|
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 } |
|
1263 |
|
1264 TEST_F(IceConnectTest, TestConnectTurnTcpOnly) { |
|
1265 if (g_turn_server.empty()) |
|
1266 return; |
|
1267 |
|
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 } |
|
1278 |
|
1279 TEST_F(IceConnectTest, TestSendReceiveTurnOnly) { |
|
1280 if (g_turn_server.empty()) |
|
1281 return; |
|
1282 |
|
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 } |
|
1293 |
|
1294 TEST_F(IceConnectTest, TestSendReceiveTurnTcpOnly) { |
|
1295 if (g_turn_server.empty()) |
|
1296 return; |
|
1297 |
|
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 } |
|
1309 |
|
1310 TEST_F(IceConnectTest, TestSendReceiveTurnBothOnly) { |
|
1311 if (g_turn_server.empty()) |
|
1312 return; |
|
1313 |
|
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 } |
|
1334 |
|
1335 TEST_F(IceConnectTest, TestConnectShutdownOneSide) { |
|
1336 AddStream("first", 1); |
|
1337 ASSERT_TRUE(Gather(true)); |
|
1338 ConnectThenDelete(); |
|
1339 } |
|
1340 |
|
1341 TEST_F(IceConnectTest, TestPollCandPairsBeforeConnect) { |
|
1342 AddStream("first", 1); |
|
1343 ASSERT_TRUE(Gather(true)); |
|
1344 |
|
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()); |
|
1350 |
|
1351 res = p2_->GetCandidatePairs(0, &pairs); |
|
1352 ASSERT_TRUE(NS_FAILED(res)); |
|
1353 ASSERT_EQ(0U, pairs.size()); |
|
1354 } |
|
1355 |
|
1356 TEST_F(IceConnectTest, TestPollCandPairsAfterConnect) { |
|
1357 AddStream("first", 1); |
|
1358 ASSERT_TRUE(Gather(true)); |
|
1359 Connect(); |
|
1360 |
|
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(); |
|
1371 |
|
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 } |
|
1378 |
|
1379 TEST_F(IceConnectTest, TestPollCandPairsDuringConnect) { |
|
1380 AddStream("first", 1); |
|
1381 ASSERT_TRUE(Gather(true)); |
|
1382 |
|
1383 p1_->Connect(p2_, TRICKLE_NONE, false); |
|
1384 p2_->Connect(p1_, TRICKLE_NONE, false); |
|
1385 |
|
1386 std::vector<NrIceCandidatePair> pairs1; |
|
1387 std::vector<NrIceCandidatePair> pairs2; |
|
1388 |
|
1389 p1_->StartChecks(); |
|
1390 p1_->UpdateAndValidateCandidatePairs(0, &pairs1); |
|
1391 p2_->UpdateAndValidateCandidatePairs(0, &pairs2); |
|
1392 |
|
1393 p2_->StartChecks(); |
|
1394 p1_->UpdateAndValidateCandidatePairs(0, &pairs1); |
|
1395 p2_->UpdateAndValidateCandidatePairs(0, &pairs2); |
|
1396 |
|
1397 WaitForComplete(); |
|
1398 p1_->UpdateAndValidateCandidatePairs(0, &pairs1); |
|
1399 p2_->UpdateAndValidateCandidatePairs(0, &pairs2); |
|
1400 ASSERT_TRUE(ContainsSucceededPair(pairs1)); |
|
1401 ASSERT_TRUE(ContainsSucceededPair(pairs2)); |
|
1402 } |
|
1403 |
|
1404 TEST_F(IceConnectTest, TestRLogRingBuffer) { |
|
1405 RLogRingBuffer::CreateInstance(); |
|
1406 AddStream("first", 1); |
|
1407 ASSERT_TRUE(Gather(true)); |
|
1408 |
|
1409 p1_->Connect(p2_, TRICKLE_NONE, false); |
|
1410 p2_->Connect(p1_, TRICKLE_NONE, false); |
|
1411 |
|
1412 std::vector<NrIceCandidatePair> pairs1; |
|
1413 std::vector<NrIceCandidatePair> pairs2; |
|
1414 |
|
1415 p1_->StartChecks(); |
|
1416 p1_->UpdateAndValidateCandidatePairs(0, &pairs1); |
|
1417 p2_->UpdateAndValidateCandidatePairs(0, &pairs2); |
|
1418 |
|
1419 p2_->StartChecks(); |
|
1420 p1_->UpdateAndValidateCandidatePairs(0, &pairs1); |
|
1421 p2_->UpdateAndValidateCandidatePairs(0, &pairs2); |
|
1422 |
|
1423 WaitForComplete(); |
|
1424 p1_->UpdateAndValidateCandidatePairs(0, &pairs1); |
|
1425 p2_->UpdateAndValidateCandidatePairs(0, &pairs2); |
|
1426 ASSERT_TRUE(ContainsSucceededPair(pairs1)); |
|
1427 ASSERT_TRUE(ContainsSucceededPair(pairs2)); |
|
1428 |
|
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 } |
|
1436 |
|
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 } |
|
1444 |
|
1445 RLogRingBuffer::DestroyInstance(); |
|
1446 } |
|
1447 |
|
1448 TEST_F(PrioritizerTest, TestPrioritizer) { |
|
1449 SetPriorizer(::mozilla::CreateInterfacePrioritizer()); |
|
1450 |
|
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 |
|
1463 |
|
1464 // expected preference "4" > "5" > "1" > "7" > "6" > "2" > "9" > "8" > "3" > "11" > "10" > "0" |
|
1465 |
|
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 } |
|
1478 |
|
1479 TEST_F(PacketFilterTest, TestSendNonStunPacket) { |
|
1480 const unsigned char data[] = "12345abcde"; |
|
1481 TestOutgoing(data, sizeof(data), 123, 45, false); |
|
1482 } |
|
1483 |
|
1484 TEST_F(PacketFilterTest, TestRecvNonStunPacket) { |
|
1485 const unsigned char data[] = "12345abcde"; |
|
1486 TestIncoming(data, sizeof(data), 123, 45, false); |
|
1487 } |
|
1488 |
|
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 } |
|
1497 |
|
1498 TEST_F(PacketFilterTest, TestRecvStunPacketWithoutAPendingId) { |
|
1499 nr_stun_message *msg; |
|
1500 ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg)); |
|
1501 |
|
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); |
|
1506 |
|
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); |
|
1511 |
|
1512 ASSERT_EQ(0, nr_stun_message_destroy(&msg)); |
|
1513 } |
|
1514 |
|
1515 TEST_F(PacketFilterTest, TestRecvStunPacketWithoutAPendingAddress) { |
|
1516 nr_stun_message *msg; |
|
1517 ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg)); |
|
1518 |
|
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); |
|
1522 |
|
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); |
|
1527 |
|
1528 ASSERT_EQ(0, nr_stun_message_destroy(&msg)); |
|
1529 } |
|
1530 |
|
1531 TEST_F(PacketFilterTest, TestRecvStunPacketWithPendingIdAndAddress) { |
|
1532 nr_stun_message *msg; |
|
1533 ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg)); |
|
1534 |
|
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); |
|
1538 |
|
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); |
|
1542 |
|
1543 // Test whitelist by filtering non-stun packets. |
|
1544 const unsigned char data[] = "12345abcde"; |
|
1545 |
|
1546 // 123:45 is white-listed. |
|
1547 TestOutgoing(data, sizeof(data), 123, 45, true); |
|
1548 TestIncoming(data, sizeof(data), 123, 45, true); |
|
1549 |
|
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); |
|
1555 |
|
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); |
|
1561 |
|
1562 ASSERT_EQ(0, nr_stun_message_destroy(&msg)); |
|
1563 } |
|
1564 |
|
1565 TEST_F(PacketFilterTest, TestSendNonRequestStunPacket) { |
|
1566 nr_stun_message *msg; |
|
1567 ASSERT_EQ(0, nr_stun_build_req_no_auth(NULL, &msg)); |
|
1568 |
|
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); |
|
1572 |
|
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); |
|
1577 |
|
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); |
|
1582 |
|
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); |
|
1586 |
|
1587 ASSERT_EQ(0, nr_stun_message_destroy(&msg)); |
|
1588 } |
|
1589 |
|
1590 static std::string get_environment(const char *name) { |
|
1591 char *value = getenv(name); |
|
1592 |
|
1593 if (!value) |
|
1594 return ""; |
|
1595 |
|
1596 return value; |
|
1597 } |
|
1598 |
|
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 |
|
1605 |
|
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"); |
|
1609 |
|
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 } |
|
1618 |
|
1619 std::string tmp = get_environment("STUN_SERVER_ADDRESS"); |
|
1620 if (tmp != "") |
|
1621 g_stun_server_address = tmp; |
|
1622 |
|
1623 |
|
1624 tmp = get_environment("STUN_SERVER_HOSTNAME"); |
|
1625 if (tmp != "") |
|
1626 g_stun_server_hostname = tmp; |
|
1627 |
|
1628 test_utils = new MtransportTestUtils(); |
|
1629 NSS_NoDB_Init(nullptr); |
|
1630 NSS_SetDomesticPolicy(); |
|
1631 |
|
1632 // Start the tests |
|
1633 ::testing::InitGoogleTest(&argc, argv); |
|
1634 |
|
1635 ::testing::TestEventListeners& listeners = |
|
1636 ::testing::UnitTest::GetInstance()->listeners(); |
|
1637 // Adds a listener to the end. Google Test takes the ownership. |
|
1638 |
|
1639 listeners.Append(new test::RingbufferDumper(test_utils)); |
|
1640 test_utils->sts_target()->Dispatch( |
|
1641 WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC); |
|
1642 |
|
1643 int rv = RUN_ALL_TESTS(); |
|
1644 |
|
1645 test_utils->sts_target()->Dispatch( |
|
1646 WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC); |
|
1647 |
|
1648 delete test_utils; |
|
1649 return rv; |
|
1650 } |