1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/*
2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle
3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2005, Google Inc.
4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without
6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met:
7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  1. Redistributions of source code must retain the above copyright notice,
9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer.
10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  2. Redistributions in binary form must reproduce the above copyright notice,
11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer in the documentation
12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     and/or other materials provided with the distribution.
13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  3. The name of the author may not be used to endorse or promote products
14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     derived from this software without specific prior written permission.
15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */
27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "talk/base/asyncpacketsocket.h"
29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/helpers.h"
30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/logging.h"
31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/relayport.h"
32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace cricket {
34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const uint32 kMessageConnectTimeout = 1;
36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const int kKeepAliveDelay           = 10 * 60 * 1000;
37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const int kRetryTimeout             = 50 * 1000;  // ICE says 50 secs
38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// How long to wait for a socket to connect to remote host in milliseconds
39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// before trying another connection.
40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const int kSoftConnectTimeoutMs     = 3 * 1000;
41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Handles a connection to one address/port/protocol combination for a
43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// particular RelayEntry.
44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochclass RelayConnection : public sigslot::has_slots<> {
45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public:
46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  RelayConnection(const ProtocolAddress* protocol_address,
47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                  talk_base::AsyncPacketSocket* socket,
48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                  talk_base::Thread* thread);
49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ~RelayConnection();
50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  talk_base::AsyncPacketSocket* socket() const { return socket_; }
51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const ProtocolAddress* protocol_address() {
53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return protocol_address_;
54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  talk_base::SocketAddress GetAddress() const {
57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return protocol_address_->address;
58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ProtocolType GetProtocol() const {
61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return protocol_address_->proto;
62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int SetSocketOption(talk_base::Socket::Option opt, int value);
65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Validates a response to a STUN allocate request.
67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool CheckResponse(StunMessage* msg);
68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Sends data to the relay server.
70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int Send(const void* pv, size_t cb);
71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Sends a STUN allocate request message to the relay server.
73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  void SendAllocateRequest(RelayEntry* entry, int delay);
74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Return the latest error generated by the socket.
76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int GetError() { return socket_->GetError(); }
77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Called on behalf of a StunRequest to write data to the socket.  This is
79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // already STUN intended for the server, so no wrapping is necessary.
80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  void OnSendPacket(const void* data, size_t size, StunRequest* req);
81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch private:
83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  talk_base::AsyncPacketSocket* socket_;
84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const ProtocolAddress* protocol_address_;
85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  StunRequestManager *request_manager_;
86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Manages a number of connections to the relayserver, one for each
89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// available protocol. We aim to use each connection for only a
90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// specific destination address so that we can avoid wrapping every
91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// packet in a STUN send / data indication.
92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochclass RelayEntry : public talk_base::MessageHandler,
93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                   public sigslot::has_slots<> {
94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public:
95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  RelayEntry(RelayPort* port, const talk_base::SocketAddress& ext_addr);
96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ~RelayEntry();
97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  RelayPort* port() { return port_; }
99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const talk_base::SocketAddress& address() const { return ext_addr_; }
101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  void set_address(const talk_base::SocketAddress& addr) { ext_addr_ = addr; }
102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool connected() const { return connected_; }
104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool locked() const { return locked_; }
105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Returns the last error on the socket of this entry.
107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int GetError();
108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Returns the most preferred connection of the given
110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // ones. Connections are rated based on protocol in the order of:
111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // UDP, TCP and SSLTCP, where UDP is the most preferred protocol
112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  static RelayConnection* GetBestConnection(RelayConnection* conn1,
113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                            RelayConnection* conn2);
114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Sends the STUN requests to the server to initiate this connection.
116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  void Connect();
117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Called when this entry becomes connected.  The address given is the one
119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // exposed to the outside world on the relay server.
120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  void OnConnect(const talk_base::SocketAddress& mapped_addr,
121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                 RelayConnection* socket);
122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Sends a packet to the given destination address using the socket of this
124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // entry.  This will wrap the packet in STUN if necessary.
125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int SendTo(const void* data, size_t size,
126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const talk_base::SocketAddress& addr);
127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Schedules a keep-alive allocate request.
129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  void ScheduleKeepAlive();
130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  void SetServerIndex(size_t sindex) { server_index_ = sindex; }
132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Sets this option on the socket of each connection.
134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int SetSocketOption(talk_base::Socket::Option opt, int value);
135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t ServerIndex() const { return server_index_; }
137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Try a different server address
139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  void HandleConnectFailure(talk_base::AsyncPacketSocket* socket);
140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Implementation of the MessageHandler Interface.
142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  virtual void OnMessage(talk_base::Message *pmsg);
143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch private:
145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  RelayPort* port_;
146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  talk_base::SocketAddress ext_addr_;
147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t server_index_;
148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool connected_;
149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool locked_;
150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  RelayConnection* current_connection_;
151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Called when a TCP connection is established or fails
153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  void OnSocketConnect(talk_base::AsyncPacketSocket* socket);
154dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  void OnSocketClose(talk_base::AsyncPacketSocket* socket, int error);
155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Called when a packet is received on this socket.
157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  void OnReadPacket(talk_base::AsyncPacketSocket* socket,
158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                    const char* data, size_t size,
159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                    const talk_base::SocketAddress& remote_addr);
160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Sends the given data on the socket to the server with no wrapping.  This
162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // returns the number of bytes written or -1 if an error occurred.
163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int SendPacket(const void* data, size_t size);
164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Handles an allocate request for a particular RelayEntry.
167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochclass AllocateRequest : public StunRequest {
168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public:
169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  AllocateRequest(RelayEntry* entry, RelayConnection* connection);
170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  virtual ~AllocateRequest() {}
171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  virtual void Prepare(StunMessage* request);
173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  virtual int GetNextDelay();
175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  virtual void OnResponse(StunMessage* response);
177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  virtual void OnErrorResponse(StunMessage* response);
178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  virtual void OnTimeout();
179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch private:
181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  RelayEntry* entry_;
182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  RelayConnection* connection_;
183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  uint32 start_time_;
184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst std::string RELAY_PORT_TYPE("relay");
187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayPort::RelayPort(
189dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
190dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    talk_base::Network* network, uint32 ip, int min_port, int max_port,
191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const std::string& username, const std::string& password,
192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const std::string& magic_cookie)
193dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port),
194dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      ready_(false),
195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      magic_cookie_(magic_cookie),
196dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      error_(0) {
197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  entries_.push_back(
198dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      new RelayEntry(this, talk_base::SocketAddress()));
199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  set_username_fragment(username);
201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  set_password(password);
202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (magic_cookie_.size() == 0)
203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    magic_cookie_.append(STUN_MAGIC_COOKIE_VALUE, 4);
204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayPort::~RelayPort() {
207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i = 0; i < entries_.size(); ++i)
208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    delete entries_[i];
209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  thread_->Clear(this);
210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::AddServerAddress(const ProtocolAddress& addr) {
213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Since HTTP proxies usually only allow 443,
214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // let's up the priority on PROTO_SSLTCP
215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (addr.proto == PROTO_SSLTCP &&
216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      (proxy().type == talk_base::PROXY_HTTPS ||
217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch       proxy().type == talk_base::PROXY_UNKNOWN)) {
218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    server_addr_.push_front(addr);
219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    server_addr_.push_back(addr);
221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::AddExternalAddress(const ProtocolAddress& addr) {
225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::string proto_name = ProtoToString(addr.proto);
226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (std::vector<Candidate>::const_iterator it = candidates().begin();
227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch       it != candidates().end(); ++it) {
228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if ((it->address() == addr.address) && (it->protocol() == proto_name)) {
229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      LOG(INFO) << "Redundant relay address: " << proto_name
230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                << " @ " << addr.address.ToString();
231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return;
232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  AddAddress(addr.address, proto_name, false);
235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::SetReady() {
238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!ready_) {
239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ready_ = true;
240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    SignalAddressReady(this);
241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst ProtocolAddress * RelayPort::ServerAddress(size_t index) const {
245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (index < server_addr_.size())
246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return &server_addr_[index];
247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return NULL;
248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool RelayPort::HasMagicCookie(const char* data, size_t size) {
251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (size < 24 + magic_cookie_.size()) {
252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return 0 == std::memcmp(data + 24,
255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                            magic_cookie_.c_str(),
256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                            magic_cookie_.size());
257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::PrepareAddress() {
261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // We initiate a connect on the first entry.  If this completes, it will fill
262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // in the server address as the address of this port.
263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(entries_.size() == 1);
264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  entries_[0]->Connect();
265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ready_ = false;
266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochConnection* RelayPort::CreateConnection(const Candidate& address,
269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                        CandidateOrigin origin) {
270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // We only create conns to non-udp sockets if they are incoming on this port
271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((address.protocol() != "udp") && (origin != ORIGIN_THIS_PORT)) {
272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return 0;
273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // We don't support loopback on relays
276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (address.type() == type()) {
277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return 0;
278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t index = 0;
281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i = 0; i < candidates().size(); ++i) {
282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const Candidate& local = candidates()[i];
283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (local.protocol() == address.protocol()) {
284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      index = i;
285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      break;
286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Connection * conn = new ProxyConnection(this, index, address);
290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  AddConnection(conn);
291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return conn;
292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayPort::SendTo(const void* data, size_t size,
295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                      const talk_base::SocketAddress& addr, bool payload) {
296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Try to find an entry for this specific address.  Note that the first entry
297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // created was not given an address initially, so it can be set to the first
298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // address that comes along.
299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  RelayEntry* entry = 0;
300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i = 0; i < entries_.size(); ++i) {
302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (entries_[i]->address().IsAny() && payload) {
303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      entry = entries_[i];
304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      entry->set_address(addr);
305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      break;
306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else if (entries_[i]->address() == addr) {
307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      entry = entries_[i];
308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      break;
309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // If we did not find one, then we make a new one.  This will not be useable
313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // until it becomes connected, however.
314f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!entry && payload) {
315dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    entry = new RelayEntry(this, addr);
316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!entries_.empty()) {
317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      entry->SetServerIndex(entries_[0]->ServerIndex());
318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    entry->Connect();
320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    entries_.push_back(entry);
321f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
323f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // If the entry is connected, then we can send on it (though wrapping may
324f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // still be necessary).  Otherwise, we can't yet use this connection, so we
325f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // default to the first one.
326f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!entry || !entry->connected()) {
327f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(!entries_.empty());
328f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    entry = entries_[0];
329f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!entry->connected()) {
330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      error_ = EWOULDBLOCK;
331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return SOCKET_ERROR;
332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Send the actual contents to the server using the usual mechanism.
336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int sent = entry->SendTo(data, size, addr);
337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (sent <= 0) {
338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(sent < 0);
339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    error_ = entry->GetError();
340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return SOCKET_ERROR;
341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // The caller of the function is expecting the number of user data bytes,
343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // rather than the size of the packet.
344dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return size;
345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayPort::SetOption(talk_base::Socket::Option opt, int value) {
348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int result = 0;
349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i = 0; i < entries_.size(); ++i) {
350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (entries_[i]->SetSocketOption(opt, value) < 0) {
351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      result = -1;
352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      error_ = entries_[i]->GetError();
353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  options_.push_back(OptionValue(opt, value));
356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return result;
357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayPort::GetError() {
360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return error_;
361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::OnReadPacket(
364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const char* data, size_t size,
365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const talk_base::SocketAddress& remote_addr) {
366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (Connection* conn = GetConnection(remote_addr)) {
367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    conn->OnReadPacket(data, size);
368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    Port::OnReadPacket(data, size, remote_addr);
370f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
371f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
372f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
373f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayConnection::RelayConnection(const ProtocolAddress* protocol_address,
374f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                 talk_base::AsyncPacketSocket* socket,
375f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                 talk_base::Thread* thread)
376f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    : socket_(socket),
377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      protocol_address_(protocol_address) {
378f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request_manager_ = new StunRequestManager(thread);
379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request_manager_->SignalSendPacket.connect(this,
380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                             &RelayConnection::OnSendPacket);
381f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
382f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayConnection::~RelayConnection() {
384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  delete request_manager_;
3853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  delete socket_;
386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayConnection::SetSocketOption(talk_base::Socket::Option opt,
389f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                     int value) {
390f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (socket_) {
391f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return socket_->SetOption(opt, value);
392f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
393f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return 0;
394f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
395f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool RelayConnection::CheckResponse(StunMessage* msg) {
397f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return request_manager_->CheckResponse(msg);
398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
399f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
400f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayConnection::OnSendPacket(const void* data, size_t size,
401f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                   StunRequest* req) {
402f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int sent = socket_->SendTo(data, size, GetAddress());
403f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (sent <= 0) {
404f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(LS_VERBOSE) << "OnSendPacket: failed sending to " << GetAddress() <<
405f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        std::strerror(socket_->GetError());
406f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(sent < 0);
407f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
408f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
409f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
410f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayConnection::Send(const void* pv, size_t cb) {
411f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return socket_->SendTo(pv, cb, GetAddress());
412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
413f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
414f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayConnection::SendAllocateRequest(RelayEntry* entry, int delay) {
415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request_manager_->SendDelayed(new AllocateRequest(entry, this), delay);
416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
417f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
418f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayEntry::RelayEntry(RelayPort* port,
419dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                       const talk_base::SocketAddress& ext_addr)
420dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : port_(port), ext_addr_(ext_addr),
421f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      server_index_(0), connected_(false), locked_(false),
422f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      current_connection_(NULL) {
423f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
424f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
425f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayEntry::~RelayEntry() {
426f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Remove all RelayConnections and dispose sockets.
427f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  delete current_connection_;
428f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  current_connection_ = NULL;
429f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
430f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
431f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::Connect() {
432f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // If we're already connected, return.
433f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (connected_)
434f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
435f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
436f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // If we've exhausted all options, bail out.
437f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const ProtocolAddress* ra = port()->ServerAddress(server_index_);
438f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!ra) {
439f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(LS_WARNING) << "No more relay addresses left to try";
440f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
441f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
442f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
443f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Remove any previous connection.
444f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (current_connection_) {
4453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    port()->thread()->Dispose(current_connection_);
446f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    current_connection_ = NULL;
447f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
448f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
449f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Try to set up our new socket.
450f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LOG(LS_INFO) << "Connecting to relay via " << ProtoToString(ra->proto) <<
451f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      " @ " << ra->address.ToString();
452f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
453dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  talk_base::AsyncPacketSocket* socket = NULL;
454dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
455dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (ra->proto == PROTO_UDP) {
456dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // UDP sockets are simple.
457dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    socket = port_->socket_factory()->CreateUdpSocket(
458dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        talk_base::SocketAddress(port_->ip_, 0),
459dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        port_->min_port_, port_->max_port_);
460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) {
461dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    socket = port_->socket_factory()->CreateClientTcpSocket(
462dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        talk_base::SocketAddress(port_->ip_, 0), ra->address,
463dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        port_->proxy(), port_->user_agent(), ra->proto == PROTO_SSLTCP);
464dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else {
465dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    LOG(LS_WARNING) << "Unknown protocol (" << ra->proto << ")";
466dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
467dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
468f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!socket) {
469f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(LS_WARNING) << "Socket creation failed";
470f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
471f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
472f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // If we failed to get a socket, move on to the next protocol.
473f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!socket) {
474f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    port()->thread()->Post(this, kMessageConnectTimeout);
475f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
476f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
477f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
478f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Otherwise, create the new connection and configure any socket options.
479f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  socket->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket);
480f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  current_connection_ = new RelayConnection(ra, socket, port()->thread());
481f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i = 0; i < port_->options().size(); ++i) {
482f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    current_connection_->SetSocketOption(port_->options()[i].first,
483f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                         port_->options()[i].second);
484f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
485f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
486f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // If we're trying UDP, start binding requests.
487dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // If we're trying TCP, wait for connection with a fixed timeout.
488f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
489dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    socket->SignalClose.connect(this, &RelayEntry::OnSocketClose);
490dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
491f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    port()->thread()->PostDelayed(kSoftConnectTimeoutMs, this,
492f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                  kMessageConnectTimeout);
493f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
494f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    current_connection_->SendAllocateRequest(this, 0);
495f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
496f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
497f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
498f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayEntry::GetError() {
499f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (current_connection_ != NULL) {
500f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return current_connection_->GetError();
501f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
502f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return 0;
503f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
504f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
505f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayConnection* RelayEntry::GetBestConnection(RelayConnection* conn1,
506f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                               RelayConnection* conn2) {
507f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return conn1->GetProtocol() <= conn2->GetProtocol() ? conn1 : conn2;
508f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
509f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
510f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::OnConnect(const talk_base::SocketAddress& mapped_addr,
511f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                           RelayConnection* connection) {
512f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // We are connected, notify our parent.
513f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ProtocolType proto = PROTO_UDP;
514f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto)
515f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            << " @ " << mapped_addr.ToString();
516f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  connected_ = true;
517f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
518f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
519f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  port_->SetReady();
520f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
521f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
522f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayEntry::SendTo(const void* data, size_t size,
523f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                       const talk_base::SocketAddress& addr) {
524f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // If this connection is locked to the address given, then we can send the
525f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // packet with no wrapper.
526f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (locked_ && (ext_addr_ == addr))
527f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return SendPacket(data, size);
528f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
529f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Otherwise, we must wrap the given data in a STUN SEND request so that we
530f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // can communicate the destination address to the server.
531f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  //
532f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Note that we do not use a StunRequest here.  This is because there is
533f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // likely no reason to resend this packet. If it is late, we just drop it.
534f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // The next send to this address will try again.
535f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
536f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  StunMessage request;
537f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request.SetType(STUN_SEND_REQUEST);
538f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request.SetTransactionID(talk_base::CreateRandomString(16));
539f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
540f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  StunByteStringAttribute* magic_cookie_attr =
541f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
542f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  magic_cookie_attr->CopyBytes(port_->magic_cookie().c_str(),
543dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                               port_->magic_cookie().size());
544f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request.AddAttribute(magic_cookie_attr);
545f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
546f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  StunByteStringAttribute* username_attr =
547f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
548f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  username_attr->CopyBytes(port_->username_fragment().c_str(),
549dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                           port_->username_fragment().size());
550f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request.AddAttribute(username_attr);
551f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
552f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  StunAddressAttribute* addr_attr =
553f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
554f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  addr_attr->SetFamily(1);
555f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  addr_attr->SetIP(addr.ip());
556f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  addr_attr->SetPort(addr.port());
557f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request.AddAttribute(addr_attr);
558f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
559f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Attempt to lock
560f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (ext_addr_ == addr) {
561f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    StunUInt32Attribute* options_attr =
562f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      StunAttribute::CreateUInt32(STUN_ATTR_OPTIONS);
563f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    options_attr->SetValue(0x1);
564f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    request.AddAttribute(options_attr);
565f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
566f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
567f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  StunByteStringAttribute* data_attr =
568f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      StunAttribute::CreateByteString(STUN_ATTR_DATA);
569dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  data_attr->CopyBytes(data, size);
570f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request.AddAttribute(data_attr);
571f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
572f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO: compute the HMAC.
573f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
574f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  talk_base::ByteBuffer buf;
575f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request.Write(&buf);
576f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
577f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return SendPacket(buf.Data(), buf.Length());
578f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
579f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
580f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::ScheduleKeepAlive() {
581f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (current_connection_) {
582f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    current_connection_->SendAllocateRequest(this, kKeepAliveDelay);
583f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
584f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
585f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
586f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayEntry::SetSocketOption(talk_base::Socket::Option opt, int value) {
587f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Set the option on all available sockets.
588f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int socket_error = 0;
589f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (current_connection_) {
590f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    socket_error = current_connection_->SetSocketOption(opt, value);
591f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
592f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return socket_error;
593f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
594f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
595f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::HandleConnectFailure(
596f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    talk_base::AsyncPacketSocket* socket) {
597f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Make sure it's the current connection that has failed, it might
598f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // be an old socked that has not yet been disposed.
599f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!socket || socket == current_connection_->socket()) {
600f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (current_connection_)
601f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      port()->SignalConnectFailure(current_connection_->protocol_address());
602f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
603f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Try to connect to the next server address.
604f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    server_index_ += 1;
605f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    Connect();
606f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
607f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
608f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
609f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::OnMessage(talk_base::Message *pmsg) {
610f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(pmsg->message_id == kMessageConnectTimeout);
611f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (current_connection_) {
612f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const ProtocolAddress* ra = current_connection_->protocol_address();
613f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(LS_WARNING) << "Relay " << ra->proto << " connection to " <<
614f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        ra->address << " timed out";
615f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
616f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Currently we connect to each server address in sequence. If we
617f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // have more addresses to try, treat this is an error and move on to
618f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // the next address, otherwise give this connection more time and
619f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // await the real timeout.
620f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    //
621dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // TODO: Connect to servers in parallel to speed up connect time
622dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // and to avoid giving up too early.
623f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    port_->SignalSoftTimeout(ra);
624f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    HandleConnectFailure(current_connection_->socket());
625f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
626f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    HandleConnectFailure(NULL);
627f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
628f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
629f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
630dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid RelayEntry::OnSocketConnect(talk_base::AsyncPacketSocket* socket) {
631f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LOG(INFO) << "relay tcp connected to " <<
632f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      socket->GetRemoteAddress().ToString();
633f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (current_connection_ != NULL) {
634f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    current_connection_->SendAllocateRequest(this, 0);
635f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
636f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
637f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
638dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid RelayEntry::OnSocketClose(talk_base::AsyncPacketSocket* socket,
639dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                               int error) {
640f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  PLOG(LERROR, error) << "Relay connection failed: socket closed";
641f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HandleConnectFailure(socket);
642f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
643f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
644dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid RelayEntry::OnReadPacket(talk_base::AsyncPacketSocket* socket,
645dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                              const char* data, size_t size,
646dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                              const talk_base::SocketAddress& remote_addr) {
647f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // ASSERT(remote_addr == port_->server_addr());
648f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO: are we worried about this?
649f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
650f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (current_connection_ == NULL || socket != current_connection_->socket()) {
651f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // This packet comes from an unknown address.
652f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(WARNING) << "Dropping packet: unknown address";
653f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
654f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
655f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
656f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // If the magic cookie is not present, then this is an unwrapped packet sent
657f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // by the server,  The actual remote address is the one we recorded.
658f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!port_->HasMagicCookie(data, size)) {
659f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (locked_) {
660f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      port_->OnReadPacket(data, size, ext_addr_);
661f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else {
662f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      LOG(WARNING) << "Dropping packet: entry not locked";
663f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
664f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
665f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
666f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
667f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  talk_base::ByteBuffer buf(data, size);
668f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  StunMessage msg;
669f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!msg.Read(&buf)) {
670f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(INFO) << "Incoming packet was not STUN";
671f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
672f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
673f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
674f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // The incoming packet should be a STUN ALLOCATE response, SEND response, or
675f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // DATA indication.
676f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (current_connection_->CheckResponse(&msg)) {
677f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
678f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if (msg.type() == STUN_SEND_RESPONSE) {
679f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (const StunUInt32Attribute* options_attr =
680f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        msg.GetUInt32(STUN_ATTR_OPTIONS)) {
681f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (options_attr->value() & 0x1) {
682f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        locked_ = true;
683f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
684f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
685f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
686f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if (msg.type() != STUN_DATA_INDICATION) {
687f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(INFO) << "Received BAD stun type from server: " << msg.type();
688f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
689f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
690f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
691f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // This must be a data indication.
692f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
693f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const StunAddressAttribute* addr_attr =
694f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
695f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!addr_attr) {
696f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(INFO) << "Data indication has no source address";
697f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
698f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if (addr_attr->family() != 1) {
699f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(INFO) << "Source address has bad family";
700f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
701f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
702f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
703f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  talk_base::SocketAddress remote_addr2(addr_attr->ip(), addr_attr->port());
704f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
705f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
706f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!data_attr) {
707f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(INFO) << "Data indication has no data";
708f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
709f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
710f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
711f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Process the actual data and remote address in the normal manner.
712f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  port_->OnReadPacket(data_attr->bytes(), data_attr->length(), remote_addr2);
713f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
714f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
715f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayEntry::SendPacket(const void* data, size_t size) {
716f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int sent = 0;
717f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (current_connection_) {
718f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // We are connected, no need to send packets anywere else than to
719f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // the current connection.
720f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    sent = current_connection_->Send(data, size);
721f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
722f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return sent;
723f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
724f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
725f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochAllocateRequest::AllocateRequest(RelayEntry* entry,
726f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                 RelayConnection* connection) :
727f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    entry_(entry), connection_(connection) {
728f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  start_time_ = talk_base::Time();
729f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
730f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
731f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid AllocateRequest::Prepare(StunMessage* request) {
732f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request->SetType(STUN_ALLOCATE_REQUEST);
733f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
734f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  StunByteStringAttribute* magic_cookie_attr =
735f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
736f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  magic_cookie_attr->CopyBytes(
737f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      entry_->port()->magic_cookie().c_str(),
738dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      entry_->port()->magic_cookie().size());
739f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request->AddAttribute(magic_cookie_attr);
740f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
741f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  StunByteStringAttribute* username_attr =
742f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
743f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  username_attr->CopyBytes(
744f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      entry_->port()->username_fragment().c_str(),
745dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      entry_->port()->username_fragment().size());
746f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  request->AddAttribute(username_attr);
747f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
748f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
749f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint AllocateRequest::GetNextDelay() {
750f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int delay = 100 * talk_base::_max(1 << count_, 2);
751f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  count_ += 1;
752f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (count_ == 5)
753f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    timeout_ = true;
754f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return delay;
755f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
756f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
757f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid AllocateRequest::OnResponse(StunMessage* response) {
758f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const StunAddressAttribute* addr_attr =
759f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
760f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!addr_attr) {
761f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(INFO) << "Allocate response missing mapped address.";
762f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if (addr_attr->family() != 1) {
763f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(INFO) << "Mapped address has bad family";
764f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
765f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    talk_base::SocketAddress addr(addr_attr->ip(), addr_attr->port());
766f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    entry_->OnConnect(addr, connection_);
767f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
768f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
769f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // We will do a keep-alive regardless of whether this request suceeds.
770f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // This should have almost no impact on network usage.
771f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  entry_->ScheduleKeepAlive();
772f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
773f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
774f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid AllocateRequest::OnErrorResponse(StunMessage* response) {
775f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const StunErrorCodeAttribute* attr = response->GetErrorCode();
776f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!attr) {
777f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(INFO) << "Bad allocate response error code";
778f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
779f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(INFO) << "Allocate error response:"
780f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch              << " code=" << static_cast<int>(attr->error_code())
781f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch              << " reason='" << attr->reason() << "'";
782f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
783f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
784f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (talk_base::TimeSince(start_time_) <= kRetryTimeout)
785f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    entry_->ScheduleKeepAlive();
786f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
787f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
788f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid AllocateRequest::OnTimeout() {
789f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LOG(INFO) << "Allocate request timed out";
790f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  entry_->HandleConnectFailure(connection_->socket());
791f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
792f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
793f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}  // namespace cricket
794