| /* | 
 |  *  Copyright 2012 The WebRTC Project Authors. All rights reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 | #if defined(WEBRTC_POSIX) | 
 | #include <dirent.h> | 
 | #endif | 
 |  | 
 | #include <list> | 
 | #include <memory> | 
 | #include <utility> | 
 | #include <vector> | 
 |  | 
 | #include "absl/types/optional.h" | 
 | #include "api/units/time_delta.h" | 
 | #include "p2p/base/basic_packet_socket_factory.h" | 
 | #include "p2p/base/connection.h" | 
 | #include "p2p/base/p2p_constants.h" | 
 | #include "p2p/base/port_allocator.h" | 
 | #include "p2p/base/stun_port.h" | 
 | #include "p2p/base/test_turn_customizer.h" | 
 | #include "p2p/base/test_turn_server.h" | 
 | #include "p2p/base/transport_description.h" | 
 | #include "p2p/base/turn_port.h" | 
 | #include "p2p/base/turn_server.h" | 
 | #include "rtc_base/async_socket.h" | 
 | #include "rtc_base/buffer.h" | 
 | #include "rtc_base/byte_buffer.h" | 
 | #include "rtc_base/checks.h" | 
 | #include "rtc_base/fake_clock.h" | 
 | #include "rtc_base/gunit.h" | 
 | #include "rtc_base/location.h" | 
 | #include "rtc_base/message_handler.h" | 
 | #include "rtc_base/net_helper.h" | 
 | #include "rtc_base/socket_address.h" | 
 | #include "rtc_base/thread.h" | 
 | #include "rtc_base/time_utils.h" | 
 | #include "rtc_base/virtual_socket_server.h" | 
 | #include "test/field_trial.h" | 
 | #include "test/gtest.h" | 
 |  | 
 | using rtc::SocketAddress; | 
 |  | 
 | static const SocketAddress kLocalAddr1("11.11.11.11", 0); | 
 | static const SocketAddress kLocalAddr2("22.22.22.22", 0); | 
 | static const SocketAddress kLocalIPv6Addr("2401:fa00:4:1000:be30:5bff:fee5:c3", | 
 |                                           0); | 
 | static const SocketAddress kLocalIPv6Addr2("2401:fa00:4:2000:be30:5bff:fee5:d4", | 
 |                                            0); | 
 | static const SocketAddress kTurnUdpIntAddr("99.99.99.3", | 
 |                                            cricket::TURN_SERVER_PORT); | 
 | static const SocketAddress kTurnTcpIntAddr("99.99.99.4", | 
 |                                            cricket::TURN_SERVER_PORT); | 
 | static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0); | 
 | static const SocketAddress kTurnAlternateIntAddr("99.99.99.6", | 
 |                                                  cricket::TURN_SERVER_PORT); | 
 | // Port for redirecting to a TCP Web server. Should not work. | 
 | static const SocketAddress kTurnDangerousAddr("99.99.99.7", 81); | 
 | // Port 53 (the DNS port); should work. | 
 | static const SocketAddress kTurnPort53Addr("99.99.99.7", 53); | 
 | // Port 80 (the HTTP port); should work. | 
 | static const SocketAddress kTurnPort80Addr("99.99.99.7", 80); | 
 | // Port 443 (the HTTPS port); should work. | 
 | static const SocketAddress kTurnPort443Addr("99.99.99.7", 443); | 
 | // The default TURN server port. | 
 | static const SocketAddress kTurnIntAddr("99.99.99.7", | 
 |                                         cricket::TURN_SERVER_PORT); | 
 | static const SocketAddress kTurnIPv6IntAddr( | 
 |     "2400:4030:2:2c00:be30:abcd:efab:cdef", | 
 |     cricket::TURN_SERVER_PORT); | 
 | static const SocketAddress kTurnUdpIPv6IntAddr( | 
 |     "2400:4030:1:2c00:be30:abcd:efab:cdef", | 
 |     cricket::TURN_SERVER_PORT); | 
 | static const SocketAddress kTurnInvalidAddr("www.google.invalid", 3478); | 
 |  | 
 | static const char kCandidateFoundation[] = "foundation"; | 
 | static const char kIceUfrag1[] = "TESTICEUFRAG0001"; | 
 | static const char kIceUfrag2[] = "TESTICEUFRAG0002"; | 
 | static const char kIcePwd1[] = "TESTICEPWD00000000000001"; | 
 | static const char kIcePwd2[] = "TESTICEPWD00000000000002"; | 
 | static const char kTurnUsername[] = "test"; | 
 | static const char kTurnPassword[] = "test"; | 
 | static const char kTestOrigin[] = "http://example.com"; | 
 | // This test configures the virtual socket server to simulate delay so that we | 
 | // can verify operations take no more than the expected number of round trips. | 
 | static constexpr unsigned int kSimulatedRtt = 50; | 
 | // Connection destruction may happen asynchronously, but it should only | 
 | // take one simulated clock tick. | 
 | static constexpr unsigned int kConnectionDestructionDelay = 1; | 
 | // This used to be 1 second, but that's not always enough for getaddrinfo(). | 
 | // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=5191 | 
 | static constexpr unsigned int kResolverTimeout = 10000; | 
 |  | 
 | static const cricket::ProtocolAddress kTurnUdpProtoAddr(kTurnUdpIntAddr, | 
 |                                                         cricket::PROTO_UDP); | 
 | static const cricket::ProtocolAddress kTurnTcpProtoAddr(kTurnTcpIntAddr, | 
 |                                                         cricket::PROTO_TCP); | 
 | static const cricket::ProtocolAddress kTurnTlsProtoAddr(kTurnTcpIntAddr, | 
 |                                                         cricket::PROTO_TLS); | 
 | static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr(kTurnUdpIPv6IntAddr, | 
 |                                                             cricket::PROTO_UDP); | 
 | static const cricket::ProtocolAddress kTurnDangerousProtoAddr( | 
 |     kTurnDangerousAddr, | 
 |     cricket::PROTO_TCP); | 
 | static const cricket::ProtocolAddress kTurnPort53ProtoAddr(kTurnPort53Addr, | 
 |                                                            cricket::PROTO_TCP); | 
 | static const cricket::ProtocolAddress kTurnPort80ProtoAddr(kTurnPort80Addr, | 
 |                                                            cricket::PROTO_TCP); | 
 | static const cricket::ProtocolAddress kTurnPort443ProtoAddr(kTurnPort443Addr, | 
 |                                                             cricket::PROTO_TCP); | 
 |  | 
 | static const unsigned int MSG_TESTFINISH = 0; | 
 |  | 
 | #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) | 
 | static int GetFDCount() { | 
 |   struct dirent* dp; | 
 |   int fd_count = 0; | 
 |   DIR* dir = opendir("/proc/self/fd/"); | 
 |   while ((dp = readdir(dir)) != NULL) { | 
 |     if (dp->d_name[0] == '.') | 
 |       continue; | 
 |     ++fd_count; | 
 |   } | 
 |   closedir(dir); | 
 |   return fd_count; | 
 | } | 
 | #endif | 
 |  | 
 | namespace cricket { | 
 |  | 
 | class TurnPortTestVirtualSocketServer : public rtc::VirtualSocketServer { | 
 |  public: | 
 |   TurnPortTestVirtualSocketServer() { | 
 |     // This configures the virtual socket server to always add a simulated | 
 |     // delay of exactly half of kSimulatedRtt. | 
 |     set_delay_mean(kSimulatedRtt / 2); | 
 |     UpdateDelayDistribution(); | 
 |   } | 
 |  | 
 |   using rtc::VirtualSocketServer::LookupBinding; | 
 | }; | 
 |  | 
 | class TestConnectionWrapper : public sigslot::has_slots<> { | 
 |  public: | 
 |   explicit TestConnectionWrapper(Connection* conn) : connection_(conn) { | 
 |     conn->SignalDestroyed.connect( | 
 |         this, &TestConnectionWrapper::OnConnectionDestroyed); | 
 |   } | 
 |  | 
 |   Connection* connection() { return connection_; } | 
 |  | 
 |  private: | 
 |   void OnConnectionDestroyed(Connection* conn) { | 
 |     ASSERT_TRUE(conn == connection_); | 
 |     connection_ = nullptr; | 
 |   } | 
 |  | 
 |   Connection* connection_; | 
 | }; | 
 |  | 
 | // Note: This test uses a fake clock with a simulated network round trip | 
 | // (between local port and TURN server) of kSimulatedRtt. | 
 | class TurnPortTest : public ::testing::Test, | 
 |                      public sigslot::has_slots<>, | 
 |                      public rtc::MessageHandlerAutoCleanup { | 
 |  public: | 
 |   TurnPortTest() | 
 |       : ss_(new TurnPortTestVirtualSocketServer()), | 
 |         main_(ss_.get()), | 
 |         socket_factory_(rtc::Thread::Current()), | 
 |         turn_server_(&main_, kTurnUdpIntAddr, kTurnUdpExtAddr), | 
 |         turn_ready_(false), | 
 |         turn_error_(false), | 
 |         turn_unknown_address_(false), | 
 |         turn_create_permission_success_(false), | 
 |         turn_port_closed_(false), | 
 |         turn_port_destroyed_(false), | 
 |         udp_ready_(false), | 
 |         test_finish_(false) { | 
 |     // Some code uses "last received time == 0" to represent "nothing received | 
 |     // so far", so we need to start the fake clock at a nonzero time... | 
 |     // TODO(deadbeef): Fix this. | 
 |     fake_clock_.AdvanceTime(webrtc::TimeDelta::Seconds(1)); | 
 |   } | 
 |  | 
 |   virtual void OnMessage(rtc::Message* msg) { | 
 |     RTC_CHECK(msg->message_id == MSG_TESTFINISH); | 
 |     if (msg->message_id == MSG_TESTFINISH) | 
 |       test_finish_ = true; | 
 |   } | 
 |  | 
 |   void OnTurnPortComplete(Port* port) { turn_ready_ = true; } | 
 |   void OnTurnPortError(Port* port) { turn_error_ = true; } | 
 |   void OnCandidateError(Port* port, | 
 |                         const cricket::IceCandidateErrorEvent& event) { | 
 |     error_event_ = event; | 
 |   } | 
 |   void OnTurnUnknownAddress(PortInterface* port, | 
 |                             const SocketAddress& addr, | 
 |                             ProtocolType proto, | 
 |                             IceMessage* msg, | 
 |                             const std::string& rf, | 
 |                             bool /*port_muxed*/) { | 
 |     turn_unknown_address_ = true; | 
 |   } | 
 |   void OnTurnCreatePermissionResult(TurnPort* port, | 
 |                                     const SocketAddress& addr, | 
 |                                     int code) { | 
 |     // Ignoring the address. | 
 |     turn_create_permission_success_ = (code == 0); | 
 |   } | 
 |  | 
 |   void OnTurnRefreshResult(TurnPort* port, int code) { | 
 |     turn_refresh_success_ = (code == 0); | 
 |   } | 
 |   void OnTurnReadPacket(Connection* conn, | 
 |                         const char* data, | 
 |                         size_t size, | 
 |                         int64_t packet_time_us) { | 
 |     turn_packets_.push_back(rtc::Buffer(data, size)); | 
 |   } | 
 |   void OnUdpPortComplete(Port* port) { udp_ready_ = true; } | 
 |   void OnUdpReadPacket(Connection* conn, | 
 |                        const char* data, | 
 |                        size_t size, | 
 |                        int64_t packet_time_us) { | 
 |     udp_packets_.push_back(rtc::Buffer(data, size)); | 
 |   } | 
 |   void OnSocketReadPacket(rtc::AsyncPacketSocket* socket, | 
 |                           const char* data, | 
 |                           size_t size, | 
 |                           const rtc::SocketAddress& remote_addr, | 
 |                           const int64_t& packet_time_us) { | 
 |     turn_port_->HandleIncomingPacket(socket, data, size, remote_addr, | 
 |                                      packet_time_us); | 
 |   } | 
 |   void OnTurnPortClosed(TurnPort* port) { turn_port_closed_ = true; } | 
 |   void OnTurnPortDestroyed(PortInterface* port) { turn_port_destroyed_ = true; } | 
 |  | 
 |   rtc::AsyncSocket* CreateServerSocket(const SocketAddress addr) { | 
 |     rtc::AsyncSocket* socket = ss_->CreateAsyncSocket(AF_INET, SOCK_STREAM); | 
 |     EXPECT_GE(socket->Bind(addr), 0); | 
 |     EXPECT_GE(socket->Listen(5), 0); | 
 |     return socket; | 
 |   } | 
 |  | 
 |   rtc::Network* MakeNetwork(const SocketAddress& addr) { | 
 |     networks_.emplace_back("unittest", "unittest", addr.ipaddr(), 32); | 
 |     networks_.back().AddIP(addr.ipaddr()); | 
 |     return &networks_.back(); | 
 |   } | 
 |  | 
 |   bool CreateTurnPort(const std::string& username, | 
 |                       const std::string& password, | 
 |                       const ProtocolAddress& server_address) { | 
 |     return CreateTurnPortWithAllParams(MakeNetwork(kLocalAddr1), username, | 
 |                                        password, server_address, std::string()); | 
 |   } | 
 |   bool CreateTurnPort(const rtc::SocketAddress& local_address, | 
 |                       const std::string& username, | 
 |                       const std::string& password, | 
 |                       const ProtocolAddress& server_address) { | 
 |     return CreateTurnPortWithAllParams(MakeNetwork(local_address), username, | 
 |                                        password, server_address, std::string()); | 
 |   } | 
 |  | 
 |   // Should be identical to CreateTurnPort but specifies an origin value | 
 |   // when creating the instance of TurnPort. | 
 |   bool CreateTurnPortWithOrigin(const rtc::SocketAddress& local_address, | 
 |                                 const std::string& username, | 
 |                                 const std::string& password, | 
 |                                 const ProtocolAddress& server_address, | 
 |                                 const std::string& origin) { | 
 |     return CreateTurnPortWithAllParams(MakeNetwork(local_address), username, | 
 |                                        password, server_address, origin); | 
 |   } | 
 |  | 
 |   bool CreateTurnPortWithNetwork(rtc::Network* network, | 
 |                                  const std::string& username, | 
 |                                  const std::string& password, | 
 |                                  const ProtocolAddress& server_address) { | 
 |     return CreateTurnPortWithAllParams(network, username, password, | 
 |                                        server_address, std::string()); | 
 |   } | 
 |  | 
 |   // Version of CreateTurnPort that takes all possible parameters; all other | 
 |   // helper methods call this, such that "SetIceRole" and "ConnectSignals" (and | 
 |   // possibly other things in the future) only happen in one place. | 
 |   bool CreateTurnPortWithAllParams(rtc::Network* network, | 
 |                                    const std::string& username, | 
 |                                    const std::string& password, | 
 |                                    const ProtocolAddress& server_address, | 
 |                                    const std::string& origin) { | 
 |     RelayCredentials credentials(username, password); | 
 |     turn_port_ = TurnPort::Create( | 
 |         &main_, &socket_factory_, network, 0, 0, kIceUfrag1, kIcePwd1, | 
 |         server_address, credentials, 0, origin, {}, {}, turn_customizer_.get()); | 
 |     if (!turn_port_) { | 
 |       return false; | 
 |     } | 
 |     // This TURN port will be the controlling. | 
 |     turn_port_->SetIceRole(ICEROLE_CONTROLLING); | 
 |     ConnectSignals(); | 
 |  | 
 |     if (server_address.proto == cricket::PROTO_TLS) { | 
 |       // The test TURN server has a self-signed certificate so will not pass | 
 |       // the normal client validation. Instruct the client to ignore certificate | 
 |       // errors for testing only. | 
 |       turn_port_->SetTlsCertPolicy( | 
 |           TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK); | 
 |     } | 
 |     return true; | 
 |   } | 
 |  | 
 |   void CreateSharedTurnPort(const std::string& username, | 
 |                             const std::string& password, | 
 |                             const ProtocolAddress& server_address) { | 
 |     RTC_CHECK(server_address.proto == PROTO_UDP); | 
 |  | 
 |     if (!socket_) { | 
 |       socket_.reset(socket_factory_.CreateUdpSocket( | 
 |           rtc::SocketAddress(kLocalAddr1.ipaddr(), 0), 0, 0)); | 
 |       ASSERT_TRUE(socket_ != NULL); | 
 |       socket_->SignalReadPacket.connect(this, | 
 |                                         &TurnPortTest::OnSocketReadPacket); | 
 |     } | 
 |  | 
 |     RelayCredentials credentials(username, password); | 
 |     turn_port_ = | 
 |         TurnPort::Create(&main_, &socket_factory_, MakeNetwork(kLocalAddr1), | 
 |                          socket_.get(), kIceUfrag1, kIcePwd1, server_address, | 
 |                          credentials, 0, std::string(), nullptr); | 
 |     // This TURN port will be the controlling. | 
 |     turn_port_->SetIceRole(ICEROLE_CONTROLLING); | 
 |     ConnectSignals(); | 
 |   } | 
 |  | 
 |   void ConnectSignals() { | 
 |     turn_port_->SignalPortComplete.connect(this, | 
 |                                            &TurnPortTest::OnTurnPortComplete); | 
 |     turn_port_->SignalPortError.connect(this, &TurnPortTest::OnTurnPortError); | 
 |     turn_port_->SignalCandidateError.connect(this, | 
 |                                              &TurnPortTest::OnCandidateError); | 
 |     turn_port_->SignalUnknownAddress.connect( | 
 |         this, &TurnPortTest::OnTurnUnknownAddress); | 
 |     turn_port_->SignalCreatePermissionResult.connect( | 
 |         this, &TurnPortTest::OnTurnCreatePermissionResult); | 
 |     turn_port_->SignalTurnRefreshResult.connect( | 
 |         this, &TurnPortTest::OnTurnRefreshResult); | 
 |     turn_port_->SignalTurnPortClosed.connect(this, | 
 |                                              &TurnPortTest::OnTurnPortClosed); | 
 |     turn_port_->SubscribePortDestroyed( | 
 |         [this](PortInterface* port) { OnTurnPortDestroyed(port); }); | 
 |   } | 
 |  | 
 |   void CreateUdpPort() { CreateUdpPort(kLocalAddr2); } | 
 |  | 
 |   void CreateUdpPort(const SocketAddress& address) { | 
 |     udp_port_ = UDPPort::Create(&main_, &socket_factory_, MakeNetwork(address), | 
 |                                 0, 0, kIceUfrag2, kIcePwd2, std::string(), | 
 |                                 false, absl::nullopt); | 
 |     // UDP port will be controlled. | 
 |     udp_port_->SetIceRole(ICEROLE_CONTROLLED); | 
 |     udp_port_->SignalPortComplete.connect(this, | 
 |                                           &TurnPortTest::OnUdpPortComplete); | 
 |   } | 
 |  | 
 |   void PrepareTurnAndUdpPorts(ProtocolType protocol_type) { | 
 |     // turn_port_ should have been created. | 
 |     ASSERT_TRUE(turn_port_ != nullptr); | 
 |     turn_port_->PrepareAddress(); | 
 |     ASSERT_TRUE_SIMULATED_WAIT( | 
 |         turn_ready_, TimeToGetTurnCandidate(protocol_type), fake_clock_); | 
 |  | 
 |     CreateUdpPort(); | 
 |     udp_port_->PrepareAddress(); | 
 |     ASSERT_TRUE_SIMULATED_WAIT(udp_ready_, kSimulatedRtt, fake_clock_); | 
 |   } | 
 |  | 
 |   // Returns the fake clock time to establish a connection over the given | 
 |   // protocol. | 
 |   int TimeToConnect(ProtocolType protocol_type) { | 
 |     switch (protocol_type) { | 
 |       case PROTO_TCP: | 
 |         // The virtual socket server will delay by a fixed half a round trip | 
 |         // for a TCP connection. | 
 |         return kSimulatedRtt / 2; | 
 |       case PROTO_TLS: | 
 |         // TLS operates over TCP and additionally has a round of HELLO for | 
 |         // negotiating ciphers and a round for exchanging certificates. | 
 |         return 2 * kSimulatedRtt + TimeToConnect(PROTO_TCP); | 
 |       case PROTO_UDP: | 
 |       default: | 
 |         // UDP requires no round trips to set up the connection. | 
 |         return 0; | 
 |     } | 
 |   } | 
 |  | 
 |   // Returns the total fake clock time to establish a connection with a TURN | 
 |   // server over the given protocol and to allocate a TURN candidate. | 
 |   int TimeToGetTurnCandidate(ProtocolType protocol_type) { | 
 |     // For a simple allocation, the first Allocate message will return with an | 
 |     // error asking for credentials and will succeed after the second Allocate | 
 |     // message. | 
 |     return 2 * kSimulatedRtt + TimeToConnect(protocol_type); | 
 |   } | 
 |  | 
 |   // Total fake clock time to do the following: | 
 |   // 1. Connect to primary TURN server | 
 |   // 2. Send Allocate and receive a redirect from the primary TURN server | 
 |   // 3. Connect to alternate TURN server | 
 |   // 4. Send Allocate and receive a request for credentials | 
 |   // 5. Send Allocate with credentials and receive allocation | 
 |   int TimeToGetAlternateTurnCandidate(ProtocolType protocol_type) { | 
 |     return 3 * kSimulatedRtt + 2 * TimeToConnect(protocol_type); | 
 |   } | 
 |  | 
 |   bool CheckConnectionFailedAndPruned(Connection* conn) { | 
 |     return conn && !conn->active() && | 
 |            conn->state() == IceCandidatePairState::FAILED; | 
 |   } | 
 |  | 
 |   // Checks that |turn_port_| has a nonempty set of connections and they are all | 
 |   // failed and pruned. | 
 |   bool CheckAllConnectionsFailedAndPruned() { | 
 |     auto& connections = turn_port_->connections(); | 
 |     if (connections.empty()) { | 
 |       return false; | 
 |     } | 
 |     for (const auto& kv : connections) { | 
 |       if (!CheckConnectionFailedAndPruned(kv.second)) { | 
 |         return false; | 
 |       } | 
 |     } | 
 |     return true; | 
 |   } | 
 |  | 
 |   void TestReconstructedServerUrl(ProtocolType protocol_type, | 
 |                                   const char* expected_url) { | 
 |     turn_port_->PrepareAddress(); | 
 |     ASSERT_TRUE_SIMULATED_WAIT( | 
 |         turn_ready_, TimeToGetTurnCandidate(protocol_type), fake_clock_); | 
 |     ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |     EXPECT_EQ(turn_port_->Candidates()[0].url(), expected_url); | 
 |   } | 
 |  | 
 |   void TestTurnAlternateServer(ProtocolType protocol_type) { | 
 |     std::vector<rtc::SocketAddress> redirect_addresses; | 
 |     redirect_addresses.push_back(kTurnAlternateIntAddr); | 
 |  | 
 |     TestTurnRedirector redirector(redirect_addresses); | 
 |  | 
 |     turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type); | 
 |     turn_server_.AddInternalSocket(kTurnAlternateIntAddr, protocol_type); | 
 |     turn_server_.set_redirect_hook(&redirector); | 
 |     CreateTurnPort(kTurnUsername, kTurnPassword, | 
 |                    ProtocolAddress(kTurnIntAddr, protocol_type)); | 
 |  | 
 |     // Retrieve the address before we run the state machine. | 
 |     const SocketAddress old_addr = turn_port_->server_address().address; | 
 |  | 
 |     turn_port_->PrepareAddress(); | 
 |     EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, | 
 |                                TimeToGetAlternateTurnCandidate(protocol_type), | 
 |                                fake_clock_); | 
 |     // Retrieve the address again, the turn port's address should be | 
 |     // changed. | 
 |     const SocketAddress new_addr = turn_port_->server_address().address; | 
 |     EXPECT_NE(old_addr, new_addr); | 
 |     ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |     EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), | 
 |               turn_port_->Candidates()[0].address().ipaddr()); | 
 |     EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); | 
 |   } | 
 |  | 
 |   void TestTurnAlternateServerV4toV6(ProtocolType protocol_type) { | 
 |     std::vector<rtc::SocketAddress> redirect_addresses; | 
 |     redirect_addresses.push_back(kTurnIPv6IntAddr); | 
 |  | 
 |     TestTurnRedirector redirector(redirect_addresses); | 
 |     turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type); | 
 |     turn_server_.set_redirect_hook(&redirector); | 
 |     CreateTurnPort(kTurnUsername, kTurnPassword, | 
 |                    ProtocolAddress(kTurnIntAddr, protocol_type)); | 
 |     turn_port_->PrepareAddress(); | 
 |     // Need time to connect to TURN server, send Allocate request and receive | 
 |     // redirect notice. | 
 |     EXPECT_TRUE_SIMULATED_WAIT( | 
 |         turn_error_, kSimulatedRtt + TimeToConnect(protocol_type), fake_clock_); | 
 |   } | 
 |  | 
 |   void TestTurnAlternateServerPingPong(ProtocolType protocol_type) { | 
 |     std::vector<rtc::SocketAddress> redirect_addresses; | 
 |     redirect_addresses.push_back(kTurnAlternateIntAddr); | 
 |     redirect_addresses.push_back(kTurnIntAddr); | 
 |  | 
 |     TestTurnRedirector redirector(redirect_addresses); | 
 |  | 
 |     turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type); | 
 |     turn_server_.AddInternalSocket(kTurnAlternateIntAddr, protocol_type); | 
 |     turn_server_.set_redirect_hook(&redirector); | 
 |     CreateTurnPort(kTurnUsername, kTurnPassword, | 
 |                    ProtocolAddress(kTurnIntAddr, protocol_type)); | 
 |  | 
 |     turn_port_->PrepareAddress(); | 
 |     EXPECT_TRUE_SIMULATED_WAIT(turn_error_, | 
 |                                TimeToGetAlternateTurnCandidate(protocol_type), | 
 |                                fake_clock_); | 
 |     ASSERT_EQ(0U, turn_port_->Candidates().size()); | 
 |     rtc::SocketAddress address; | 
 |     // Verify that we have exhausted all alternate servers instead of | 
 |     // failure caused by other errors. | 
 |     EXPECT_FALSE(redirector.ShouldRedirect(address, &address)); | 
 |   } | 
 |  | 
 |   void TestTurnAlternateServerDetectRepetition(ProtocolType protocol_type) { | 
 |     std::vector<rtc::SocketAddress> redirect_addresses; | 
 |     redirect_addresses.push_back(kTurnAlternateIntAddr); | 
 |     redirect_addresses.push_back(kTurnAlternateIntAddr); | 
 |  | 
 |     TestTurnRedirector redirector(redirect_addresses); | 
 |  | 
 |     turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type); | 
 |     turn_server_.AddInternalSocket(kTurnAlternateIntAddr, protocol_type); | 
 |     turn_server_.set_redirect_hook(&redirector); | 
 |     CreateTurnPort(kTurnUsername, kTurnPassword, | 
 |                    ProtocolAddress(kTurnIntAddr, protocol_type)); | 
 |  | 
 |     turn_port_->PrepareAddress(); | 
 |     EXPECT_TRUE_SIMULATED_WAIT(turn_error_, | 
 |                                TimeToGetAlternateTurnCandidate(protocol_type), | 
 |                                fake_clock_); | 
 |     ASSERT_EQ(0U, turn_port_->Candidates().size()); | 
 |   } | 
 |  | 
 |   // A certain security exploit works by redirecting to a loopback address, | 
 |   // which doesn't ever actually make sense. So redirects to loopback should | 
 |   // be treated as errors. | 
 |   // See: https://bugs.chromium.org/p/chromium/issues/detail?id=649118 | 
 |   void TestTurnAlternateServerLoopback(ProtocolType protocol_type, bool ipv6) { | 
 |     const SocketAddress& local_address = ipv6 ? kLocalIPv6Addr : kLocalAddr1; | 
 |     const SocketAddress& server_address = | 
 |         ipv6 ? kTurnIPv6IntAddr : kTurnIntAddr; | 
 |  | 
 |     std::vector<rtc::SocketAddress> redirect_addresses; | 
 |     // Pick an unusual address in the 127.0.0.0/8 range to make sure more than | 
 |     // 127.0.0.1 is covered. | 
 |     SocketAddress loopback_address(ipv6 ? "::1" : "127.1.2.3", | 
 |                                    TURN_SERVER_PORT); | 
 |     redirect_addresses.push_back(loopback_address); | 
 |  | 
 |     // Make a socket and bind it to the local port, to make extra sure no | 
 |     // packet is sent to this address. | 
 |     std::unique_ptr<rtc::Socket> loopback_socket(ss_->CreateSocket( | 
 |         AF_INET, protocol_type == PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM)); | 
 |     ASSERT_NE(nullptr, loopback_socket.get()); | 
 |     ASSERT_EQ(0, loopback_socket->Bind(loopback_address)); | 
 |     if (protocol_type == PROTO_TCP) { | 
 |       ASSERT_EQ(0, loopback_socket->Listen(1)); | 
 |     } | 
 |  | 
 |     TestTurnRedirector redirector(redirect_addresses); | 
 |  | 
 |     turn_server_.AddInternalSocket(server_address, protocol_type); | 
 |     turn_server_.set_redirect_hook(&redirector); | 
 |     CreateTurnPort(local_address, kTurnUsername, kTurnPassword, | 
 |                    ProtocolAddress(server_address, protocol_type)); | 
 |  | 
 |     turn_port_->PrepareAddress(); | 
 |     EXPECT_TRUE_SIMULATED_WAIT( | 
 |         turn_error_, TimeToGetTurnCandidate(protocol_type), fake_clock_); | 
 |  | 
 |     // Wait for some extra time, and make sure no packets were received on the | 
 |     // loopback port we created (or in the case of TCP, no connection attempt | 
 |     // occurred). | 
 |     SIMULATED_WAIT(false, kSimulatedRtt, fake_clock_); | 
 |     if (protocol_type == PROTO_UDP) { | 
 |       char buf[1]; | 
 |       EXPECT_EQ(-1, loopback_socket->Recv(&buf, 1, nullptr)); | 
 |     } else { | 
 |       std::unique_ptr<rtc::Socket> accepted_socket( | 
 |           loopback_socket->Accept(nullptr)); | 
 |       EXPECT_EQ(nullptr, accepted_socket.get()); | 
 |     } | 
 |   } | 
 |  | 
 |   void TestTurnConnection(ProtocolType protocol_type) { | 
 |     // Create ports and prepare addresses. | 
 |     PrepareTurnAndUdpPorts(protocol_type); | 
 |  | 
 |     // Send ping from UDP to TURN. | 
 |     ASSERT_GE(turn_port_->Candidates().size(), 1U); | 
 |     Connection* conn1 = udp_port_->CreateConnection(turn_port_->Candidates()[0], | 
 |                                                     Port::ORIGIN_MESSAGE); | 
 |     ASSERT_TRUE(conn1 != NULL); | 
 |     conn1->Ping(0); | 
 |     SIMULATED_WAIT(!turn_unknown_address_, kSimulatedRtt * 2, fake_clock_); | 
 |     EXPECT_FALSE(turn_unknown_address_); | 
 |     EXPECT_FALSE(conn1->receiving()); | 
 |     EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state()); | 
 |  | 
 |     // Send ping from TURN to UDP. | 
 |     Connection* conn2 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                      Port::ORIGIN_MESSAGE); | 
 |     ASSERT_TRUE(conn2 != NULL); | 
 |     ASSERT_TRUE_SIMULATED_WAIT(turn_create_permission_success_, kSimulatedRtt, | 
 |                                fake_clock_); | 
 |     conn2->Ping(0); | 
 |  | 
 |     // Two hops from TURN port to UDP port through TURN server, thus two RTTs. | 
 |     EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), | 
 |                              kSimulatedRtt * 2, fake_clock_); | 
 |     EXPECT_TRUE(conn1->receiving()); | 
 |     EXPECT_TRUE(conn2->receiving()); | 
 |     EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state()); | 
 |  | 
 |     // Send another ping from UDP to TURN. | 
 |     conn1->Ping(0); | 
 |     EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), | 
 |                              kSimulatedRtt * 2, fake_clock_); | 
 |     EXPECT_TRUE(conn2->receiving()); | 
 |   } | 
 |  | 
 |   void TestDestroyTurnConnection() { | 
 |     PrepareTurnAndUdpPorts(PROTO_UDP); | 
 |  | 
 |     // Create connections on both ends. | 
 |     Connection* conn1 = udp_port_->CreateConnection(turn_port_->Candidates()[0], | 
 |                                                     Port::ORIGIN_MESSAGE); | 
 |     Connection* conn2 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                      Port::ORIGIN_MESSAGE); | 
 |  | 
 |     // Increased to 10 minutes, to ensure that the TurnEntry times out before | 
 |     // the TurnPort. | 
 |     turn_port_->set_timeout_delay(10 * 60 * 1000); | 
 |  | 
 |     ASSERT_TRUE(conn2 != NULL); | 
 |     ASSERT_TRUE_SIMULATED_WAIT(turn_create_permission_success_, kSimulatedRtt, | 
 |                                fake_clock_); | 
 |     // Make sure turn connection can receive. | 
 |     conn1->Ping(0); | 
 |     EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), | 
 |                              kSimulatedRtt * 2, fake_clock_); | 
 |     EXPECT_FALSE(turn_unknown_address_); | 
 |  | 
 |     // Destroy the connection on the TURN port. The TurnEntry still exists, so | 
 |     // the TURN port should still process a ping from an unknown address. | 
 |     conn2->Destroy(); | 
 |     conn1->Ping(0); | 
 |     EXPECT_TRUE_SIMULATED_WAIT(turn_unknown_address_, kSimulatedRtt, | 
 |                                fake_clock_); | 
 |  | 
 |     // Wait for TurnEntry to expire. Timeout is 5 minutes. | 
 |     // Expect that it still processes an incoming ping and signals the | 
 |     // unknown address. | 
 |     turn_unknown_address_ = false; | 
 |     fake_clock_.AdvanceTime(webrtc::TimeDelta::Seconds(5 * 60)); | 
 |     conn1->Ping(0); | 
 |     EXPECT_TRUE_SIMULATED_WAIT(turn_unknown_address_, kSimulatedRtt, | 
 |                                fake_clock_); | 
 |  | 
 |     // If the connection is created again, it will start to receive pings. | 
 |     conn2 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                          Port::ORIGIN_MESSAGE); | 
 |     conn1->Ping(0); | 
 |     EXPECT_TRUE_SIMULATED_WAIT(conn2->receiving(), kSimulatedRtt, fake_clock_); | 
 |   } | 
 |  | 
 |   void TestTurnSendData(ProtocolType protocol_type) { | 
 |     PrepareTurnAndUdpPorts(protocol_type); | 
 |  | 
 |     // Create connections and send pings. | 
 |     Connection* conn1 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                      Port::ORIGIN_MESSAGE); | 
 |     Connection* conn2 = udp_port_->CreateConnection(turn_port_->Candidates()[0], | 
 |                                                     Port::ORIGIN_MESSAGE); | 
 |     ASSERT_TRUE(conn1 != NULL); | 
 |     ASSERT_TRUE(conn2 != NULL); | 
 |     conn1->SignalReadPacket.connect(static_cast<TurnPortTest*>(this), | 
 |                                     &TurnPortTest::OnTurnReadPacket); | 
 |     conn2->SignalReadPacket.connect(static_cast<TurnPortTest*>(this), | 
 |                                     &TurnPortTest::OnUdpReadPacket); | 
 |     conn1->Ping(0); | 
 |     EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), | 
 |                              kSimulatedRtt * 2, fake_clock_); | 
 |     conn2->Ping(0); | 
 |     EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), | 
 |                              kSimulatedRtt * 2, fake_clock_); | 
 |  | 
 |     // Send some data. | 
 |     size_t num_packets = 256; | 
 |     for (size_t i = 0; i < num_packets; ++i) { | 
 |       unsigned char buf[256] = {0}; | 
 |       for (size_t j = 0; j < i + 1; ++j) { | 
 |         buf[j] = 0xFF - static_cast<unsigned char>(j); | 
 |       } | 
 |       conn1->Send(buf, i + 1, options); | 
 |       conn2->Send(buf, i + 1, options); | 
 |       SIMULATED_WAIT(false, kSimulatedRtt, fake_clock_); | 
 |     } | 
 |  | 
 |     // Check the data. | 
 |     ASSERT_EQ(num_packets, turn_packets_.size()); | 
 |     ASSERT_EQ(num_packets, udp_packets_.size()); | 
 |     for (size_t i = 0; i < num_packets; ++i) { | 
 |       EXPECT_EQ(i + 1, turn_packets_[i].size()); | 
 |       EXPECT_EQ(i + 1, udp_packets_[i].size()); | 
 |       EXPECT_EQ(turn_packets_[i], udp_packets_[i]); | 
 |     } | 
 |   } | 
 |  | 
 |   // Test that a TURN allocation is released when the port is closed. | 
 |   void TestTurnReleaseAllocation(ProtocolType protocol_type) { | 
 |     PrepareTurnAndUdpPorts(protocol_type); | 
 |     turn_port_.reset(); | 
 |     EXPECT_EQ_SIMULATED_WAIT(0U, turn_server_.server()->allocations().size(), | 
 |                              kSimulatedRtt, fake_clock_); | 
 |   } | 
 |  | 
 |   // Test that the TURN allocation is released by sending a refresh request | 
 |   // with lifetime 0 when Release is called. | 
 |   void TestTurnGracefulReleaseAllocation(ProtocolType protocol_type) { | 
 |     PrepareTurnAndUdpPorts(protocol_type); | 
 |  | 
 |     // Create connections and send pings. | 
 |     Connection* conn1 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                      Port::ORIGIN_MESSAGE); | 
 |     Connection* conn2 = udp_port_->CreateConnection(turn_port_->Candidates()[0], | 
 |                                                     Port::ORIGIN_MESSAGE); | 
 |     ASSERT_TRUE(conn1 != NULL); | 
 |     ASSERT_TRUE(conn2 != NULL); | 
 |     conn1->SignalReadPacket.connect(static_cast<TurnPortTest*>(this), | 
 |                                     &TurnPortTest::OnTurnReadPacket); | 
 |     conn2->SignalReadPacket.connect(static_cast<TurnPortTest*>(this), | 
 |                                     &TurnPortTest::OnUdpReadPacket); | 
 |     conn1->Ping(0); | 
 |     EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), | 
 |                              kSimulatedRtt * 2, fake_clock_); | 
 |     conn2->Ping(0); | 
 |     EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), | 
 |                              kSimulatedRtt * 2, fake_clock_); | 
 |  | 
 |     // Send some data from Udp to TurnPort. | 
 |     unsigned char buf[256] = {0}; | 
 |     conn2->Send(buf, sizeof(buf), options); | 
 |  | 
 |     // Now release the TurnPort allocation. | 
 |     // This will send a REFRESH with lifetime 0 to server. | 
 |     turn_port_->Release(); | 
 |  | 
 |     // Wait for the TurnPort to signal closed. | 
 |     ASSERT_TRUE_SIMULATED_WAIT(turn_port_closed_, kSimulatedRtt, fake_clock_); | 
 |  | 
 |     // But the data should have arrived first. | 
 |     ASSERT_EQ(1ul, turn_packets_.size()); | 
 |     EXPECT_EQ(sizeof(buf), turn_packets_[0].size()); | 
 |  | 
 |     // The allocation is released at server. | 
 |     EXPECT_EQ(0U, turn_server_.server()->allocations().size()); | 
 |   } | 
 |  | 
 |  protected: | 
 |   rtc::ScopedFakeClock fake_clock_; | 
 |   // When a "create port" helper method is called with an IP, we create a | 
 |   // Network with that IP and add it to this list. Using a list instead of a | 
 |   // vector so that when it grows, pointers aren't invalidated. | 
 |   std::list<rtc::Network> networks_; | 
 |   std::unique_ptr<TurnPortTestVirtualSocketServer> ss_; | 
 |   rtc::AutoSocketServerThread main_; | 
 |   rtc::BasicPacketSocketFactory socket_factory_; | 
 |   std::unique_ptr<rtc::AsyncPacketSocket> socket_; | 
 |   TestTurnServer turn_server_; | 
 |   std::unique_ptr<TurnPort> turn_port_; | 
 |   std::unique_ptr<UDPPort> udp_port_; | 
 |   bool turn_ready_; | 
 |   bool turn_error_; | 
 |   bool turn_unknown_address_; | 
 |   bool turn_create_permission_success_; | 
 |   bool turn_port_closed_; | 
 |   bool turn_port_destroyed_; | 
 |   bool udp_ready_; | 
 |   bool test_finish_; | 
 |   bool turn_refresh_success_ = false; | 
 |   std::vector<rtc::Buffer> turn_packets_; | 
 |   std::vector<rtc::Buffer> udp_packets_; | 
 |   rtc::PacketOptions options; | 
 |   std::unique_ptr<webrtc::TurnCustomizer> turn_customizer_; | 
 |   cricket::IceCandidateErrorEvent error_event_; | 
 | }; | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnPortType) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   EXPECT_EQ(cricket::RELAY_PORT_TYPE, turn_port_->Type()); | 
 | } | 
 |  | 
 | // Tests that the URL of the servers can be correctly reconstructed when | 
 | // gathering the candidates. | 
 | TEST_F(TurnPortTest, TestReconstructedServerUrlForUdpIPv4) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestReconstructedServerUrl(PROTO_UDP, "turn:99.99.99.3:3478?transport=udp"); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestReconstructedServerUrlForUdpIPv6) { | 
 |   turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, PROTO_UDP); | 
 |   CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, | 
 |                  kTurnUdpIPv6ProtoAddr); | 
 |   TestReconstructedServerUrl( | 
 |       PROTO_UDP, | 
 |       "turn:2400:4030:1:2c00:be30:abcd:efab:cdef:3478?transport=udp"); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestReconstructedServerUrlForTcp) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   TestReconstructedServerUrl(PROTO_TCP, "turn:99.99.99.4:3478?transport=tcp"); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestReconstructedServerUrlForTls) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr); | 
 |   TestReconstructedServerUrl(PROTO_TLS, "turns:99.99.99.4:3478?transport=tcp"); | 
 | } | 
 |  | 
 | // Do a normal TURN allocation. | 
 | TEST_F(TurnPortTest, TestTurnAllocate) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   EXPECT_EQ(0, turn_port_->SetOption(rtc::Socket::OPT_SNDBUF, 10 * 1024)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); | 
 |   ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |   EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), | 
 |             turn_port_->Candidates()[0].address().ipaddr()); | 
 |   EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); | 
 | } | 
 |  | 
 | class TurnLoggingIdValidator : public StunMessageObserver { | 
 |  public: | 
 |   explicit TurnLoggingIdValidator(const char* expect_val) | 
 |       : expect_val_(expect_val) {} | 
 |   ~TurnLoggingIdValidator() {} | 
 |   void ReceivedMessage(const TurnMessage* msg) override { | 
 |     if (msg->type() == cricket::STUN_ALLOCATE_REQUEST) { | 
 |       const StunByteStringAttribute* attr = | 
 |           msg->GetByteString(cricket::STUN_ATTR_TURN_LOGGING_ID); | 
 |       if (expect_val_) { | 
 |         ASSERT_NE(nullptr, attr); | 
 |         ASSERT_EQ(expect_val_, attr->GetString()); | 
 |       } else { | 
 |         EXPECT_EQ(nullptr, attr); | 
 |       } | 
 |     } | 
 |   } | 
 |   void ReceivedChannelData(const char* data, size_t size) override {} | 
 |  | 
 |  private: | 
 |   const char* expect_val_; | 
 | }; | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAllocateWithLoggingId) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   turn_port_->SetTurnLoggingId("KESO"); | 
 |   turn_server_.server()->SetStunMessageObserver( | 
 |       std::make_unique<TurnLoggingIdValidator>("KESO")); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); | 
 |   ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |   EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), | 
 |             turn_port_->Candidates()[0].address().ipaddr()); | 
 |   EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAllocateWithoutLoggingId) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   turn_server_.server()->SetStunMessageObserver( | 
 |       std::make_unique<TurnLoggingIdValidator>(nullptr)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); | 
 |   ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |   EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), | 
 |             turn_port_->Candidates()[0].address().ipaddr()); | 
 |   EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); | 
 | } | 
 |  | 
 | // Test bad credentials. | 
 | TEST_F(TurnPortTest, TestTurnBadCredentials) { | 
 |   CreateTurnPort(kTurnUsername, "bad", kTurnUdpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_error_, kSimulatedRtt * 3, fake_clock_); | 
 |   ASSERT_EQ(0U, turn_port_->Candidates().size()); | 
 |   EXPECT_EQ_SIMULATED_WAIT(error_event_.error_code, STUN_ERROR_UNAUTHORIZED, | 
 |                            kSimulatedRtt * 3, fake_clock_); | 
 |   EXPECT_EQ(error_event_.error_text, "Unauthorized"); | 
 | } | 
 |  | 
 | // Testing a normal UDP allocation using TCP connection. | 
 | TEST_F(TurnPortTest, TestTurnTcpAllocate) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   EXPECT_EQ(0, turn_port_->SetOption(rtc::Socket::OPT_SNDBUF, 10 * 1024)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 3, fake_clock_); | 
 |   ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |   EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), | 
 |             turn_port_->Candidates()[0].address().ipaddr()); | 
 |   EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); | 
 | } | 
 |  | 
 | // Test case for WebRTC issue 3927 where a proxy binds to the local host address | 
 | // instead the address that TurnPort originally bound to. The candidate pair | 
 | // impacted by this behavior should still be used. | 
 | TEST_F(TurnPortTest, TestTurnTcpAllocationWhenProxyChangesAddressToLocalHost) { | 
 |   SocketAddress local_address("127.0.0.1", 0); | 
 |   // After calling this, when TurnPort attempts to get a socket bound to | 
 |   // kLocalAddr, it will end up using localhost instead. | 
 |   ss_->SetAlternativeLocalAddress(kLocalAddr1.ipaddr(), local_address.ipaddr()); | 
 |  | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kLocalAddr1, kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   EXPECT_EQ(0, turn_port_->SetOption(rtc::Socket::OPT_SNDBUF, 10 * 1024)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 3, fake_clock_); | 
 |   ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |   EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), | 
 |             turn_port_->Candidates()[0].address().ipaddr()); | 
 |   EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); | 
 |  | 
 |   // Verify that the socket actually used localhost, otherwise this test isn't | 
 |   // doing what it meant to. | 
 |   ASSERT_EQ(local_address.ipaddr(), | 
 |             turn_port_->Candidates()[0].related_address().ipaddr()); | 
 | } | 
 |  | 
 | // If the address the socket ends up bound to does not match any address of the | 
 | // TurnPort's Network, then the socket should be discarded and no candidates | 
 | // should be signaled. In the context of ICE, where one TurnPort is created for | 
 | // each Network, when this happens it's likely that the unexpected address is | 
 | // associated with some other Network, which another TurnPort is already | 
 | // covering. | 
 | TEST_F(TurnPortTest, | 
 |        TurnTcpAllocationDiscardedIfBoundAddressDoesNotMatchNetwork) { | 
 |   // Sockets bound to kLocalAddr1 will actually end up with kLocalAddr2. | 
 |   ss_->SetAlternativeLocalAddress(kLocalAddr1.ipaddr(), kLocalAddr2.ipaddr()); | 
 |  | 
 |   // Set up TURN server to use TCP (this logic only exists for TCP). | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |  | 
 |   // Create TURN port and tell it to start allocation. | 
 |   CreateTurnPort(kLocalAddr1, kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |  | 
 |   // Shouldn't take more than 1 RTT to realize the bound address isn't the one | 
 |   // expected. | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_error_, kSimulatedRtt, fake_clock_); | 
 |   EXPECT_EQ_SIMULATED_WAIT(error_event_.error_code, STUN_ERROR_GLOBAL_FAILURE, | 
 |                            kSimulatedRtt, fake_clock_); | 
 |   ASSERT_NE(error_event_.error_text.find('.'), std::string::npos); | 
 |   ASSERT_NE(error_event_.address.find(kLocalAddr2.HostAsSensitiveURIString()), | 
 |             std::string::npos); | 
 |   ASSERT_NE(error_event_.port, 0); | 
 |   std::string server_url = | 
 |       "turn:" + kTurnTcpIntAddr.ToString() + "?transport=tcp"; | 
 |   ASSERT_EQ(error_event_.url, server_url); | 
 | } | 
 |  | 
 | // A caveat for the above logic: if the socket ends up bound to one of the IPs | 
 | // associated with the Network, just not the "best" one, this is ok. | 
 | TEST_F(TurnPortTest, TurnTcpAllocationNotDiscardedIfNotBoundToBestIP) { | 
 |   // Sockets bound to kLocalAddr1 will actually end up with kLocalAddr2. | 
 |   ss_->SetAlternativeLocalAddress(kLocalAddr1.ipaddr(), kLocalAddr2.ipaddr()); | 
 |  | 
 |   // Set up a network with kLocalAddr1 as the "best" IP, and kLocalAddr2 as an | 
 |   // alternate. | 
 |   rtc::Network* network = MakeNetwork(kLocalAddr1); | 
 |   network->AddIP(kLocalAddr2.ipaddr()); | 
 |   ASSERT_EQ(kLocalAddr1.ipaddr(), network->GetBestIP()); | 
 |  | 
 |   // Set up TURN server to use TCP (this logic only exists for TCP). | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |  | 
 |   // Create TURN port using our special Network, and tell it to start | 
 |   // allocation. | 
 |   CreateTurnPortWithNetwork(network, kTurnUsername, kTurnPassword, | 
 |                             kTurnTcpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |  | 
 |   // Candidate should be gathered as normally. | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 3, fake_clock_); | 
 |   ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |  | 
 |   // Verify that the socket actually used the alternate address, otherwise this | 
 |   // test isn't doing what it meant to. | 
 |   ASSERT_EQ(kLocalAddr2.ipaddr(), | 
 |             turn_port_->Candidates()[0].related_address().ipaddr()); | 
 | } | 
 |  | 
 | // Regression test for crbug.com/webrtc/8972, caused by buggy comparison | 
 | // between rtc::IPAddress and rtc::InterfaceAddress. | 
 | TEST_F(TurnPortTest, TCPPortNotDiscardedIfBoundToTemporaryIP) { | 
 |   networks_.emplace_back("unittest", "unittest", kLocalIPv6Addr.ipaddr(), 32); | 
 |   networks_.back().AddIP(rtc::InterfaceAddress( | 
 |       kLocalIPv6Addr.ipaddr(), rtc::IPV6_ADDRESS_FLAG_TEMPORARY)); | 
 |  | 
 |   // Set up TURN server to use TCP (this logic only exists for TCP). | 
 |   turn_server_.AddInternalSocket(kTurnIPv6IntAddr, PROTO_TCP); | 
 |  | 
 |   // Create TURN port using our special Network, and tell it to start | 
 |   // allocation. | 
 |   CreateTurnPortWithNetwork( | 
 |       &networks_.back(), kTurnUsername, kTurnPassword, | 
 |       cricket::ProtocolAddress(kTurnIPv6IntAddr, PROTO_TCP)); | 
 |   turn_port_->PrepareAddress(); | 
 |  | 
 |   // Candidate should be gathered as normally. | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 3, fake_clock_); | 
 |   ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 | } | 
 |  | 
 | // Testing turn port will attempt to create TCP socket on address resolution | 
 | // failure. | 
 | TEST_F(TurnPortTest, TestTurnTcpOnAddressResolveFailure) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, | 
 |                  ProtocolAddress(kTurnInvalidAddr, PROTO_TCP)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_error_, kResolverTimeout); | 
 |   // As VSS doesn't provide a DNS resolution, name resolve will fail. TurnPort | 
 |   // will proceed in creating a TCP socket which will fail as there is no | 
 |   // server on the above domain and error will be set to SOCKET_ERROR. | 
 |   EXPECT_EQ(SOCKET_ERROR, turn_port_->error()); | 
 |   EXPECT_EQ_SIMULATED_WAIT(error_event_.error_code, SERVER_NOT_REACHABLE_ERROR, | 
 |                            kSimulatedRtt, fake_clock_); | 
 |   std::string server_url = | 
 |       "turn:" + kTurnInvalidAddr.ToString() + "?transport=tcp"; | 
 |   ASSERT_EQ(error_event_.url, server_url); | 
 | } | 
 |  | 
 | // Testing turn port will attempt to create TLS socket on address resolution | 
 | // failure. | 
 | TEST_F(TurnPortTest, TestTurnTlsOnAddressResolveFailure) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, | 
 |                  ProtocolAddress(kTurnInvalidAddr, PROTO_TLS)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_error_, kResolverTimeout); | 
 |   EXPECT_EQ(SOCKET_ERROR, turn_port_->error()); | 
 | } | 
 |  | 
 | // In case of UDP on address resolve failure, TurnPort will not create socket | 
 | // and return allocate failure. | 
 | TEST_F(TurnPortTest, TestTurnUdpOnAddressResolveFailure) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, | 
 |                  ProtocolAddress(kTurnInvalidAddr, PROTO_UDP)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_error_, kResolverTimeout); | 
 |   // Error from turn port will not be socket error. | 
 |   EXPECT_NE(SOCKET_ERROR, turn_port_->error()); | 
 | } | 
 |  | 
 | // Try to do a TURN allocation with an invalid password. | 
 | TEST_F(TurnPortTest, TestTurnAllocateBadPassword) { | 
 |   CreateTurnPort(kTurnUsername, "bad", kTurnUdpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_error_, kSimulatedRtt * 2, fake_clock_); | 
 |   ASSERT_EQ(0U, turn_port_->Candidates().size()); | 
 | } | 
 |  | 
 | // Tests that TURN port nonce will be reset when receiving an ALLOCATE MISMATCH | 
 | // error. | 
 | TEST_F(TurnPortTest, TestTurnAllocateNonceResetAfterAllocateMismatch) { | 
 |   // Do a normal allocation first. | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); | 
 |   rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); | 
 |   // Destroy the turnport while keeping the drop probability to 1 to | 
 |   // suppress the release of the allocation at the server. | 
 |   ss_->set_drop_probability(1.0); | 
 |   turn_port_.reset(); | 
 |   SIMULATED_WAIT(false, kSimulatedRtt, fake_clock_); | 
 |   ss_->set_drop_probability(0.0); | 
 |  | 
 |   // Force the socket server to assign the same port. | 
 |   ss_->SetNextPortForTesting(first_addr.port()); | 
 |   turn_ready_ = false; | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |  | 
 |   // It is expected that the turn port will first get a nonce from the server | 
 |   // using timestamp |ts_before| but then get an allocate mismatch error and | 
 |   // receive an even newer nonce based on the system clock. |ts_before| is | 
 |   // chosen so that the two NONCEs generated by the server will be different. | 
 |   int64_t ts_before = rtc::TimeMillis() - 1; | 
 |   std::string first_nonce = | 
 |       turn_server_.server()->SetTimestampForNextNonce(ts_before); | 
 |   turn_port_->PrepareAddress(); | 
 |  | 
 |   // Four round trips; first we'll get "stale nonce", then | 
 |   // "allocate mismatch", then "stale nonce" again, then finally it will | 
 |   // succeed. | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 4, fake_clock_); | 
 |   EXPECT_NE(first_nonce, turn_port_->nonce()); | 
 | } | 
 |  | 
 | // Tests that a new local address is created after | 
 | // STUN_ERROR_ALLOCATION_MISMATCH. | 
 | TEST_F(TurnPortTest, TestTurnAllocateMismatch) { | 
 |   // Do a normal allocation first. | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); | 
 |   rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); | 
 |  | 
 |   // Clear connected_ flag on turnport to suppress the release of | 
 |   // the allocation. | 
 |   turn_port_->OnSocketClose(turn_port_->socket(), 0); | 
 |  | 
 |   // Forces the socket server to assign the same port. | 
 |   ss_->SetNextPortForTesting(first_addr.port()); | 
 |  | 
 |   turn_ready_ = false; | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |  | 
 |   // Verifies that the new port has the same address. | 
 |   EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress()); | 
 |  | 
 |   // Four round trips; first we'll get "stale nonce", then | 
 |   // "allocate mismatch", then "stale nonce" again, then finally it will | 
 |   // succeed. | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 4, fake_clock_); | 
 |  | 
 |   // Verifies that the new port has a different address now. | 
 |   EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); | 
 |  | 
 |   // Verify that all packets received from the shared socket are ignored. | 
 |   std::string test_packet = "Test packet"; | 
 |   EXPECT_FALSE(turn_port_->HandleIncomingPacket( | 
 |       socket_.get(), test_packet.data(), test_packet.size(), | 
 |       rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0), rtc::TimeMicros())); | 
 | } | 
 |  | 
 | // Tests that a shared-socket-TurnPort creates its own socket after | 
 | // STUN_ERROR_ALLOCATION_MISMATCH. | 
 | TEST_F(TurnPortTest, TestSharedSocketAllocateMismatch) { | 
 |   // Do a normal allocation first. | 
 |   CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); | 
 |   rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); | 
 |  | 
 |   // Clear connected_ flag on turnport to suppress the release of | 
 |   // the allocation. | 
 |   turn_port_->OnSocketClose(turn_port_->socket(), 0); | 
 |  | 
 |   turn_ready_ = false; | 
 |   CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |  | 
 |   // Verifies that the new port has the same address. | 
 |   EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress()); | 
 |   EXPECT_TRUE(turn_port_->SharedSocket()); | 
 |  | 
 |   turn_port_->PrepareAddress(); | 
 |   // Extra 2 round trips due to allocate mismatch. | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 4, fake_clock_); | 
 |  | 
 |   // Verifies that the new port has a different address now. | 
 |   EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); | 
 |   EXPECT_FALSE(turn_port_->SharedSocket()); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnTcpAllocateMismatch) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |  | 
 |   // Do a normal allocation first. | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 3, fake_clock_); | 
 |   rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); | 
 |  | 
 |   // Clear connected_ flag on turnport to suppress the release of | 
 |   // the allocation. | 
 |   turn_port_->OnSocketClose(turn_port_->socket(), 0); | 
 |  | 
 |   // Forces the socket server to assign the same port. | 
 |   ss_->SetNextPortForTesting(first_addr.port()); | 
 |  | 
 |   turn_ready_ = false; | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |  | 
 |   // Verifies that the new port has the same address. | 
 |   EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress()); | 
 |  | 
 |   // Extra 2 round trips due to allocate mismatch. | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 5, fake_clock_); | 
 |  | 
 |   // Verifies that the new port has a different address now. | 
 |   EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestRefreshRequestGetsErrorResponse) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   PrepareTurnAndUdpPorts(PROTO_UDP); | 
 |   turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                Port::ORIGIN_MESSAGE); | 
 |   // Set bad credentials. | 
 |   RelayCredentials bad_credentials("bad_user", "bad_pwd"); | 
 |   turn_port_->set_credentials(bad_credentials); | 
 |   turn_refresh_success_ = false; | 
 |   // This sends out the first RefreshRequest with correct credentials. | 
 |   // When this succeeds, it will schedule a new RefreshRequest with the bad | 
 |   // credential. | 
 |   turn_port_->FlushRequests(TURN_REFRESH_REQUEST); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_refresh_success_, kSimulatedRtt, fake_clock_); | 
 |   // Flush it again, it will receive a bad response. | 
 |   turn_port_->FlushRequests(TURN_REFRESH_REQUEST); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(!turn_refresh_success_, kSimulatedRtt, | 
 |                              fake_clock_); | 
 |   EXPECT_FALSE(turn_port_->connected()); | 
 |   EXPECT_TRUE(CheckAllConnectionsFailedAndPruned()); | 
 |   EXPECT_FALSE(turn_port_->HasRequests()); | 
 | } | 
 |  | 
 | // Test that TurnPort will not handle any incoming packets once it has been | 
 | // closed. | 
 | TEST_F(TurnPortTest, TestStopProcessingPacketsAfterClosed) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   PrepareTurnAndUdpPorts(PROTO_UDP); | 
 |   Connection* conn1 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                    Port::ORIGIN_MESSAGE); | 
 |   Connection* conn2 = udp_port_->CreateConnection(turn_port_->Candidates()[0], | 
 |                                                   Port::ORIGIN_MESSAGE); | 
 |   ASSERT_TRUE(conn1 != NULL); | 
 |   ASSERT_TRUE(conn2 != NULL); | 
 |   // Make sure conn2 is writable. | 
 |   conn2->Ping(0); | 
 |   EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), | 
 |                            kSimulatedRtt * 2, fake_clock_); | 
 |  | 
 |   turn_port_->Close(); | 
 |   SIMULATED_WAIT(false, kSimulatedRtt, fake_clock_); | 
 |   turn_unknown_address_ = false; | 
 |   conn2->Ping(0); | 
 |   SIMULATED_WAIT(false, kSimulatedRtt, fake_clock_); | 
 |   // Since the turn port does not handle packets any more, it should not | 
 |   // SignalUnknownAddress. | 
 |   EXPECT_FALSE(turn_unknown_address_); | 
 | } | 
 |  | 
 | // Test that CreateConnection will return null if port becomes disconnected. | 
 | TEST_F(TurnPortTest, TestCreateConnectionWhenSocketClosed) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   PrepareTurnAndUdpPorts(PROTO_TCP); | 
 |   // Create a connection. | 
 |   Connection* conn1 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                    Port::ORIGIN_MESSAGE); | 
 |   ASSERT_TRUE(conn1 != NULL); | 
 |  | 
 |   // Close the socket and create a connection again. | 
 |   turn_port_->OnSocketClose(turn_port_->socket(), 1); | 
 |   conn1 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                        Port::ORIGIN_MESSAGE); | 
 |   ASSERT_TRUE(conn1 == NULL); | 
 | } | 
 |  | 
 | // Tests that when a TCP socket is closed, the respective TURN connection will | 
 | // be destroyed. | 
 | TEST_F(TurnPortTest, TestSocketCloseWillDestroyConnection) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   PrepareTurnAndUdpPorts(PROTO_TCP); | 
 |   Connection* conn = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                   Port::ORIGIN_MESSAGE); | 
 |   EXPECT_NE(nullptr, conn); | 
 |   EXPECT_TRUE(!turn_port_->connections().empty()); | 
 |   turn_port_->socket()->SignalClose(turn_port_->socket(), 1); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_port_->connections().empty(), | 
 |                              kConnectionDestructionDelay, fake_clock_); | 
 | } | 
 |  | 
 | // Test try-alternate-server feature. | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerUDP) { | 
 |   TestTurnAlternateServer(PROTO_UDP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerTCP) { | 
 |   TestTurnAlternateServer(PROTO_TCP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerTLS) { | 
 |   TestTurnAlternateServer(PROTO_TLS); | 
 | } | 
 |  | 
 | // Test that we fail when we redirect to an address different from | 
 | // current IP family. | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6UDP) { | 
 |   TestTurnAlternateServerV4toV6(PROTO_UDP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6TCP) { | 
 |   TestTurnAlternateServerV4toV6(PROTO_TCP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6TLS) { | 
 |   TestTurnAlternateServerV4toV6(PROTO_TLS); | 
 | } | 
 |  | 
 | // Test try-alternate-server catches the case of pingpong. | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerPingPongUDP) { | 
 |   TestTurnAlternateServerPingPong(PROTO_UDP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerPingPongTCP) { | 
 |   TestTurnAlternateServerPingPong(PROTO_TCP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerPingPongTLS) { | 
 |   TestTurnAlternateServerPingPong(PROTO_TLS); | 
 | } | 
 |  | 
 | // Test try-alternate-server catch the case of repeated server. | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetitionUDP) { | 
 |   TestTurnAlternateServerDetectRepetition(PROTO_UDP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetitionTCP) { | 
 |   TestTurnAlternateServerDetectRepetition(PROTO_TCP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetitionTLS) { | 
 |   TestTurnAlternateServerDetectRepetition(PROTO_TCP); | 
 | } | 
 |  | 
 | // Test catching the case of a redirect to loopback. | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackUdpIpv4) { | 
 |   TestTurnAlternateServerLoopback(PROTO_UDP, false); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackUdpIpv6) { | 
 |   TestTurnAlternateServerLoopback(PROTO_UDP, true); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackTcpIpv4) { | 
 |   TestTurnAlternateServerLoopback(PROTO_TCP, false); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackTcpIpv6) { | 
 |   TestTurnAlternateServerLoopback(PROTO_TCP, true); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackTlsIpv4) { | 
 |   TestTurnAlternateServerLoopback(PROTO_TLS, false); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackTlsIpv6) { | 
 |   TestTurnAlternateServerLoopback(PROTO_TLS, true); | 
 | } | 
 |  | 
 | // Do a TURN allocation and try to send a packet to it from the outside. | 
 | // The packet should be dropped. Then, try to send a packet from TURN to the | 
 | // outside. It should reach its destination. Finally, try again from the | 
 | // outside. It should now work as well. | 
 | TEST_F(TurnPortTest, TestTurnConnection) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestTurnConnection(PROTO_UDP); | 
 | } | 
 |  | 
 | // Similar to above, except that this test will use the shared socket. | 
 | TEST_F(TurnPortTest, TestTurnConnectionUsingSharedSocket) { | 
 |   CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestTurnConnection(PROTO_UDP); | 
 | } | 
 |  | 
 | // Test that we can establish a TCP connection with TURN server. | 
 | TEST_F(TurnPortTest, TestTurnTcpConnection) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   TestTurnConnection(PROTO_TCP); | 
 | } | 
 |  | 
 | // Test that we can establish a TLS connection with TURN server. | 
 | TEST_F(TurnPortTest, TestTurnTlsConnection) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr); | 
 |   TestTurnConnection(PROTO_TLS); | 
 | } | 
 |  | 
 | // Test that if a connection on a TURN port is destroyed, the TURN port can | 
 | // still receive ping on that connection as if it is from an unknown address. | 
 | // If the connection is created again, it will be used to receive ping. | 
 | TEST_F(TurnPortTest, TestDestroyTurnConnection) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestDestroyTurnConnection(); | 
 | } | 
 |  | 
 | // Similar to above, except that this test will use the shared socket. | 
 | TEST_F(TurnPortTest, TestDestroyTurnConnectionUsingSharedSocket) { | 
 |   CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestDestroyTurnConnection(); | 
 | } | 
 |  | 
 | // Run TurnConnectionTest with one-time-use nonce feature. | 
 | // Here server will send a 438 STALE_NONCE error message for | 
 | // every TURN transaction. | 
 | TEST_F(TurnPortTest, TestTurnConnectionUsingOTUNonce) { | 
 |   turn_server_.set_enable_otu_nonce(true); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestTurnConnection(PROTO_UDP); | 
 | } | 
 |  | 
 | // Test that CreatePermissionRequest will be scheduled after the success | 
 | // of the first create permission request and the request will get an | 
 | // ErrorResponse if the ufrag and pwd are incorrect. | 
 | TEST_F(TurnPortTest, TestRefreshCreatePermissionRequest) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   PrepareTurnAndUdpPorts(PROTO_UDP); | 
 |  | 
 |   Connection* conn = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                   Port::ORIGIN_MESSAGE); | 
 |   ASSERT_TRUE(conn != NULL); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_create_permission_success_, kSimulatedRtt, | 
 |                              fake_clock_); | 
 |   turn_create_permission_success_ = false; | 
 |   // A create-permission-request should be pending. | 
 |   // After the next create-permission-response is received, it will schedule | 
 |   // another request with bad_ufrag and bad_pwd. | 
 |   RelayCredentials bad_credentials("bad_user", "bad_pwd"); | 
 |   turn_port_->set_credentials(bad_credentials); | 
 |   turn_port_->FlushRequests(kAllRequests); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_create_permission_success_, kSimulatedRtt, | 
 |                              fake_clock_); | 
 |   // Flush the requests again; the create-permission-request will fail. | 
 |   turn_port_->FlushRequests(kAllRequests); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(!turn_create_permission_success_, kSimulatedRtt, | 
 |                              fake_clock_); | 
 |   EXPECT_TRUE(CheckConnectionFailedAndPruned(conn)); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestChannelBindGetErrorResponse) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   PrepareTurnAndUdpPorts(PROTO_UDP); | 
 |   Connection* conn1 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                    Port::ORIGIN_MESSAGE); | 
 |   ASSERT_TRUE(conn1 != nullptr); | 
 |   Connection* conn2 = udp_port_->CreateConnection(turn_port_->Candidates()[0], | 
 |                                                   Port::ORIGIN_MESSAGE); | 
 |  | 
 |   ASSERT_TRUE(conn2 != nullptr); | 
 |   conn1->Ping(0); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(conn1->writable(), kSimulatedRtt * 2, fake_clock_); | 
 |   // TODO(deadbeef): SetEntryChannelId should not be a public method. | 
 |   // Instead we should set an option on the fake TURN server to force it to | 
 |   // send a channel bind errors. | 
 |   ASSERT_TRUE( | 
 |       turn_port_->SetEntryChannelId(udp_port_->Candidates()[0].address(), -1)); | 
 |  | 
 |   std::string data = "ABC"; | 
 |   conn1->Send(data.data(), data.length(), options); | 
 |  | 
 |   EXPECT_TRUE_SIMULATED_WAIT(CheckConnectionFailedAndPruned(conn1), | 
 |                              kSimulatedRtt, fake_clock_); | 
 |   // Verify that packets are allowed to be sent after a bind request error. | 
 |   // They'll just use a send indication instead. | 
 |   conn2->SignalReadPacket.connect(static_cast<TurnPortTest*>(this), | 
 |                                   &TurnPortTest::OnUdpReadPacket); | 
 |   conn1->Send(data.data(), data.length(), options); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(!udp_packets_.empty(), kSimulatedRtt, fake_clock_); | 
 | } | 
 |  | 
 | // Do a TURN allocation, establish a UDP connection, and send some data. | 
 | TEST_F(TurnPortTest, TestTurnSendDataTurnUdpToUdp) { | 
 |   // Create ports and prepare addresses. | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestTurnSendData(PROTO_UDP); | 
 |   EXPECT_EQ(UDP_PROTOCOL_NAME, turn_port_->Candidates()[0].relay_protocol()); | 
 | } | 
 |  | 
 | // Do a TURN allocation, establish a TCP connection, and send some data. | 
 | TEST_F(TurnPortTest, TestTurnSendDataTurnTcpToUdp) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   // Create ports and prepare addresses. | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   TestTurnSendData(PROTO_TCP); | 
 |   EXPECT_EQ(TCP_PROTOCOL_NAME, turn_port_->Candidates()[0].relay_protocol()); | 
 | } | 
 |  | 
 | // Do a TURN allocation, establish a TLS connection, and send some data. | 
 | TEST_F(TurnPortTest, TestTurnSendDataTurnTlsToUdp) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr); | 
 |   TestTurnSendData(PROTO_TLS); | 
 |   EXPECT_EQ(TLS_PROTOCOL_NAME, turn_port_->Candidates()[0].relay_protocol()); | 
 | } | 
 |  | 
 | // Test TURN fails to make a connection from IPv6 address to a server which has | 
 | // IPv4 address. | 
 | TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv4) { | 
 |   turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, PROTO_UDP); | 
 |   CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, | 
 |                  kTurnUdpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   ASSERT_TRUE_SIMULATED_WAIT(turn_error_, kSimulatedRtt, fake_clock_); | 
 |   EXPECT_TRUE(turn_port_->Candidates().empty()); | 
 | } | 
 |  | 
 | // Test TURN make a connection from IPv6 address to a server which has | 
 | // IPv6 intenal address. But in this test external address is a IPv4 address, | 
 | // hence allocated address will be a IPv4 address. | 
 | TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) { | 
 |   turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, PROTO_UDP); | 
 |   CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, | 
 |                  kTurnUdpIPv6ProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); | 
 |   ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |   EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), | 
 |             turn_port_->Candidates()[0].address().ipaddr()); | 
 |   EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); | 
 | } | 
 |  | 
 | // Tests that the local and remote candidate address families should match when | 
 | // a connection is created. Specifically, if a TURN port has an IPv6 address, | 
 | // its local candidate will still be an IPv4 address and it can only create | 
 | // connections with IPv4 remote candidates. | 
 | TEST_F(TurnPortTest, TestCandidateAddressFamilyMatch) { | 
 |   turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, PROTO_UDP); | 
 |  | 
 |   CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, | 
 |                  kTurnUdpIPv6ProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); | 
 |   ASSERT_EQ(1U, turn_port_->Candidates().size()); | 
 |  | 
 |   // Create an IPv4 candidate. It will match the TURN candidate. | 
 |   Candidate remote_candidate(ICE_CANDIDATE_COMPONENT_RTP, "udp", kLocalAddr2, 0, | 
 |                              "", "", "local", 0, kCandidateFoundation); | 
 |   remote_candidate.set_address(kLocalAddr2); | 
 |   Connection* conn = | 
 |       turn_port_->CreateConnection(remote_candidate, Port::ORIGIN_MESSAGE); | 
 |   EXPECT_NE(nullptr, conn); | 
 |  | 
 |   // Set the candidate address family to IPv6. It won't match the TURN | 
 |   // candidate. | 
 |   remote_candidate.set_address(kLocalIPv6Addr2); | 
 |   conn = turn_port_->CreateConnection(remote_candidate, Port::ORIGIN_MESSAGE); | 
 |   EXPECT_EQ(nullptr, conn); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestOriginHeader) { | 
 |   CreateTurnPortWithOrigin(kLocalAddr1, kTurnUsername, kTurnPassword, | 
 |                            kTurnUdpProtoAddr, kTestOrigin); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); | 
 |   ASSERT_GT(turn_server_.server()->allocations().size(), 0U); | 
 |   SocketAddress local_address = turn_port_->GetLocalAddress(); | 
 |   ASSERT_TRUE(turn_server_.FindAllocation(local_address) != NULL); | 
 |   EXPECT_EQ(kTestOrigin, turn_server_.FindAllocation(local_address)->origin()); | 
 | } | 
 |  | 
 | // Test that a CreatePermission failure will result in the connection being | 
 | // pruned and failed. | 
 | TEST_F(TurnPortTest, TestConnectionFailedAndPrunedOnCreatePermissionFailure) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   turn_server_.server()->set_reject_private_addresses(true); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 3, fake_clock_); | 
 |  | 
 |   CreateUdpPort(SocketAddress("10.0.0.10", 0)); | 
 |   udp_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(udp_ready_, kSimulatedRtt, fake_clock_); | 
 |   // Create a connection. | 
 |   TestConnectionWrapper conn(turn_port_->CreateConnection( | 
 |       udp_port_->Candidates()[0], Port::ORIGIN_MESSAGE)); | 
 |   EXPECT_TRUE(conn.connection() != nullptr); | 
 |  | 
 |   // Asynchronously, CreatePermission request should be sent and fail, which | 
 |   // will make the connection pruned and failed. | 
 |   EXPECT_TRUE_SIMULATED_WAIT(CheckConnectionFailedAndPruned(conn.connection()), | 
 |                              kSimulatedRtt, fake_clock_); | 
 |   EXPECT_TRUE_SIMULATED_WAIT(!turn_create_permission_success_, kSimulatedRtt, | 
 |                              fake_clock_); | 
 |   // Check that the connection is not deleted asynchronously. | 
 |   SIMULATED_WAIT(conn.connection() == nullptr, kConnectionDestructionDelay, | 
 |                  fake_clock_); | 
 |   EXPECT_NE(nullptr, conn.connection()); | 
 | } | 
 |  | 
 | // Test that a TURN allocation is released when the port is closed. | 
 | TEST_F(TurnPortTest, TestTurnReleaseAllocation) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestTurnReleaseAllocation(PROTO_UDP); | 
 | } | 
 |  | 
 | // Test that a TURN TCP allocation is released when the port is closed. | 
 | TEST_F(TurnPortTest, TestTurnTCPReleaseAllocation) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   TestTurnReleaseAllocation(PROTO_TCP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnTLSReleaseAllocation) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr); | 
 |   TestTurnReleaseAllocation(PROTO_TLS); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnUDPGracefulReleaseAllocation) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_UDP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestTurnGracefulReleaseAllocation(PROTO_UDP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnTCPGracefulReleaseAllocation) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   TestTurnGracefulReleaseAllocation(PROTO_TCP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnTLSGracefulReleaseAllocation) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr); | 
 |   TestTurnGracefulReleaseAllocation(PROTO_TLS); | 
 | } | 
 |  | 
 | // Test that nothing bad happens if we try to create a connection to the same | 
 | // remote address twice. Previously there was a bug that caused this to hit a | 
 | // DCHECK. | 
 | TEST_F(TurnPortTest, CanCreateTwoConnectionsToSameAddress) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   PrepareTurnAndUdpPorts(PROTO_UDP); | 
 |   Connection* conn1 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                    Port::ORIGIN_MESSAGE); | 
 |   Connection* conn2 = turn_port_->CreateConnection(udp_port_->Candidates()[0], | 
 |                                                    Port::ORIGIN_MESSAGE); | 
 |   EXPECT_NE(conn1, conn2); | 
 | } | 
 |  | 
 | // This test verifies any FD's are not leaked after TurnPort is destroyed. | 
 | // https://code.google.com/p/webrtc/issues/detail?id=2651 | 
 | #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) | 
 |  | 
 | TEST_F(TurnPortTest, TestResolverShutdown) { | 
 |   turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, PROTO_UDP); | 
 |   int last_fd_count = GetFDCount(); | 
 |   // Need to supply unresolved address to kick off resolver. | 
 |   CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, | 
 |                  ProtocolAddress(rtc::SocketAddress("www.google.invalid", 3478), | 
 |                                  PROTO_UDP)); | 
 |   turn_port_->PrepareAddress(); | 
 |   ASSERT_TRUE_WAIT(turn_error_, kResolverTimeout); | 
 |   EXPECT_TRUE(turn_port_->Candidates().empty()); | 
 |   turn_port_.reset(); | 
 |   rtc::Thread::Current()->Post(RTC_FROM_HERE, this, MSG_TESTFINISH); | 
 |   // Waiting for above message to be processed. | 
 |   ASSERT_TRUE_SIMULATED_WAIT(test_finish_, 1, fake_clock_); | 
 |   EXPECT_EQ(last_fd_count, GetFDCount()); | 
 | } | 
 | #endif | 
 |  | 
 | class MessageObserver : public StunMessageObserver { | 
 |  public: | 
 |   MessageObserver(unsigned int* message_counter, | 
 |                   unsigned int* channel_data_counter, | 
 |                   unsigned int* attr_counter) | 
 |       : message_counter_(message_counter), | 
 |         channel_data_counter_(channel_data_counter), | 
 |         attr_counter_(attr_counter) {} | 
 |   virtual ~MessageObserver() {} | 
 |   void ReceivedMessage(const TurnMessage* msg) override { | 
 |     if (message_counter_ != nullptr) { | 
 |       (*message_counter_)++; | 
 |     } | 
 |     // Implementation defined attributes are returned as ByteString | 
 |     const StunByteStringAttribute* attr = | 
 |         msg->GetByteString(TestTurnCustomizer::STUN_ATTR_COUNTER); | 
 |     if (attr != nullptr && attr_counter_ != nullptr) { | 
 |       rtc::ByteBufferReader buf(attr->bytes(), attr->length()); | 
 |       unsigned int val = ~0u; | 
 |       buf.ReadUInt32(&val); | 
 |       (*attr_counter_)++; | 
 |     } | 
 |   } | 
 |  | 
 |   void ReceivedChannelData(const char* data, size_t size) override { | 
 |     if (channel_data_counter_ != nullptr) { | 
 |       (*channel_data_counter_)++; | 
 |     } | 
 |   } | 
 |  | 
 |   // Number of TurnMessages observed. | 
 |   unsigned int* message_counter_ = nullptr; | 
 |  | 
 |   // Number of channel data observed. | 
 |   unsigned int* channel_data_counter_ = nullptr; | 
 |  | 
 |   // Number of TurnMessages that had STUN_ATTR_COUNTER. | 
 |   unsigned int* attr_counter_ = nullptr; | 
 | }; | 
 |  | 
 | // Do a TURN allocation, establish a TLS connection, and send some data. | 
 | // Add customizer and check that it get called. | 
 | TEST_F(TurnPortTest, TestTurnCustomizerCount) { | 
 |   unsigned int observer_message_counter = 0; | 
 |   unsigned int observer_channel_data_counter = 0; | 
 |   unsigned int observer_attr_counter = 0; | 
 |   TestTurnCustomizer* customizer = new TestTurnCustomizer(); | 
 |   std::unique_ptr<MessageObserver> validator(new MessageObserver( | 
 |       &observer_message_counter, &observer_channel_data_counter, | 
 |       &observer_attr_counter)); | 
 |  | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS); | 
 |   turn_customizer_.reset(customizer); | 
 |   turn_server_.server()->SetStunMessageObserver(std::move(validator)); | 
 |  | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr); | 
 |   TestTurnSendData(PROTO_TLS); | 
 |   EXPECT_EQ(TLS_PROTOCOL_NAME, turn_port_->Candidates()[0].relay_protocol()); | 
 |  | 
 |   // There should have been at least turn_packets_.size() calls to |customizer|. | 
 |   EXPECT_GE(customizer->modify_cnt_ + customizer->allow_channel_data_cnt_, | 
 |             turn_packets_.size()); | 
 |  | 
 |   // Some channel data should be received. | 
 |   EXPECT_GE(observer_channel_data_counter, 0u); | 
 |  | 
 |   // Need to release TURN port before the customizer. | 
 |   turn_port_.reset(nullptr); | 
 | } | 
 |  | 
 | // Do a TURN allocation, establish a TLS connection, and send some data. | 
 | // Add customizer and check that it can can prevent usage of channel data. | 
 | TEST_F(TurnPortTest, TestTurnCustomizerDisallowChannelData) { | 
 |   unsigned int observer_message_counter = 0; | 
 |   unsigned int observer_channel_data_counter = 0; | 
 |   unsigned int observer_attr_counter = 0; | 
 |   TestTurnCustomizer* customizer = new TestTurnCustomizer(); | 
 |   std::unique_ptr<MessageObserver> validator(new MessageObserver( | 
 |       &observer_message_counter, &observer_channel_data_counter, | 
 |       &observer_attr_counter)); | 
 |   customizer->allow_channel_data_ = false; | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS); | 
 |   turn_customizer_.reset(customizer); | 
 |   turn_server_.server()->SetStunMessageObserver(std::move(validator)); | 
 |  | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr); | 
 |   TestTurnSendData(PROTO_TLS); | 
 |   EXPECT_EQ(TLS_PROTOCOL_NAME, turn_port_->Candidates()[0].relay_protocol()); | 
 |  | 
 |   // There should have been at least turn_packets_.size() calls to |customizer|. | 
 |   EXPECT_GE(customizer->modify_cnt_, turn_packets_.size()); | 
 |  | 
 |   // No channel data should be received. | 
 |   EXPECT_EQ(observer_channel_data_counter, 0u); | 
 |  | 
 |   // Need to release TURN port before the customizer. | 
 |   turn_port_.reset(nullptr); | 
 | } | 
 |  | 
 | // Do a TURN allocation, establish a TLS connection, and send some data. | 
 | // Add customizer and check that it can add attribute to messages. | 
 | TEST_F(TurnPortTest, TestTurnCustomizerAddAttribute) { | 
 |   unsigned int observer_message_counter = 0; | 
 |   unsigned int observer_channel_data_counter = 0; | 
 |   unsigned int observer_attr_counter = 0; | 
 |   TestTurnCustomizer* customizer = new TestTurnCustomizer(); | 
 |   std::unique_ptr<MessageObserver> validator(new MessageObserver( | 
 |       &observer_message_counter, &observer_channel_data_counter, | 
 |       &observer_attr_counter)); | 
 |   customizer->allow_channel_data_ = false; | 
 |   customizer->add_counter_ = true; | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS); | 
 |   turn_customizer_.reset(customizer); | 
 |   turn_server_.server()->SetStunMessageObserver(std::move(validator)); | 
 |  | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr); | 
 |   TestTurnSendData(PROTO_TLS); | 
 |   EXPECT_EQ(TLS_PROTOCOL_NAME, turn_port_->Candidates()[0].relay_protocol()); | 
 |  | 
 |   // There should have been at least turn_packets_.size() calls to |customizer|. | 
 |   EXPECT_GE(customizer->modify_cnt_, turn_packets_.size()); | 
 |  | 
 |   // Everything will be sent as messages since channel data is disallowed. | 
 |   EXPECT_GE(customizer->modify_cnt_, observer_message_counter); | 
 |  | 
 |   // All messages should have attribute. | 
 |   EXPECT_EQ(observer_message_counter, observer_attr_counter); | 
 |  | 
 |   // At least allow_channel_data_cnt_ messages should have been sent. | 
 |   EXPECT_GE(customizer->modify_cnt_, customizer->allow_channel_data_cnt_); | 
 |   EXPECT_GE(customizer->allow_channel_data_cnt_, 0u); | 
 |  | 
 |   // No channel data should be received. | 
 |   EXPECT_EQ(observer_channel_data_counter, 0u); | 
 |  | 
 |   // Need to release TURN port before the customizer. | 
 |   turn_port_.reset(nullptr); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestOverlongUsername) { | 
 |   std::string overlong_username(513, 'x'); | 
 |   RelayCredentials credentials(overlong_username, kTurnPassword); | 
 |   EXPECT_FALSE( | 
 |       CreateTurnPort(overlong_username, kTurnPassword, kTurnTlsProtoAddr)); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnDangerousServer) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnDangerousProtoAddr); | 
 |   ASSERT_FALSE(turn_port_); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnDangerousServerPermits53) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnPort53ProtoAddr); | 
 |   ASSERT_TRUE(turn_port_); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnDangerousServerPermits80) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnPort80ProtoAddr); | 
 |   ASSERT_TRUE(turn_port_); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnDangerousServerPermits443) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnPort443ProtoAddr); | 
 |   ASSERT_TRUE(turn_port_); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnDangerousAlternateServer) { | 
 |   const ProtocolType protocol_type = PROTO_TCP; | 
 |   std::vector<rtc::SocketAddress> redirect_addresses; | 
 |   redirect_addresses.push_back(kTurnDangerousAddr); | 
 |  | 
 |   TestTurnRedirector redirector(redirect_addresses); | 
 |  | 
 |   turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type); | 
 |   turn_server_.AddInternalSocket(kTurnDangerousAddr, protocol_type); | 
 |   turn_server_.set_redirect_hook(&redirector); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, | 
 |                  ProtocolAddress(kTurnIntAddr, protocol_type)); | 
 |  | 
 |   // Retrieve the address before we run the state machine. | 
 |   const SocketAddress old_addr = turn_port_->server_address().address; | 
 |  | 
 |   turn_port_->PrepareAddress(); | 
 |   // This should result in an error event. | 
 |   EXPECT_TRUE_SIMULATED_WAIT(error_event_.error_code != 0, | 
 |                              TimeToGetAlternateTurnCandidate(protocol_type), | 
 |                              fake_clock_); | 
 |   // but should NOT result in the port turning ready, and no candidates | 
 |   // should be gathered. | 
 |   EXPECT_FALSE(turn_ready_); | 
 |   ASSERT_EQ(0U, turn_port_->Candidates().size()); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnDangerousServerAllowedWithFieldTrial) { | 
 |   webrtc::test::ScopedFieldTrials override_field_trials( | 
 |       "WebRTC-Turn-AllowSystemPorts/Enabled/"); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnDangerousProtoAddr); | 
 |   ASSERT_TRUE(turn_port_); | 
 | } | 
 |  | 
 | }  // namespace cricket |