| /* | 
 |  *  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 "webrtc/p2p/base/basicpacketsocketfactory.h" | 
 | #include "webrtc/p2p/base/constants.h" | 
 | #include "webrtc/p2p/base/tcpport.h" | 
 | #include "webrtc/p2p/base/testturnserver.h" | 
 | #include "webrtc/p2p/base/turnport.h" | 
 | #include "webrtc/p2p/base/udpport.h" | 
 | #include "webrtc/base/asynctcpsocket.h" | 
 | #include "webrtc/base/buffer.h" | 
 | #include "webrtc/base/dscp.h" | 
 | #include "webrtc/base/firewallsocketserver.h" | 
 | #include "webrtc/base/gunit.h" | 
 | #include "webrtc/base/helpers.h" | 
 | #include "webrtc/base/logging.h" | 
 | #include "webrtc/base/physicalsocketserver.h" | 
 | #include "webrtc/base/scoped_ptr.h" | 
 | #include "webrtc/base/socketaddress.h" | 
 | #include "webrtc/base/ssladapter.h" | 
 | #include "webrtc/base/thread.h" | 
 | #include "webrtc/base/virtualsocketserver.h" | 
 |  | 
 | using rtc::SocketAddress; | 
 | using cricket::Connection; | 
 | using cricket::Port; | 
 | using cricket::PortInterface; | 
 | using cricket::TurnPort; | 
 | using cricket::UDPPort; | 
 |  | 
 | 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 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); | 
 | 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 kTurnUdpIPv6ExtAddr( | 
 |   "2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0); | 
 |  | 
 | 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"; | 
 | static const unsigned int kTimeout = 1000; | 
 |  | 
 | static const cricket::ProtocolAddress kTurnUdpProtoAddr( | 
 |     kTurnUdpIntAddr, cricket::PROTO_UDP); | 
 | static const cricket::ProtocolAddress kTurnTcpProtoAddr( | 
 |     kTurnTcpIntAddr, cricket::PROTO_TCP); | 
 | static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr( | 
 |     kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); | 
 |  | 
 | 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 | 
 |  | 
 | class TurnPortTestVirtualSocketServer : public rtc::VirtualSocketServer { | 
 |  public: | 
 |   explicit TurnPortTestVirtualSocketServer(SocketServer* ss) | 
 |       : VirtualSocketServer(ss) {} | 
 |  | 
 |   using rtc::VirtualSocketServer::LookupBinding; | 
 | }; | 
 |  | 
 | class TurnPortTest : public testing::Test, | 
 |                      public sigslot::has_slots<>, | 
 |                      public rtc::MessageHandler { | 
 |  public: | 
 |   TurnPortTest() | 
 |       : main_(rtc::Thread::Current()), | 
 |         pss_(new rtc::PhysicalSocketServer), | 
 |         ss_(new TurnPortTestVirtualSocketServer(pss_.get())), | 
 |         ss_scope_(ss_.get()), | 
 |         network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32), | 
 |         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), | 
 |         udp_ready_(false), | 
 |         test_finish_(false) { | 
 |     network_.AddIP(rtc::IPAddress(INADDR_ANY)); | 
 |   } | 
 |  | 
 |   virtual void OnMessage(rtc::Message* msg) { | 
 |     ASSERT(msg->message_id == MSG_TESTFINISH); | 
 |     if (msg->message_id == MSG_TESTFINISH) | 
 |       test_finish_ = true; | 
 |   } | 
 |  | 
 |   void ConnectSignalAddressReadyToSetLocalhostAsAltenertativeLocalAddress() { | 
 |     rtc::AsyncPacketSocket* socket = turn_port_->socket(); | 
 |     rtc::VirtualSocket* virtual_socket = | 
 |         ss_->LookupBinding(socket->GetLocalAddress()); | 
 |     virtual_socket->SignalAddressReady.connect( | 
 |         this, &TurnPortTest::SetLocalhostAsAltenertativeLocalAddress); | 
 |   } | 
 |  | 
 |   void SetLocalhostAsAltenertativeLocalAddress( | 
 |       rtc::VirtualSocket* socket, | 
 |       const rtc::SocketAddress& address) { | 
 |     SocketAddress local_address("127.0.0.1", 2000); | 
 |     socket->SetAlternativeLocalAddress(local_address); | 
 |   } | 
 |  | 
 |   void OnTurnPortComplete(Port* port) { | 
 |     turn_ready_ = true; | 
 |   } | 
 |   void OnTurnPortError(Port* port) { | 
 |     turn_error_ = true; | 
 |   } | 
 |   void OnTurnUnknownAddress(PortInterface* port, const SocketAddress& addr, | 
 |                             cricket::ProtocolType proto, | 
 |                             cricket::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. | 
 |     if (code == 0) { | 
 |       turn_create_permission_success_ = true; | 
 |     } | 
 |   } | 
 |   void OnTurnReadPacket(Connection* conn, const char* data, size_t size, | 
 |                         const rtc::PacketTime& packet_time) { | 
 |     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, | 
 |                        const rtc::PacketTime& packet_time) { | 
 |     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 rtc::PacketTime& packet_time) { | 
 |     turn_port_->HandleIncomingPacket(socket, data, size, remote_addr, | 
 |                                      packet_time); | 
 |   } | 
 |   rtc::AsyncSocket* CreateServerSocket(const SocketAddress addr) { | 
 |     rtc::AsyncSocket* socket = ss_->CreateAsyncSocket(SOCK_STREAM); | 
 |     EXPECT_GE(socket->Bind(addr), 0); | 
 |     EXPECT_GE(socket->Listen(5), 0); | 
 |     return socket; | 
 |   } | 
 |  | 
 |   void CreateTurnPort(const std::string& username, | 
 |                       const std::string& password, | 
 |                       const cricket::ProtocolAddress& server_address) { | 
 |     CreateTurnPort(kLocalAddr1, username, password, server_address); | 
 |   } | 
 |   void CreateTurnPort(const rtc::SocketAddress& local_address, | 
 |                       const std::string& username, | 
 |                       const std::string& password, | 
 |                       const cricket::ProtocolAddress& server_address) { | 
 |     cricket::RelayCredentials credentials(username, password); | 
 |     turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_, | 
 |                                  local_address.ipaddr(), 0, 0, | 
 |                                  kIceUfrag1, kIcePwd1, | 
 |                                  server_address, credentials, 0, | 
 |                                  std::string())); | 
 |     // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be | 
 |     // in Hybrid mode. Protocol type is necessary to send correct type STUN ping | 
 |     // messages. | 
 |     // This TURN port will be the controlling. | 
 |     turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); | 
 |     turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING); | 
 |     ConnectSignals(); | 
 |   } | 
 |  | 
 |   // Should be identical to CreateTurnPort but specifies an origin value | 
 |   // when creating the instance of TurnPort. | 
 |   void CreateTurnPortWithOrigin(const rtc::SocketAddress& local_address, | 
 |                                 const std::string& username, | 
 |                                 const std::string& password, | 
 |                                 const cricket::ProtocolAddress& server_address, | 
 |                                 const std::string& origin) { | 
 |     cricket::RelayCredentials credentials(username, password); | 
 |     turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_, | 
 |                                  local_address.ipaddr(), 0, 0, | 
 |                                  kIceUfrag1, kIcePwd1, | 
 |                                  server_address, credentials, 0, | 
 |                                  origin)); | 
 |     // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be | 
 |     // in Hybrid mode. Protocol type is necessary to send correct type STUN ping | 
 |     // messages. | 
 |     // This TURN port will be the controlling. | 
 |     turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); | 
 |     turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING); | 
 |     ConnectSignals(); | 
 |   } | 
 |  | 
 |   void CreateSharedTurnPort(const std::string& username, | 
 |                             const std::string& password, | 
 |                             const cricket::ProtocolAddress& server_address) { | 
 |     ASSERT(server_address.proto == cricket::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); | 
 |     } | 
 |  | 
 |     cricket::RelayCredentials credentials(username, password); | 
 |     turn_port_.reset(cricket::TurnPort::Create( | 
 |         main_, &socket_factory_, &network_, socket_.get(), | 
 |         kIceUfrag1, kIcePwd1, server_address, credentials, 0, std::string())); | 
 |     // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be | 
 |     // in Hybrid mode. Protocol type is necessary to send correct type STUN ping | 
 |     // messages. | 
 |     // This TURN port will be the controlling. | 
 |     turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); | 
 |     turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING); | 
 |     ConnectSignals(); | 
 |   } | 
 |  | 
 |   void ConnectSignals() { | 
 |     turn_port_->SignalPortComplete.connect(this, | 
 |         &TurnPortTest::OnTurnPortComplete); | 
 |     turn_port_->SignalPortError.connect(this, | 
 |         &TurnPortTest::OnTurnPortError); | 
 |     turn_port_->SignalUnknownAddress.connect(this, | 
 |         &TurnPortTest::OnTurnUnknownAddress); | 
 |     turn_port_->SignalCreatePermissionResult.connect(this, | 
 |         &TurnPortTest::OnTurnCreatePermissionResult); | 
 |   } | 
 |   void CreateUdpPort() { | 
 |     udp_port_.reset(UDPPort::Create(main_, &socket_factory_, &network_, | 
 |                                     kLocalAddr2.ipaddr(), 0, 0, | 
 |                                     kIceUfrag2, kIcePwd2, | 
 |                                     std::string())); | 
 |     // Set protocol type to RFC5245, as turn port is also in same mode. | 
 |     // UDP port will be controlled. | 
 |     udp_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); | 
 |     udp_port_->SetIceRole(cricket::ICEROLE_CONTROLLED); | 
 |     udp_port_->SignalPortComplete.connect( | 
 |         this, &TurnPortTest::OnUdpPortComplete); | 
 |   } | 
 |  | 
 |   void TestTurnAlternateServer(cricket::ProtocolType protocol_type) { | 
 |     std::vector<rtc::SocketAddress> redirect_addresses; | 
 |     redirect_addresses.push_back(kTurnAlternateIntAddr); | 
 |  | 
 |     cricket::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, | 
 |                    cricket::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_WAIT(turn_ready_, kTimeout * 100); | 
 |     // 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(cricket::ProtocolType protocol_type) { | 
 |     std::vector<rtc::SocketAddress> redirect_addresses; | 
 |     redirect_addresses.push_back(kTurnIPv6IntAddr); | 
 |  | 
 |     cricket::TestTurnRedirector redirector(redirect_addresses); | 
 |     turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type); | 
 |     turn_server_.set_redirect_hook(&redirector); | 
 |     CreateTurnPort(kTurnUsername, kTurnPassword, | 
 |                    cricket::ProtocolAddress(kTurnIntAddr, protocol_type)); | 
 |     turn_port_->PrepareAddress(); | 
 |     EXPECT_TRUE_WAIT(turn_error_, kTimeout); | 
 |   } | 
 |  | 
 |   void TestTurnAlternateServerPingPong(cricket::ProtocolType protocol_type) { | 
 |     std::vector<rtc::SocketAddress> redirect_addresses; | 
 |     redirect_addresses.push_back(kTurnAlternateIntAddr); | 
 |     redirect_addresses.push_back(kTurnIntAddr); | 
 |  | 
 |     cricket::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, | 
 |                    cricket::ProtocolAddress(kTurnIntAddr, protocol_type)); | 
 |  | 
 |     turn_port_->PrepareAddress(); | 
 |     EXPECT_TRUE_WAIT(turn_error_, kTimeout); | 
 |     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( | 
 |       cricket::ProtocolType protocol_type) { | 
 |     std::vector<rtc::SocketAddress> redirect_addresses; | 
 |     redirect_addresses.push_back(kTurnAlternateIntAddr); | 
 |     redirect_addresses.push_back(kTurnAlternateIntAddr); | 
 |  | 
 |     cricket::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, | 
 |                    cricket::ProtocolAddress(kTurnIntAddr, protocol_type)); | 
 |  | 
 |     turn_port_->PrepareAddress(); | 
 |     EXPECT_TRUE_WAIT(turn_error_, kTimeout); | 
 |     ASSERT_EQ(0U, turn_port_->Candidates().size()); | 
 |   } | 
 |  | 
 |   void TestTurnConnection() { | 
 |     // Create ports and prepare addresses. | 
 |     ASSERT_TRUE(turn_port_ != NULL); | 
 |     turn_port_->PrepareAddress(); | 
 |     ASSERT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |     CreateUdpPort(); | 
 |     udp_port_->PrepareAddress(); | 
 |     ASSERT_TRUE_WAIT(udp_ready_, kTimeout); | 
 |  | 
 |     // Send ping from UDP to TURN. | 
 |     Connection* conn1 = udp_port_->CreateConnection( | 
 |                     turn_port_->Candidates()[0], Port::ORIGIN_MESSAGE); | 
 |     ASSERT_TRUE(conn1 != NULL); | 
 |     conn1->Ping(0); | 
 |     WAIT(!turn_unknown_address_, kTimeout); | 
 |     EXPECT_FALSE(turn_unknown_address_); | 
 |     EXPECT_EQ(Connection::STATE_READ_INIT, conn1->read_state()); | 
 |     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_WAIT(turn_create_permission_success_, kTimeout); | 
 |     conn2->Ping(0); | 
 |  | 
 |     EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout); | 
 |     EXPECT_EQ(Connection::STATE_READABLE, conn1->read_state()); | 
 |     EXPECT_EQ(Connection::STATE_READ_INIT, conn2->read_state()); | 
 |     EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state()); | 
 |  | 
 |     // Send another ping from UDP to TURN. | 
 |     conn1->Ping(0); | 
 |     EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout); | 
 |     EXPECT_EQ(Connection::STATE_READABLE, conn2->read_state()); | 
 |   } | 
 |  | 
 |   void TestTurnSendData() { | 
 |     turn_port_->PrepareAddress(); | 
 |     EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |     CreateUdpPort(); | 
 |     udp_port_->PrepareAddress(); | 
 |     EXPECT_TRUE_WAIT(udp_ready_, kTimeout); | 
 |     // 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_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout); | 
 |     conn2->Ping(0); | 
 |     EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout); | 
 |  | 
 |     // 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); | 
 |       main_->ProcessMessages(0); | 
 |     } | 
 |  | 
 |     // Check the data. | 
 |     ASSERT_EQ_WAIT(num_packets, turn_packets_.size(), kTimeout); | 
 |     ASSERT_EQ_WAIT(num_packets, udp_packets_.size(), kTimeout); | 
 |     for (size_t i = 0; i < num_packets; ++i) { | 
 |       EXPECT_EQ(i + 1, turn_packets_[i].length()); | 
 |       EXPECT_EQ(i + 1, udp_packets_[i].length()); | 
 |       EXPECT_EQ(turn_packets_[i], udp_packets_[i]); | 
 |     } | 
 |   } | 
 |  | 
 |  protected: | 
 |   rtc::Thread* main_; | 
 |   rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_; | 
 |   rtc::scoped_ptr<TurnPortTestVirtualSocketServer> ss_; | 
 |   rtc::SocketServerScope ss_scope_; | 
 |   rtc::Network network_; | 
 |   rtc::BasicPacketSocketFactory socket_factory_; | 
 |   rtc::scoped_ptr<rtc::AsyncPacketSocket> socket_; | 
 |   cricket::TestTurnServer turn_server_; | 
 |   rtc::scoped_ptr<TurnPort> turn_port_; | 
 |   rtc::scoped_ptr<UDPPort> udp_port_; | 
 |   bool turn_ready_; | 
 |   bool turn_error_; | 
 |   bool turn_unknown_address_; | 
 |   bool turn_create_permission_success_; | 
 |   bool udp_ready_; | 
 |   bool test_finish_; | 
 |   std::vector<rtc::Buffer> turn_packets_; | 
 |   std::vector<rtc::Buffer> udp_packets_; | 
 |   rtc::PacketOptions options; | 
 | }; | 
 |  | 
 | // 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_WAIT(turn_ready_, kTimeout); | 
 |   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()); | 
 | } | 
 |  | 
 | // Testing a normal UDP allocation using TCP connection. | 
 | TEST_F(TurnPortTest, TestTurnTcpAllocate) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   EXPECT_EQ(0, turn_port_->SetOption(rtc::Socket::OPT_SNDBUF, 10*1024)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |   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) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   EXPECT_EQ(0, turn_port_->SetOption(rtc::Socket::OPT_SNDBUF, 10 * 1024)); | 
 |   turn_port_->PrepareAddress(); | 
 |   ConnectSignalAddressReadyToSetLocalhostAsAltenertativeLocalAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |   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()); | 
 | } | 
 |  | 
 | // Testing turn port will attempt to create TCP socket on address resolution | 
 | // failure. | 
 | TEST_F(TurnPortTest, DISABLED_TestTurnTcpOnAddressResolveFailure) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, cricket::ProtocolAddress( | 
 |       rtc::SocketAddress("www.webrtc-blah-blah.com", 3478), | 
 |       cricket::PROTO_TCP)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_error_, kTimeout); | 
 |   // 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()); | 
 | } | 
 |  | 
 | // In case of UDP on address resolve failure, TurnPort will not create socket | 
 | // and return allocate failure. | 
 | TEST_F(TurnPortTest, DISABLED_TestTurnUdpOnAdressResolveFailure) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, cricket::ProtocolAddress( | 
 |       rtc::SocketAddress("www.webrtc-blah-blah.com", 3478), | 
 |       cricket::PROTO_UDP)); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_error_, kTimeout); | 
 |   // 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_WAIT(turn_error_, kTimeout); | 
 |   ASSERT_EQ(0U, turn_port_->Candidates().size()); | 
 | } | 
 |  | 
 | // 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_WAIT(turn_ready_, kTimeout); | 
 |   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()); | 
 |  | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |  | 
 |   // Verifies that the new port has a different address now. | 
 |   EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); | 
 | } | 
 |  | 
 | // 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_WAIT(turn_ready_, kTimeout); | 
 |   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(); | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |  | 
 |   // 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, cricket::PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |  | 
 |   // Do a normal allocation first. | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |   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()); | 
 |  | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |  | 
 |   // Verifies that the new port has a different address now. | 
 |   EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); | 
 | } | 
 |  | 
 | // Test try-alternate-server feature. | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerUDP) { | 
 |   TestTurnAlternateServer(cricket::PROTO_UDP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerTCP) { | 
 |   TestTurnAlternateServer(cricket::PROTO_TCP); | 
 | } | 
 |  | 
 | // Test that we fail when we redirect to an address different from | 
 | // current IP family. | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6UDP) { | 
 |   TestTurnAlternateServerV4toV6(cricket::PROTO_UDP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6TCP) { | 
 |   TestTurnAlternateServerV4toV6(cricket::PROTO_TCP); | 
 | } | 
 |  | 
 | // Test try-alternate-server catches the case of pingpong. | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerPingPongUDP) { | 
 |   TestTurnAlternateServerPingPong(cricket::PROTO_UDP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerPingPongTCP) { | 
 |   TestTurnAlternateServerPingPong(cricket::PROTO_TCP); | 
 | } | 
 |  | 
 | // Test try-alternate-server catch the case of repeated server. | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetitionUDP) { | 
 |   TestTurnAlternateServerDetectRepetition(cricket::PROTO_UDP); | 
 | } | 
 |  | 
 | TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetitionTCP) { | 
 |   TestTurnAlternateServerDetectRepetition(cricket::PROTO_TCP); | 
 | } | 
 |  | 
 | // 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(); | 
 | } | 
 |  | 
 | // Similar to above, except that this test will use the shared socket. | 
 | TEST_F(TurnPortTest, TestTurnConnectionUsingSharedSocket) { | 
 |   CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   TestTurnConnection(); | 
 | } | 
 |  | 
 | // Test that we can establish a TCP connection with TURN server. | 
 | TEST_F(TurnPortTest, TestTurnTcpConnection) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   TestTurnConnection(); | 
 | } | 
 |  | 
 | // Test that we fail to create a connection when we want to use TLS over TCP. | 
 | // This test should be removed once we have TLS support. | 
 | TEST_F(TurnPortTest, TestTurnTlsTcpConnectionFails) { | 
 |   cricket::ProtocolAddress secure_addr(kTurnTcpProtoAddr.address, | 
 |                                        kTurnTcpProtoAddr.proto, | 
 |                                        true); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, secure_addr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_error_, kTimeout); | 
 |   ASSERT_EQ(0U, turn_port_->Candidates().size()); | 
 | } | 
 |  | 
 | // 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(); | 
 | } | 
 |  | 
 | // 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(); | 
 | } | 
 |  | 
 | // Do a TURN allocation, establish a TCP connection, and send some data. | 
 | TEST_F(TurnPortTest, TestTurnSendDataTurnTcpToUdp) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); | 
 |   // Create ports and prepare addresses. | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   TestTurnSendData(); | 
 | } | 
 |  | 
 | // 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, cricket::PROTO_UDP); | 
 |   CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, | 
 |                  kTurnUdpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   ASSERT_TRUE_WAIT(turn_error_, kTimeout); | 
 |   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, cricket::PROTO_UDP); | 
 |   CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, | 
 |                  kTurnUdpIPv6ProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |   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, TestOriginHeader) { | 
 |   CreateTurnPortWithOrigin(kLocalAddr1, kTurnUsername, kTurnPassword, | 
 |                            kTurnUdpProtoAddr, kTestOrigin); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |   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 TURN allocation is released when the port is closed. | 
 | TEST_F(TurnPortTest, TestTurnReleaseAllocation) { | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |  | 
 |   ASSERT_GT(turn_server_.server()->allocations().size(), 0U); | 
 |   turn_port_.reset(); | 
 |   EXPECT_EQ_WAIT(0U, turn_server_.server()->allocations().size(), kTimeout); | 
 | } | 
 |  | 
 | // Test that a TURN TCP allocation is released when the port is closed. | 
 | TEST_F(TurnPortTest, DISABLED_TestTurnTCPReleaseAllocation) { | 
 |   turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); | 
 |   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); | 
 |   turn_port_->PrepareAddress(); | 
 |   EXPECT_TRUE_WAIT(turn_ready_, kTimeout); | 
 |  | 
 |   ASSERT_GT(turn_server_.server()->allocations().size(), 0U); | 
 |   turn_port_.reset(); | 
 |   EXPECT_EQ_WAIT(0U, turn_server_.server()->allocations().size(), kTimeout); | 
 | } | 
 |  | 
 | // 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, cricket::PROTO_UDP); | 
 |   int last_fd_count = GetFDCount(); | 
 |   // Need to supply unresolved address to kick off resolver. | 
 |   CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, | 
 |                  cricket::ProtocolAddress(rtc::SocketAddress( | 
 |                     "stun.l.google.com", 3478), cricket::PROTO_UDP)); | 
 |   turn_port_->PrepareAddress(); | 
 |   ASSERT_TRUE_WAIT(turn_error_, kTimeout); | 
 |   EXPECT_TRUE(turn_port_->Candidates().empty()); | 
 |   turn_port_.reset(); | 
 |   rtc::Thread::Current()->Post(this, MSG_TESTFINISH); | 
 |   // Waiting for above message to be processed. | 
 |   ASSERT_TRUE_WAIT(test_finish_, kTimeout); | 
 |   EXPECT_EQ(last_fd_count, GetFDCount()); | 
 | } | 
 | #endif |