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