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