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/p2p/base/basicpacketsocketfactory.h"
11#include "talk/p2p/client/httpportallocator.h"
12#include "webrtc/base/basictypes.h"
13#include "webrtc/base/messagehandler.h"
14#include "webrtc/base/network.h"
15#include "webrtc/base/proxyinfo.h"
16#include "webrtc/base/scoped_ptr.h"
17#include "webrtc/base/sigslot.h"
18#include "webrtc/base/socketaddress.h"
19
20namespace rtc {
21class AsyncHttpRequest;
22class AutoDetectProxy;
23class BasicPacketSocketFactory;
24class NetworkManager;
25class PacketSocketFactory;
26class SignalThread;
27class TestHttpPortAllocatorSession;
28class Thread;
29}
30
31namespace cricket {
32class HttpPortAllocator;
33class Port;
34class PortAllocatorSession;
35struct PortConfiguration;
36class RelayPort;
37class StunPort;
38
39// Contains details about a discovered firewall that are of interest
40// when debugging call failures.
41struct 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.
49struct 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.
62struct NicId {
63  NicId(const rtc::IPAddress& ip,
64        const rtc::SocketAddress& proxy_address)
65      : ip(ip),
66        proxy_address(proxy_address) {
67  }
68  rtc::IPAddress ip;
69  rtc::SocketAddress proxy_address;
70};
71
72// Comparator implementation identifying unique network interface and
73// proxy address pairs.
74class 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.
94struct NicInfo {
95  NicInfo() {}
96  rtc::IPAddress ip;
97  rtc::ProxyInfo proxy_info;
98  rtc::SocketAddress external_address;
99  ServerAddresses stun_server_addresses;
100  rtc::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.
111class NicMap : public std::map<NicId, NicInfo, NicIdComparator> {
112};
113
114class 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<rtc::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 rtc::ProxyInfo& proxy) {
131    proxy_ = proxy;
132  }
133
134  void ConfigReady(PortConfiguration* config);
135
136  void OnRequestDone(rtc::SignalThread* data);
137
138  sigslot::signal4<const std::string&, const std::string&,
139                   const PortConfiguration*,
140                   const rtc::ProxyInfo&> SignalConfigReady;
141  sigslot::signal1<rtc::AsyncHttpRequest*> SignalRequestDone;
142
143 private:
144  rtc::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.
150class ConnectivityChecker
151    : public rtc::MessageHandler, public sigslot::has_slots<> {
152 public:
153  ConnectivityChecker(rtc::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(rtc::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 rtc::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 rtc::NetworkManager* CreateNetworkManager() {
204    return new rtc::BasicNetworkManager();
205  }
206  virtual rtc::BasicPacketSocketFactory* CreateSocketFactory(
207      rtc::Thread* thread) {
208    return new rtc::BasicPacketSocketFactory(thread);
209  }
210  virtual HttpPortAllocator* CreatePortAllocator(
211      rtc::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, rtc::Network* network);
217  virtual RelayPort* CreateRelayPort(
218      const std::string& username, const std::string& password,
219      const PortConfiguration* config, rtc::Network* network);
220  virtual void InitiateProxyDetection();
221  virtual void SetProxyInfo(const rtc::ProxyInfo& info);
222  virtual rtc::ProxyInfo GetProxyInfo() const;
223
224  rtc::Thread* worker() {
225    return worker_;
226  }
227
228 private:
229  bool AddNic(const rtc::IPAddress& ip,
230              const rtc::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 rtc::ProxyInfo& proxy_info);
237
238  // Must be called by the worker thread.
239  void CleanUp();
240
241  void OnRequestDone(rtc::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(rtc::SignalThread* thread);
248  void OnConfigReady(
249      const std::string& username, const std::string& password,
250      const PortConfiguration* config, const rtc::ProxyInfo& proxy);
251  void OnConfigWithProxyReady(const PortConfiguration*);
252  void RegisterHttpStart(int port);
253  rtc::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  rtc::AutoDetectProxy* proxy_detect_;
260  rtc::scoped_ptr<rtc::NetworkManager> network_manager_;
261  rtc::scoped_ptr<rtc::BasicPacketSocketFactory> socket_factory_;
262  rtc::scoped_ptr<HttpPortAllocator> port_allocator_;
263  NicMap nics_;
264  std::vector<Port*> ports_;
265  std::vector<PortAllocatorSession*> sessions_;
266  uint32 timeout_ms_;
267  rtc::SocketAddress stun_address_;
268  rtc::Thread* main_;
269  bool started_;
270};
271
272}  // namespace cricket
273
274#endif  // TALK_P2P_CLIENT_CONNECTIVITYCHECKER_H_
275