1 // Copyright 2011 Google Inc. All Rights Reserved. 2 3 4 #ifndef TALK_P2P_CLIENT_CONNECTIVITYCHECKER_H_ 5 #define TALK_P2P_CLIENT_CONNECTIVITYCHECKER_H_ 6 7 #include <map> 8 #include <string> 9 10 #include "talk/base/network.h" 11 #include "talk/base/basictypes.h" 12 #include "talk/base/messagehandler.h" 13 #include "talk/base/proxyinfo.h" 14 #include "talk/base/scoped_ptr.h" 15 #include "talk/base/sigslot.h" 16 #include "talk/base/socketaddress.h" 17 #include "talk/p2p/base/basicpacketsocketfactory.h" 18 #include "talk/p2p/client/httpportallocator.h" 19 20 namespace talk_base { 21 class AsyncHttpRequest; 22 class AutoDetectProxy; 23 class BasicPacketSocketFactory; 24 class NetworkManager; 25 class PacketSocketFactory; 26 class SignalThread; 27 class TestHttpPortAllocatorSession; 28 class Thread; 29 } 30 31 namespace cricket { 32 class HttpPortAllocator; 33 class Port; 34 class PortAllocatorSession; 35 struct PortConfiguration; 36 class RelayPort; 37 class StunPort; 38 39 // Contains details about a discovered firewall that are of interest 40 // when debugging call failures. 41 struct FirewallInfo { 42 std::string brand; 43 std::string model; 44 45 // TODO: List of current port mappings. 46 }; 47 48 // Contains details about a specific connect attempt. 49 struct ConnectInfo { 50 ConnectInfo() 51 : rtt(-1), error(0) {} 52 // Time when the connection was initiated. Needed for calculating 53 // the round trip time. 54 uint32 start_time_ms; 55 // Round trip time in milliseconds or -1 for failed connection. 56 int32 rtt; 57 // Error code representing low level errors like socket errors. 58 int error; 59 }; 60 61 // Identifier for a network interface and proxy address pair. 62 struct NicId { 63 NicId(const talk_base::IPAddress& ip, 64 const talk_base::SocketAddress& proxy_address) 65 : ip(ip), 66 proxy_address(proxy_address) { 67 } 68 talk_base::IPAddress ip; 69 talk_base::SocketAddress proxy_address; 70 }; 71 72 // Comparator implementation identifying unique network interface and 73 // proxy address pairs. 74 class NicIdComparator { 75 public: 76 int compare(const NicId &first, const NicId &second) const { 77 if (first.ip == second.ip) { 78 // Compare proxy address. 79 if (first.proxy_address == second.proxy_address) { 80 return 0; 81 } else { 82 return first.proxy_address < second.proxy_address? -1 : 1; 83 } 84 } 85 return first.ip < second.ip ? -1 : 1; 86 } 87 88 bool operator()(const NicId &first, const NicId &second) const { 89 return (compare(first, second) < 0); 90 } 91 }; 92 93 // Contains information of a network interface and proxy address pair. 94 struct NicInfo { 95 NicInfo() {} 96 talk_base::IPAddress ip; 97 talk_base::ProxyInfo proxy_info; 98 talk_base::SocketAddress external_address; 99 talk_base::SocketAddress stun_server_address; 100 talk_base::SocketAddress media_server_address; 101 ConnectInfo stun; 102 ConnectInfo http; 103 ConnectInfo https; 104 ConnectInfo udp; 105 ConnectInfo tcp; 106 ConnectInfo ssltcp; 107 FirewallInfo firewall; 108 }; 109 110 // Holds the result of the connectivity check. 111 class NicMap : public std::map<NicId, NicInfo, NicIdComparator> { 112 }; 113 114 class TestHttpPortAllocatorSession : public HttpPortAllocatorSession { 115 public: 116 TestHttpPortAllocatorSession( 117 HttpPortAllocator* allocator, 118 const std::string& content_name, 119 int component, 120 const std::string& ice_ufrag, 121 const std::string& ice_pwd, 122 const std::vector<talk_base::SocketAddress>& stun_hosts, 123 const std::vector<std::string>& relay_hosts, 124 const std::string& relay_token, 125 const std::string& user_agent) 126 : HttpPortAllocatorSession( 127 allocator, content_name, component, ice_ufrag, ice_pwd, stun_hosts, 128 relay_hosts, relay_token, user_agent) { 129 } 130 void set_proxy(const talk_base::ProxyInfo& proxy) { 131 proxy_ = proxy; 132 } 133 134 void ConfigReady(PortConfiguration* config); 135 136 void OnRequestDone(talk_base::SignalThread* data); 137 138 sigslot::signal4<const std::string&, const std::string&, 139 const PortConfiguration*, 140 const talk_base::ProxyInfo&> SignalConfigReady; 141 sigslot::signal1<talk_base::AsyncHttpRequest*> SignalRequestDone; 142 143 private: 144 talk_base::ProxyInfo proxy_; 145 }; 146 147 // Runs a request/response check on all network interface and proxy 148 // address combinations. The check is considered done either when all 149 // checks has been successful or when the check times out. 150 class ConnectivityChecker 151 : public talk_base::MessageHandler, public sigslot::has_slots<> { 152 public: 153 ConnectivityChecker(talk_base::Thread* worker, 154 const std::string& jid, 155 const std::string& session_id, 156 const std::string& user_agent, 157 const std::string& relay_token, 158 const std::string& connection); 159 virtual ~ConnectivityChecker(); 160 161 // Virtual for gMock. 162 virtual bool Initialize(); 163 virtual void Start(); 164 165 // MessageHandler implementation. 166 virtual void OnMessage(talk_base::Message *msg); 167 168 // Instruct checker to stop and wait until that's done. 169 // Virtual for gMock. 170 virtual void Stop() { 171 worker_->Stop(); 172 } 173 174 const NicMap& GetResults() const { 175 return nics_; 176 } 177 178 void set_timeout_ms(uint32 timeout) { 179 timeout_ms_ = timeout; 180 } 181 182 void set_stun_address(const talk_base::SocketAddress& stun_address) { 183 stun_address_ = stun_address; 184 } 185 186 const std::string& connection() const { 187 return connection_; 188 } 189 190 const std::string& jid() const { 191 return jid_; 192 } 193 194 const std::string& session_id() const { 195 return session_id_; 196 } 197 198 // Context: Main Thread. Signalled when the connectivity check is complete. 199 sigslot::signal1<ConnectivityChecker*> SignalCheckDone; 200 201 protected: 202 // Can be overridden for test. 203 virtual talk_base::NetworkManager* CreateNetworkManager() { 204 return new talk_base::BasicNetworkManager(); 205 } 206 virtual talk_base::BasicPacketSocketFactory* CreateSocketFactory( 207 talk_base::Thread* thread) { 208 return new talk_base::BasicPacketSocketFactory(thread); 209 } 210 virtual HttpPortAllocator* CreatePortAllocator( 211 talk_base::NetworkManager* network_manager, 212 const std::string& user_agent, 213 const std::string& relay_token); 214 virtual StunPort* CreateStunPort( 215 const std::string& username, const std::string& password, 216 const PortConfiguration* config, talk_base::Network* network); 217 virtual RelayPort* CreateRelayPort( 218 const std::string& username, const std::string& password, 219 const PortConfiguration* config, talk_base::Network* network); 220 virtual void InitiateProxyDetection(); 221 virtual void SetProxyInfo(const talk_base::ProxyInfo& info); 222 virtual talk_base::ProxyInfo GetProxyInfo() const; 223 224 talk_base::Thread* worker() { 225 return worker_; 226 } 227 228 private: 229 bool AddNic(const talk_base::IPAddress& ip, 230 const talk_base::SocketAddress& proxy_address); 231 void AllocatePorts(); 232 void AllocateRelayPorts(); 233 void CheckNetworks(); 234 void CreateRelayPorts( 235 const std::string& username, const std::string& password, 236 const PortConfiguration* config, const talk_base::ProxyInfo& proxy_info); 237 238 // Must be called by the worker thread. 239 void CleanUp(); 240 241 void OnRequestDone(talk_base::AsyncHttpRequest* request); 242 void OnRelayPortComplete(Port* port); 243 void OnStunPortComplete(Port* port); 244 void OnRelayPortError(Port* port); 245 void OnStunPortError(Port* port); 246 void OnNetworksChanged(); 247 void OnProxyDetect(talk_base::SignalThread* thread); 248 void OnConfigReady( 249 const std::string& username, const std::string& password, 250 const PortConfiguration* config, const talk_base::ProxyInfo& proxy); 251 void OnConfigWithProxyReady(const PortConfiguration*); 252 void RegisterHttpStart(int port); 253 talk_base::Thread* worker_; 254 std::string jid_; 255 std::string session_id_; 256 std::string user_agent_; 257 std::string relay_token_; 258 std::string connection_; 259 talk_base::AutoDetectProxy* proxy_detect_; 260 talk_base::scoped_ptr<talk_base::NetworkManager> network_manager_; 261 talk_base::scoped_ptr<talk_base::BasicPacketSocketFactory> socket_factory_; 262 talk_base::scoped_ptr<HttpPortAllocator> port_allocator_; 263 NicMap nics_; 264 std::vector<Port*> ports_; 265 std::vector<PortAllocatorSession*> sessions_; 266 uint32 timeout_ms_; 267 talk_base::SocketAddress stun_address_; 268 talk_base::Thread* main_; 269 bool started_; 270 }; 271 272 } // namespace cricket 273 274 #endif // TALK_P2P_CLIENT_CONNECTIVITYCHECKER_H_ 275