OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2009 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2009 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #ifndef WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_ | 11 #ifndef WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_ |
12 #define WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_ | 12 #define WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_ |
13 | 13 |
14 #include <map> | 14 #include <map> |
15 #include <memory> | 15 #include <memory> |
16 #include <string> | 16 #include <string> |
17 #include <vector> | 17 #include <vector> |
18 | 18 |
19 #include "webrtc/p2p/base/candidatepairinterface.h" | |
20 #include "webrtc/p2p/base/transportchannel.h" | |
21 #include "webrtc/p2p/base/transportcontroller.h" | |
22 #include "webrtc/p2p/base/transportchannelimpl.h" | |
23 #include "webrtc/base/bind.h" | 19 #include "webrtc/base/bind.h" |
24 #include "webrtc/base/buffer.h" | 20 #include "webrtc/base/buffer.h" |
25 #include "webrtc/base/fakesslidentity.h" | 21 #include "webrtc/base/fakesslidentity.h" |
26 #include "webrtc/base/messagequeue.h" | 22 #include "webrtc/base/messagequeue.h" |
27 #include "webrtc/base/sigslot.h" | 23 #include "webrtc/base/sigslot.h" |
28 #include "webrtc/base/sslfingerprint.h" | 24 #include "webrtc/base/sslfingerprint.h" |
29 #include "webrtc/base/thread.h" | 25 #include "webrtc/base/thread.h" |
26 #include "webrtc/p2p/base/candidatepairinterface.h" | |
27 #include "webrtc/p2p/base/dtlstransportinternal.h" | |
28 #include "webrtc/p2p/base/transportchannel.h" | |
29 #include "webrtc/p2p/base/transportcontroller.h" | |
30 #include "webrtc/p2p/base/transportchannelimpl.h" | |
30 | 31 |
31 #ifdef HAVE_QUIC | 32 #ifdef HAVE_QUIC |
32 #include "webrtc/p2p/quic/quictransport.h" | 33 #include "webrtc/p2p/quic/quictransport.h" |
33 #endif | 34 #endif |
34 | 35 |
35 namespace cricket { | 36 namespace cricket { |
36 | 37 |
37 namespace { | 38 namespace { |
38 struct PacketMessageData : public rtc::MessageData { | 39 struct PacketMessageData : public rtc::MessageData { |
39 PacketMessageData(const char* data, size_t len) : packet(data, len) {} | 40 PacketMessageData(const char* data, size_t len) : packet(data, len) {} |
40 rtc::Buffer packet; | 41 rtc::Buffer packet; |
41 }; | 42 }; |
42 } // namespace | 43 } // namespace |
43 | 44 |
44 // Fake transport channel class, which can be passed to anything that needs a | 45 // Fake transport channel class, which can be passed to anything that needs a |
45 // transport channel. Can be informed of another FakeTransportChannel via | 46 // transport channel. Can be informed of another FakeTransportChannel via |
46 // SetDestination. | 47 // SetDestination. |
47 // TODO(hbos): Move implementation to .cc file, this and other classes in file. | 48 // TODO(hbos): Move implementation to .cc file, this and other classes in file. |
48 class FakeTransportChannel : public TransportChannelImpl, | 49 class FakeTransportChannel : public TransportChannelImpl, |
Taylor Brandstetter
2017/01/03 23:21:59
Should this be renamed to FakeIceTransport, and in
Zhi Huang
2017/01/10 18:30:51
Done.
| |
49 public rtc::MessageHandler { | 50 public rtc::MessageHandler { |
50 public: | 51 public: |
51 explicit FakeTransportChannel(const std::string& name, int component) | 52 explicit FakeTransportChannel(const std::string& name, int component) |
52 : TransportChannelImpl(name, component), | 53 : TransportChannelImpl(name, component), |
53 dtls_fingerprint_("", nullptr, 0) {} | 54 dtls_fingerprint_("", nullptr, 0) {} |
54 ~FakeTransportChannel() { Reset(); } | 55 ~FakeTransportChannel() { Reset(); } |
55 | 56 |
56 uint64_t IceTiebreaker() const { return tiebreaker_; } | 57 uint64_t IceTiebreaker() const { return tiebreaker_; } |
57 IceMode remote_ice_mode() const { return remote_ice_mode_; } | 58 IceMode remote_ice_mode() const { return remote_ice_mode_; } |
58 const std::string& ice_ufrag() const { return ice_ufrag_; } | 59 const std::string& ice_ufrag() const { return ice_ufrag_; } |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
333 std::string remote_ice_pwd_; | 334 std::string remote_ice_pwd_; |
334 IceMode remote_ice_mode_ = ICEMODE_FULL; | 335 IceMode remote_ice_mode_ = ICEMODE_FULL; |
335 rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; | 336 rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; |
336 rtc::SSLFingerprint dtls_fingerprint_; | 337 rtc::SSLFingerprint dtls_fingerprint_; |
337 rtc::SSLRole ssl_role_ = rtc::SSL_CLIENT; | 338 rtc::SSLRole ssl_role_ = rtc::SSL_CLIENT; |
338 size_t connection_count_ = 0; | 339 size_t connection_count_ = 0; |
339 IceGatheringState gathering_state_ = kIceGatheringNew; | 340 IceGatheringState gathering_state_ = kIceGatheringNew; |
340 bool had_connection_ = false; | 341 bool had_connection_ = false; |
341 }; | 342 }; |
342 | 343 |
344 class FakeDtlsTransport : public DtlsTransportInternal, | |
345 public rtc::MessageHandler { | |
346 public: | |
347 FakeDtlsTransport(FakeTransportChannel* ice_transport) | |
348 : ice_transport_(ice_transport), | |
349 transport_name_(ice_transport->transport_name()), | |
350 component_(ice_transport->component()), | |
351 dtls_fingerprint_("", nullptr, 0) {} | |
352 ~FakeDtlsTransport() { Reset(); } | |
353 | |
354 uint64_t IceTiebreaker() const { return ice_transport_->IceTiebreaker(); } | |
355 IceMode remote_ice_mode() const { return ice_transport_->remote_ice_mode(); } | |
356 const std::string& ice_ufrag() const { return ice_transport_->ice_ufrag(); } | |
357 const std::string& ice_pwd() const { return ice_transport_->ice_pwd(); } | |
358 const std::string& remote_ice_ufrag() const { | |
359 return ice_transport_->remote_ice_ufrag(); | |
360 } | |
361 const std::string& remote_ice_pwd() const { | |
362 return ice_transport_->remote_ice_pwd(); | |
363 } | |
364 | |
365 DtlsTransportState dtls_state() const override { return dtls_state_; } | |
366 | |
367 const std::string& transport_name() const override { return transport_name_; } | |
368 | |
369 int component() const override { return component_; } | |
370 | |
371 const rtc::SSLFingerprint& dtls_fingerprint() const { | |
372 return dtls_fingerprint_; | |
373 } | |
374 | |
375 // If async, will send packets by "Post"-ing to message queue instead of | |
376 // synchronously "Send"-ing. | |
377 void SetAsync(bool async) { async_ = async; } | |
378 void SetAsyncDelay(int delay_ms) { async_delay_ms_ = delay_ms; } | |
Taylor Brandstetter
2017/01/03 23:21:59
I think the async settings only need to go in one
Zhi Huang
2017/01/10 18:30:51
I'll clean up the duplication when merging the two
| |
379 | |
380 IceRole GetIceRole() const { return ice_transport_->GetIceRole(); } | |
381 | |
382 bool SetRemoteFingerprint(const std::string& alg, | |
383 const uint8_t* digest, | |
384 size_t digest_len) override { | |
385 dtls_fingerprint_ = rtc::SSLFingerprint(alg, digest, digest_len); | |
386 return true; | |
387 } | |
388 | |
389 bool SetSslRole(rtc::SSLRole role) override { | |
390 ssl_role_ = role; | |
391 return true; | |
392 } | |
393 | |
394 bool GetSslRole(rtc::SSLRole* role) const override { | |
395 *role = ssl_role_; | |
396 return true; | |
397 } | |
398 | |
399 IceGatheringState gathering_state() const { | |
400 return ice_transport_->gathering_state(); | |
401 } | |
402 | |
403 void Reset() { | |
404 if (state_ != STATE_INIT) { | |
405 state_ = STATE_INIT; | |
406 if (dest_) { | |
407 dest_->state_ = STATE_INIT; | |
408 dest_->dest_ = nullptr; | |
409 dest_ = nullptr; | |
410 } | |
411 } | |
412 } | |
413 | |
414 void SetWritable(bool writable) { | |
415 ice_transport_->SetWritable(writable); | |
416 SignalWritableState(this); | |
417 } | |
418 | |
419 // Simulates the two transport channels connecting to each other. | |
420 // If |asymmetric| is true this method only affects this FakeDtlsTransport. | |
421 // If false, it affects |dest| as well. | |
422 void SetDestination(FakeDtlsTransport* dest, bool asymmetric = false) { | |
423 if (state_ == STATE_INIT && dest) { | |
424 // This simulates the delivery of candidates. | |
425 dest_ = dest; | |
426 if (local_cert_ && dest_->local_cert_) { | |
427 do_dtls_ = true; | |
428 NegotiateSrtpCiphers(); | |
429 } | |
430 state_ = STATE_CONNECTED; | |
431 SetWritable(true); | |
432 if (!asymmetric) { | |
433 dest->SetDestination(this, true); | |
434 } | |
435 } else if (state_ == STATE_CONNECTED && !dest) { | |
436 // Simulates loss of connectivity, by asymmetrically forgetting dest_. | |
437 dest_ = nullptr; | |
438 state_ = STATE_INIT; | |
439 SetWritable(false); | |
440 } | |
441 } | |
442 | |
443 void SetConnectionCount(size_t connection_count) { | |
444 ice_transport_->SetConnectionCount(connection_count); | |
445 } | |
446 | |
447 void SetCandidatesGatheringComplete() { | |
448 ice_transport_->SetCandidatesGatheringComplete(); | |
449 } | |
450 | |
451 void SetReceiving(bool receiving) { | |
452 ice_transport_->SetReceiving(receiving); | |
453 SignalReceivingState(this); | |
454 } | |
455 | |
456 int receiving_timeout() const { return ice_transport_->receiving_timeout(); } | |
457 bool gather_continually() const { | |
458 return ice_transport_->gather_continually(); | |
459 } | |
460 | |
461 int SendPacket(const char* data, | |
462 size_t len, | |
463 const rtc::PacketOptions& options, | |
464 int flags) override { | |
465 if (state_ != STATE_CONNECTED) { | |
466 return -1; | |
467 } | |
468 | |
469 if (flags != PF_SRTP_BYPASS && flags != 0) { | |
470 return -1; | |
471 } | |
472 | |
Taylor Brandstetter
2017/01/03 23:21:59
Can this just call ice_transport_->SendPacket, and
Zhi Huang
2017/01/10 18:30:51
Done.
| |
473 PacketMessageData* packet = new PacketMessageData(data, len); | |
474 if (async_) { | |
475 if (async_delay_ms_) { | |
476 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, async_delay_ms_, | |
477 this, 0, packet); | |
478 } else { | |
479 rtc::Thread::Current()->Post(RTC_FROM_HERE, this, 0, packet); | |
480 } | |
481 } else { | |
482 rtc::Thread::Current()->Send(RTC_FROM_HERE, this, 0, packet); | |
483 } | |
484 rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis()); | |
485 SignalSentPacket(this, sent_packet); | |
486 return static_cast<int>(len); | |
487 } | |
488 | |
489 bool GetOption(rtc::Socket::Option opt, int* value) override { return true; } | |
490 | |
491 const Candidates& remote_candidates() const { | |
492 return ice_transport_->remote_candidates(); | |
493 } | |
494 | |
495 void OnMessage(rtc::Message* msg) override { | |
496 PacketMessageData* data = static_cast<PacketMessageData*>(msg->pdata); | |
497 dest_->SignalReadPacket(dest_, data->packet.data<char>(), | |
498 data->packet.size(), rtc::CreatePacketTime(0), 0); | |
499 delete data; | |
500 } | |
501 | |
502 bool SetLocalCertificate( | |
503 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override { | |
504 local_cert_ = certificate; | |
505 return true; | |
506 } | |
507 | |
508 void SetRemoteSSLCertificate(rtc::FakeSSLCertificate* cert) { | |
509 remote_cert_ = cert; | |
510 } | |
511 | |
512 bool IsDtlsActive() const override { return do_dtls_; } | |
513 | |
514 bool SetSrtpCryptoSuites(const std::vector<int>& ciphers) override { | |
515 srtp_ciphers_ = ciphers; | |
516 return true; | |
517 } | |
518 | |
519 bool GetSrtpCryptoSuite(int* crypto_suite) override { | |
520 if (chosen_crypto_suite_ != rtc::SRTP_INVALID_CRYPTO_SUITE) { | |
521 *crypto_suite = chosen_crypto_suite_; | |
522 return true; | |
523 } | |
524 return false; | |
525 } | |
526 | |
527 bool GetSslCipherSuite(int* cipher_suite) override { return false; } | |
528 | |
529 rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override { | |
530 return local_cert_; | |
531 } | |
532 | |
533 std::unique_ptr<rtc::SSLCertificate> GetRemoteSSLCertificate() | |
534 const override { | |
535 return remote_cert_ ? std::unique_ptr<rtc::SSLCertificate>( | |
536 remote_cert_->GetReference()) | |
537 : nullptr; | |
538 } | |
539 | |
540 bool ExportKeyingMaterial(const std::string& label, | |
541 const uint8_t* context, | |
542 size_t context_len, | |
543 bool use_context, | |
544 uint8_t* result, | |
545 size_t result_len) override { | |
546 if (chosen_crypto_suite_ != rtc::SRTP_INVALID_CRYPTO_SUITE) { | |
547 memset(result, 0xff, result_len); | |
548 return true; | |
549 } | |
550 | |
551 return false; | |
552 } | |
553 | |
554 void set_ssl_max_protocol_version(rtc::SSLProtocolVersion version) { | |
555 ssl_max_version_ = version; | |
556 } | |
557 rtc::SSLProtocolVersion ssl_max_protocol_version() const { | |
558 return ssl_max_version_; | |
559 } | |
560 | |
561 TransportChannelImpl* ice_transport() override { return ice_transport_; } | |
562 | |
563 bool writable() const override { return ice_transport_->writable(); } | |
564 | |
565 bool receiving() const override { return ice_transport_->receiving(); } | |
566 | |
567 int GetError() override { return ice_transport_->GetError(); } | |
568 | |
569 int SetOption(rtc::Socket::Option opt, int value) override { | |
570 return ice_transport_->SetOption(opt, value); | |
571 } | |
572 | |
573 bool SetSrtpCiphers(const std::vector<std::string>& ciphers) override { | |
574 std::vector<int> crypto_suites; | |
575 for (const auto cipher : ciphers) { | |
576 crypto_suites.push_back(rtc::SrtpCryptoSuiteFromName(cipher)); | |
577 } | |
578 return SetSrtpCryptoSuites(crypto_suites); | |
579 } | |
580 | |
581 private: | |
582 void NegotiateSrtpCiphers() { | |
583 for (std::vector<int>::const_iterator it1 = srtp_ciphers_.begin(); | |
584 it1 != srtp_ciphers_.end(); ++it1) { | |
585 for (std::vector<int>::const_iterator it2 = dest_->srtp_ciphers_.begin(); | |
586 it2 != dest_->srtp_ciphers_.end(); ++it2) { | |
587 if (*it1 == *it2) { | |
588 chosen_crypto_suite_ = *it1; | |
589 return; | |
590 } | |
591 } | |
592 } | |
593 } | |
594 | |
595 enum State { STATE_INIT, STATE_CONNECTED }; | |
596 FakeTransportChannel* ice_transport_; | |
597 std::string transport_name_; | |
598 int component_; | |
599 FakeDtlsTransport* dest_ = nullptr; | |
600 State state_ = STATE_INIT; | |
601 bool async_ = false; | |
602 int async_delay_ms_ = 0; | |
603 Candidates remote_candidates_; | |
604 rtc::scoped_refptr<rtc::RTCCertificate> local_cert_; | |
605 rtc::FakeSSLCertificate* remote_cert_ = nullptr; | |
606 bool do_dtls_ = false; | |
607 std::vector<int> srtp_ciphers_; | |
608 int chosen_crypto_suite_ = rtc::SRTP_INVALID_CRYPTO_SUITE; | |
609 rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; | |
610 rtc::SSLFingerprint dtls_fingerprint_; | |
611 rtc::SSLRole ssl_role_ = rtc::SSL_CLIENT; | |
612 | |
613 DtlsTransportState dtls_state_ = DTLS_TRANSPORT_NEW; | |
614 }; | |
615 | |
343 // Fake candidate pair class, which can be passed to BaseChannel for testing | 616 // Fake candidate pair class, which can be passed to BaseChannel for testing |
344 // purposes. | 617 // purposes. |
345 class FakeCandidatePair : public CandidatePairInterface { | 618 class FakeCandidatePair : public CandidatePairInterface { |
346 public: | 619 public: |
347 FakeCandidatePair(const Candidate& local_candidate, | 620 FakeCandidatePair(const Candidate& local_candidate, |
348 const Candidate& remote_candidate) | 621 const Candidate& remote_candidate) |
349 : local_candidate_(local_candidate), | 622 : local_candidate_(local_candidate), |
350 remote_candidate_(remote_candidate) {} | 623 remote_candidate_(remote_candidate) {} |
351 const Candidate& local_candidate() const override { return local_candidate_; } | 624 const Candidate& local_candidate() const override { return local_candidate_; } |
352 const Candidate& remote_candidate() const override { | 625 const Candidate& remote_candidate() const override { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
385 } | 658 } |
386 | 659 |
387 explicit FakeTransportController(rtc::Thread* network_thread) | 660 explicit FakeTransportController(rtc::Thread* network_thread) |
388 : TransportController(rtc::Thread::Current(), network_thread, nullptr) {} | 661 : TransportController(rtc::Thread::Current(), network_thread, nullptr) {} |
389 | 662 |
390 FakeTransportController(rtc::Thread* network_thread, IceRole role) | 663 FakeTransportController(rtc::Thread* network_thread, IceRole role) |
391 : TransportController(rtc::Thread::Current(), network_thread, nullptr) { | 664 : TransportController(rtc::Thread::Current(), network_thread, nullptr) { |
392 SetIceRole(role); | 665 SetIceRole(role); |
393 } | 666 } |
394 | 667 |
395 FakeTransportChannel* GetFakeTransportChannel_n( | 668 FakeDtlsTransport* GetFakeDtlsTransport_n(const std::string& transport_name, |
396 const std::string& transport_name, | 669 int component) { |
397 int component) { | 670 return static_cast<FakeDtlsTransport*>( |
398 return static_cast<FakeTransportChannel*>( | |
399 get_channel_for_testing(transport_name, component)); | 671 get_channel_for_testing(transport_name, component)); |
400 } | 672 } |
401 | 673 |
402 // Simulate the exchange of transport descriptions, and the gathering and | 674 // Simulate the exchange of transport descriptions, and the gathering and |
403 // exchange of ICE candidates. | 675 // exchange of ICE candidates. |
404 void Connect(FakeTransportController* dest) { | 676 void Connect(FakeTransportController* dest) { |
405 for (const std::string& transport_name : transport_names_for_testing()) { | 677 for (const std::string& transport_name : transport_names_for_testing()) { |
406 TransportDescription local_desc( | 678 TransportDescription local_desc( |
407 std::vector<std::string>(), | 679 std::vector<std::string>(), |
408 rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH), | 680 rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH), |
(...skipping 30 matching lines...) Expand all Loading... | |
439 Candidate local_candidate(0, "udp", local_address, 0u, "", "", "local", 0, | 711 Candidate local_candidate(0, "udp", local_address, 0u, "", "", "local", 0, |
440 "foundation", local_network_id, 0); | 712 "foundation", local_network_id, 0); |
441 Candidate remote_candidate(0, "udp", remote_address, 0u, "", "", "local", 0, | 713 Candidate remote_candidate(0, "udp", remote_address, 0u, "", "", "local", 0, |
442 "foundation", remote_network_id, 0); | 714 "foundation", remote_network_id, 0); |
443 return new FakeCandidatePair(local_candidate, remote_candidate); | 715 return new FakeCandidatePair(local_candidate, remote_candidate); |
444 } | 716 } |
445 | 717 |
446 protected: | 718 protected: |
447 // The ICE channel is never actually used by TransportController directly, | 719 // The ICE channel is never actually used by TransportController directly, |
448 // since (currently) the DTLS channel pretends to be both ICE + DTLS. This | 720 // since (currently) the DTLS channel pretends to be both ICE + DTLS. This |
449 // will change when we get rid of TransportChannelImpl. | 721 // will change when we get rid of TransportChannelImpl. |
Taylor Brandstetter
2017/01/03 23:21:59
Should update this comment.
| |
450 TransportChannelImpl* CreateIceTransportChannel_n( | 722 TransportChannelImpl* CreateIceTransportChannel_n( |
451 const std::string& transport_name, | 723 const std::string& transport_name, |
452 int component) override { | 724 int component) override { |
453 return nullptr; | 725 return new FakeTransportChannel(transport_name, component); |
454 } | 726 } |
455 | 727 |
456 TransportChannelImpl* CreateDtlsTransportChannel_n( | 728 DtlsTransportInternal* CreateDtlsTransportChannel_n( |
457 const std::string& transport_name, | 729 const std::string& transport_name, |
458 int component, | 730 int component, |
459 TransportChannelImpl*) override { | 731 TransportChannelImpl* ice) override { |
460 return new FakeTransportChannel(transport_name, component); | 732 return new FakeDtlsTransport(static_cast<FakeTransportChannel*>(ice)); |
461 } | 733 } |
462 | 734 |
463 private: | 735 private: |
464 void SetChannelDestinations_n(FakeTransportController* dest) { | 736 void SetChannelDestinations_n(FakeTransportController* dest) { |
465 for (TransportChannelImpl* tc : channels_for_testing()) { | 737 for (DtlsTransportInternal* tc : channels_for_testing()) { |
466 FakeTransportChannel* local = static_cast<FakeTransportChannel*>(tc); | 738 FakeDtlsTransport* local = static_cast<FakeDtlsTransport*>(tc); |
467 FakeTransportChannel* remote = dest->GetFakeTransportChannel_n( | 739 FakeDtlsTransport* remote = dest->GetFakeDtlsTransport_n( |
468 local->transport_name(), local->component()); | 740 local->transport_name(), local->component()); |
469 if (remote) { | 741 if (remote) { |
470 bool asymmetric = false; | 742 bool asymmetric = false; |
471 local->SetDestination(remote, asymmetric); | 743 local->SetDestination(remote, asymmetric); |
472 } | 744 } |
473 } | 745 } |
474 } | 746 } |
475 }; | 747 }; |
476 | 748 |
477 } // namespace cricket | 749 } // namespace cricket |
478 | 750 |
479 #endif // WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_ | 751 #endif // WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_ |
OLD | NEW |