 f875f15afb
			
		
	
	f875f15afb
	
	
	
		
			
			git-svn-id: http://webrtc.googlecode.com/svn/trunk@5897 4adac7df-926f-26a2-2b94-8c16560cd09d
		
			
				
	
	
		
			352 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			352 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2011 Google Inc. All Rights Reserved.
 | |
| 
 | |
| 
 | |
| #include <string>
 | |
| 
 | |
| #include "talk/base/asynchttprequest.h"
 | |
| #include "talk/base/gunit.h"
 | |
| #include "talk/base/fakenetwork.h"
 | |
| #include "talk/base/scoped_ptr.h"
 | |
| #include "talk/base/socketaddress.h"
 | |
| #include "talk/p2p/base/basicpacketsocketfactory.h"
 | |
| #include "talk/p2p/base/relayport.h"
 | |
| #include "talk/p2p/base/stunport.h"
 | |
| #include "talk/p2p/client/connectivitychecker.h"
 | |
| #include "talk/p2p/client/httpportallocator.h"
 | |
| 
 | |
| namespace cricket {
 | |
| 
 | |
| static const talk_base::SocketAddress kClientAddr1("11.11.11.11", 0);
 | |
| static const talk_base::SocketAddress kClientAddr2("22.22.22.22", 0);
 | |
| static const talk_base::SocketAddress kExternalAddr("33.33.33.33", 3333);
 | |
| static const talk_base::SocketAddress kStunAddr("44.44.44.44", 4444);
 | |
| static const talk_base::SocketAddress kRelayAddr("55.55.55.55", 5555);
 | |
| static const talk_base::SocketAddress kProxyAddr("66.66.66.66", 6666);
 | |
| static const talk_base::ProxyType kProxyType = talk_base::PROXY_HTTPS;
 | |
| static const char kRelayHost[] = "relay.google.com";
 | |
| static const char kRelayToken[] =
 | |
|     "CAESFwoOb2phQGdvb2dsZS5jb20Q043h47MmGhBTB1rbfIXkhuarDCZe+xF6";
 | |
| static const char kBrowserAgent[] = "browser_test";
 | |
| static const char kJid[] = "a.b@c";
 | |
| static const char kUserName[] = "testuser";
 | |
| static const char kPassword[] = "testpassword";
 | |
| static const char kMagicCookie[] = "testcookie";
 | |
| static const char kRelayUdpPort[] = "4444";
 | |
| static const char kRelayTcpPort[] = "5555";
 | |
| static const char kRelaySsltcpPort[] = "6666";
 | |
| static const char kSessionId[] = "testsession";
 | |
| static const char kConnection[] = "testconnection";
 | |
| static const int kMinPort = 1000;
 | |
| static const int kMaxPort = 2000;
 | |
| 
 | |
| // Fake implementation to mock away real network usage.
 | |
| class FakeRelayPort : public RelayPort {
 | |
|  public:
 | |
|   FakeRelayPort(talk_base::Thread* thread,
 | |
|                 talk_base::PacketSocketFactory* factory,
 | |
|                 talk_base::Network* network, const talk_base::IPAddress& ip,
 | |
|                 int min_port, int max_port,
 | |
|                 const std::string& username, const std::string& password)
 | |
|       : RelayPort(thread, factory, network, ip, min_port, max_port,
 | |
|                   username, password) {
 | |
|   }
 | |
| 
 | |
|   // Just signal that we are done.
 | |
|   virtual void PrepareAddress() {
 | |
|     SignalPortComplete(this);
 | |
|   }
 | |
| };
 | |
| 
 | |
| // Fake implementation to mock away real network usage.
 | |
| class FakeStunPort : public StunPort {
 | |
|  public:
 | |
|   FakeStunPort(talk_base::Thread* thread,
 | |
|                talk_base::PacketSocketFactory* factory,
 | |
|                talk_base::Network* network,
 | |
|                const talk_base::IPAddress& ip,
 | |
|                int min_port, int max_port,
 | |
|                const std::string& username, const std::string& password,
 | |
|                const talk_base::SocketAddress& server_addr)
 | |
|       : StunPort(thread, factory, network, ip, min_port, max_port,
 | |
|                  username, password, server_addr) {
 | |
|   }
 | |
| 
 | |
|   // Just set external address and signal that we are done.
 | |
|   virtual void PrepareAddress() {
 | |
|     AddAddress(kExternalAddr, kExternalAddr, talk_base::SocketAddress(), "udp",
 | |
|                STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, true);
 | |
|     SignalPortComplete(this);
 | |
|   }
 | |
| };
 | |
| 
 | |
| // Fake implementation to mock away real network usage by responding
 | |
| // to http requests immediately.
 | |
| class FakeHttpPortAllocatorSession : public TestHttpPortAllocatorSession {
 | |
|  public:
 | |
|   FakeHttpPortAllocatorSession(
 | |
|       HttpPortAllocator* allocator,
 | |
|       const std::string& content_name,
 | |
|       int component,
 | |
|       const std::string& ice_ufrag, const std::string& ice_pwd,
 | |
|       const std::vector<talk_base::SocketAddress>& stun_hosts,
 | |
|       const std::vector<std::string>& relay_hosts,
 | |
|       const std::string& relay_token,
 | |
|       const std::string& agent)
 | |
|       : TestHttpPortAllocatorSession(allocator,
 | |
|                                      content_name,
 | |
|                                      component,
 | |
|                                      ice_ufrag,
 | |
|                                      ice_pwd,
 | |
|                                      stun_hosts,
 | |
|                                      relay_hosts,
 | |
|                                      relay_token,
 | |
|                                      agent) {
 | |
|   }
 | |
|   virtual void SendSessionRequest(const std::string& host, int port) {
 | |
|     FakeReceiveSessionResponse(host, port);
 | |
|   }
 | |
| 
 | |
|   // Pass results to the real implementation.
 | |
|   void FakeReceiveSessionResponse(const std::string& host, int port) {
 | |
|     talk_base::AsyncHttpRequest* response = CreateAsyncHttpResponse(port);
 | |
|     TestHttpPortAllocatorSession::OnRequestDone(response);
 | |
|     response->Destroy(true);
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   // Helper method for creating a response to a relay session request.
 | |
|   talk_base::AsyncHttpRequest* CreateAsyncHttpResponse(int port) {
 | |
|     talk_base::AsyncHttpRequest* request =
 | |
|         new talk_base::AsyncHttpRequest(kBrowserAgent);
 | |
|     std::stringstream ss;
 | |
|     ss << "username=" << kUserName << std::endl
 | |
|        << "password=" << kPassword << std::endl
 | |
|        << "magic_cookie=" << kMagicCookie << std::endl
 | |
|        << "relay.ip=" << kRelayAddr.ipaddr().ToString() << std::endl
 | |
|        << "relay.udp_port=" << kRelayUdpPort << std::endl
 | |
|        << "relay.tcp_port=" << kRelayTcpPort << std::endl
 | |
|        << "relay.ssltcp_port=" << kRelaySsltcpPort << std::endl;
 | |
|     request->response().document.reset(
 | |
|         new talk_base::MemoryStream(ss.str().c_str()));
 | |
|     request->response().set_success();
 | |
|     request->set_port(port);
 | |
|     request->set_secure(port == talk_base::HTTP_SECURE_PORT);
 | |
|     return request;
 | |
|   }
 | |
| };
 | |
| 
 | |
| // Fake implementation for creating fake http sessions.
 | |
| class FakeHttpPortAllocator : public HttpPortAllocator {
 | |
|  public:
 | |
|   FakeHttpPortAllocator(talk_base::NetworkManager* network_manager,
 | |
|                         const std::string& user_agent)
 | |
|       : HttpPortAllocator(network_manager, user_agent) {
 | |
|   }
 | |
| 
 | |
|   virtual PortAllocatorSession* CreateSessionInternal(
 | |
|       const std::string& content_name, int component,
 | |
|       const std::string& ice_ufrag, const std::string& ice_pwd) {
 | |
|     std::vector<talk_base::SocketAddress> stun_hosts;
 | |
|     stun_hosts.push_back(kStunAddr);
 | |
|     std::vector<std::string> relay_hosts;
 | |
|     relay_hosts.push_back(kRelayHost);
 | |
|     return new FakeHttpPortAllocatorSession(this,
 | |
|                                             content_name,
 | |
|                                             component,
 | |
|                                             ice_ufrag,
 | |
|                                             ice_pwd,
 | |
|                                             stun_hosts,
 | |
|                                             relay_hosts,
 | |
|                                             kRelayToken,
 | |
|                                             kBrowserAgent);
 | |
|   }
 | |
| };
 | |
| 
 | |
| class ConnectivityCheckerForTest : public ConnectivityChecker {
 | |
|  public:
 | |
|   ConnectivityCheckerForTest(talk_base::Thread* worker,
 | |
|                              const std::string& jid,
 | |
|                              const std::string& session_id,
 | |
|                              const std::string& user_agent,
 | |
|                              const std::string& relay_token,
 | |
|                              const std::string& connection)
 | |
|       : ConnectivityChecker(worker,
 | |
|                             jid,
 | |
|                             session_id,
 | |
|                             user_agent,
 | |
|                             relay_token,
 | |
|                             connection),
 | |
|         proxy_initiated_(false) {
 | |
|   }
 | |
| 
 | |
|   talk_base::FakeNetworkManager* network_manager() const {
 | |
|     return network_manager_;
 | |
|   }
 | |
| 
 | |
|   FakeHttpPortAllocator* port_allocator() const {
 | |
|     return fake_port_allocator_;
 | |
|   }
 | |
| 
 | |
|  protected:
 | |
|   // Overridden methods for faking a real network.
 | |
|   virtual talk_base::NetworkManager* CreateNetworkManager() {
 | |
|     network_manager_ = new talk_base::FakeNetworkManager();
 | |
|     return network_manager_;
 | |
|   }
 | |
|   virtual talk_base::BasicPacketSocketFactory* CreateSocketFactory(
 | |
|       talk_base::Thread* thread) {
 | |
|     // Create socket factory, for simplicity, let it run on the current thread.
 | |
|     socket_factory_ =
 | |
|         new talk_base::BasicPacketSocketFactory(talk_base::Thread::Current());
 | |
|     return socket_factory_;
 | |
|   }
 | |
|   virtual HttpPortAllocator* CreatePortAllocator(
 | |
|       talk_base::NetworkManager* network_manager,
 | |
|       const std::string& user_agent,
 | |
|       const std::string& relay_token) {
 | |
|     fake_port_allocator_ =
 | |
|         new FakeHttpPortAllocator(network_manager, user_agent);
 | |
|     return fake_port_allocator_;
 | |
|   }
 | |
|   virtual StunPort* CreateStunPort(
 | |
|       const std::string& username, const std::string& password,
 | |
|       const PortConfiguration* config, talk_base::Network* network) {
 | |
|     return new FakeStunPort(worker(), socket_factory_,
 | |
|                             network, network->ip(),
 | |
|                             kMinPort, kMaxPort,
 | |
|                             username, password,
 | |
|                             config->stun_address);
 | |
|   }
 | |
|   virtual RelayPort* CreateRelayPort(
 | |
|       const std::string& username, const std::string& password,
 | |
|       const PortConfiguration* config, talk_base::Network* network) {
 | |
|     return new FakeRelayPort(worker(), socket_factory_,
 | |
|                              network, network->ip(),
 | |
|                              kMinPort, kMaxPort,
 | |
|                              username, password);
 | |
|   }
 | |
|   virtual void InitiateProxyDetection() {
 | |
|     if (!proxy_initiated_) {
 | |
|       proxy_initiated_ = true;
 | |
|       proxy_info_.address = kProxyAddr;
 | |
|       proxy_info_.type = kProxyType;
 | |
|       SetProxyInfo(proxy_info_);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   virtual talk_base::ProxyInfo GetProxyInfo() const {
 | |
|     return proxy_info_;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   talk_base::BasicPacketSocketFactory* socket_factory_;
 | |
|   FakeHttpPortAllocator* fake_port_allocator_;
 | |
|   talk_base::FakeNetworkManager* network_manager_;
 | |
|   talk_base::ProxyInfo proxy_info_;
 | |
|   bool proxy_initiated_;
 | |
| };
 | |
| 
 | |
| class ConnectivityCheckerTest : public testing::Test {
 | |
|  protected:
 | |
|   void VerifyNic(const NicInfo& info,
 | |
|                  const talk_base::SocketAddress& local_address) {
 | |
|     // Verify that the external address has been set.
 | |
|     EXPECT_EQ(kExternalAddr, info.external_address);
 | |
| 
 | |
|     // Verify that the stun server address has been set.
 | |
|     EXPECT_EQ(kStunAddr, info.stun_server_address);
 | |
| 
 | |
|     // Verify that the media server address has been set. Don't care
 | |
|     // about port since it is different for different protocols.
 | |
|     EXPECT_EQ(kRelayAddr.ipaddr(), info.media_server_address.ipaddr());
 | |
| 
 | |
|     // Verify that local ip matches.
 | |
|     EXPECT_EQ(local_address.ipaddr(), info.ip);
 | |
| 
 | |
|     // Verify that we have received responses for our
 | |
|     // pings. Unsuccessful ping has rtt value -1, successful >= 0.
 | |
|     EXPECT_GE(info.stun.rtt, 0);
 | |
|     EXPECT_GE(info.udp.rtt, 0);
 | |
|     EXPECT_GE(info.tcp.rtt, 0);
 | |
|     EXPECT_GE(info.ssltcp.rtt, 0);
 | |
| 
 | |
|     // If proxy has been set, verify address and type.
 | |
|     if (!info.proxy_info.address.IsNil()) {
 | |
|       EXPECT_EQ(kProxyAddr, info.proxy_info.address);
 | |
|       EXPECT_EQ(kProxyType, info.proxy_info.type);
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| // Tests a configuration with two network interfaces. Verifies that 4
 | |
| // combinations of ip/proxy are created and that all protocols are
 | |
| // tested on each combination.
 | |
| TEST_F(ConnectivityCheckerTest, TestStart) {
 | |
|   ConnectivityCheckerForTest connectivity_checker(talk_base::Thread::Current(),
 | |
|                                                   kJid,
 | |
|                                                   kSessionId,
 | |
|                                                   kBrowserAgent,
 | |
|                                                   kRelayToken,
 | |
|                                                   kConnection);
 | |
|   connectivity_checker.Initialize();
 | |
|   connectivity_checker.set_stun_address(kStunAddr);
 | |
|   connectivity_checker.network_manager()->AddInterface(kClientAddr1);
 | |
|   connectivity_checker.network_manager()->AddInterface(kClientAddr2);
 | |
| 
 | |
|   connectivity_checker.Start();
 | |
|   talk_base::Thread::Current()->ProcessMessages(1000);
 | |
| 
 | |
|   NicMap nics = connectivity_checker.GetResults();
 | |
| 
 | |
|   // There should be 4 nics in our map. 2 for each interface added,
 | |
|   // one with proxy set and one without.
 | |
|   EXPECT_EQ(4U, nics.size());
 | |
| 
 | |
|   // First verify interfaces without proxy.
 | |
|   talk_base::SocketAddress nilAddress;
 | |
| 
 | |
|   // First lookup the address of the first nic combined with no proxy.
 | |
|   NicMap::iterator i = nics.find(NicId(kClientAddr1.ipaddr(), nilAddress));
 | |
|   ASSERT(i != nics.end());
 | |
|   NicInfo info = i->second;
 | |
|   VerifyNic(info, kClientAddr1);
 | |
| 
 | |
|   // Then make sure the second device has been tested without proxy.
 | |
|   i = nics.find(NicId(kClientAddr2.ipaddr(), nilAddress));
 | |
|   ASSERT(i != nics.end());
 | |
|   info = i->second;
 | |
|   VerifyNic(info, kClientAddr2);
 | |
| 
 | |
|   // Now verify both interfaces with proxy.
 | |
|   i = nics.find(NicId(kClientAddr1.ipaddr(), kProxyAddr));
 | |
|   ASSERT(i != nics.end());
 | |
|   info = i->second;
 | |
|   VerifyNic(info, kClientAddr1);
 | |
| 
 | |
|   i = nics.find(NicId(kClientAddr2.ipaddr(), kProxyAddr));
 | |
|   ASSERT(i != nics.end());
 | |
|   info = i->second;
 | |
|   VerifyNic(info, kClientAddr2);
 | |
| };
 | |
| 
 | |
| // Tests that nothing bad happens if thera are no network interfaces
 | |
| // available to check.
 | |
| TEST_F(ConnectivityCheckerTest, TestStartNoNetwork) {
 | |
|   ConnectivityCheckerForTest connectivity_checker(talk_base::Thread::Current(),
 | |
|                                                   kJid,
 | |
|                                                   kSessionId,
 | |
|                                                   kBrowserAgent,
 | |
|                                                   kRelayToken,
 | |
|                                                   kConnection);
 | |
|   connectivity_checker.Initialize();
 | |
|   connectivity_checker.Start();
 | |
|   talk_base::Thread::Current()->ProcessMessages(1000);
 | |
| 
 | |
|   NicMap nics = connectivity_checker.GetResults();
 | |
| 
 | |
|   // Verify that no nics where checked.
 | |
|   EXPECT_EQ(0U, nics.size());
 | |
| }
 | |
| 
 | |
| }  // namespace cricket
 |