• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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();
socket() const50   talk_base::AsyncPacketSocket* socket() const { return socket_; }
51 
protocol_address()52   const ProtocolAddress* protocol_address() {
53     return protocol_address_;
54   }
55 
GetAddress() const56   talk_base::SocketAddress GetAddress() const {
57     return protocol_address_->address;
58   }
59 
GetProtocol() const60   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);
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.
GetError()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 
port()98   RelayPort* port() { return port_; }
99 
address() const100   const talk_base::SocketAddress& address() const { return ext_addr_; }
set_address(const talk_base::SocketAddress & addr)101   void set_address(const talk_base::SocketAddress& addr) { ext_addr_ = addr; }
102 
connected() const103   bool connected() const { return connected_; }
locked() const104   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 
128   // Schedules a keep-alive allocate request.
129   void ScheduleKeepAlive();
130 
SetServerIndex(size_t sindex)131   void SetServerIndex(size_t sindex) { server_index_ = sindex; }
132 
133   // Sets this option on the socket of each connection.
134   int SetSocketOption(talk_base::Socket::Option opt, int value);
135 
ServerIndex() const136   size_t ServerIndex() const { return server_index_; }
137 
138   // Try a different server address
139   void HandleConnectFailure(talk_base::AsyncPacketSocket* socket);
140 
141   // Implementation of the MessageHandler Interface.
142   virtual void OnMessage(talk_base::Message *pmsg);
143 
144  private:
145   RelayPort* port_;
146   talk_base::SocketAddress ext_addr_;
147   size_t server_index_;
148   bool connected_;
149   bool locked_;
150   RelayConnection* current_connection_;
151 
152   // Called when a TCP connection is established or fails
153   void OnSocketConnect(talk_base::AsyncPacketSocket* socket);
154   void OnSocketClose(talk_base::AsyncPacketSocket* socket, int error);
155 
156   // Called when a packet is received on this socket.
157   void OnReadPacket(talk_base::AsyncPacketSocket* socket,
158                     const char* data, size_t size,
159                     const talk_base::SocketAddress& remote_addr);
160 
161   // Sends the given data on the socket to the server with no wrapping.  This
162   // returns the number of bytes written or -1 if an error occurred.
163   int SendPacket(const void* data, size_t size);
164 };
165 
166 // Handles an allocate request for a particular RelayEntry.
167 class AllocateRequest : public StunRequest {
168  public:
169   AllocateRequest(RelayEntry* entry, RelayConnection* connection);
~AllocateRequest()170   virtual ~AllocateRequest() {}
171 
172   virtual void Prepare(StunMessage* request);
173 
174   virtual int GetNextDelay();
175 
176   virtual void OnResponse(StunMessage* response);
177   virtual void OnErrorResponse(StunMessage* response);
178   virtual void OnTimeout();
179 
180  private:
181   RelayEntry* entry_;
182   RelayConnection* connection_;
183   uint32 start_time_;
184 };
185 
186 const std::string RELAY_PORT_TYPE("relay");
187 
RelayPort(talk_base::Thread * thread,talk_base::PacketSocketFactory * factory,talk_base::Network * network,uint32 ip,int min_port,int max_port,const std::string & username,const std::string & password,const std::string & magic_cookie)188 RelayPort::RelayPort(
189     talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
190     talk_base::Network* network, uint32 ip, int min_port, int max_port,
191     const std::string& username, const std::string& password,
192     const std::string& magic_cookie)
193     : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port),
194       ready_(false),
195       magic_cookie_(magic_cookie),
196       error_(0) {
197   entries_.push_back(
198       new RelayEntry(this, talk_base::SocketAddress()));
199 
200   set_username_fragment(username);
201   set_password(password);
202   if (magic_cookie_.size() == 0)
203     magic_cookie_.append(STUN_MAGIC_COOKIE_VALUE, 4);
204 }
205 
~RelayPort()206 RelayPort::~RelayPort() {
207   for (size_t i = 0; i < entries_.size(); ++i)
208     delete entries_[i];
209   thread_->Clear(this);
210 }
211 
AddServerAddress(const ProtocolAddress & addr)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 
AddExternalAddress(const ProtocolAddress & addr)224 void RelayPort::AddExternalAddress(const ProtocolAddress& addr) {
225   std::string proto_name = ProtoToString(addr.proto);
226   for (std::vector<Candidate>::const_iterator it = candidates().begin();
227        it != candidates().end(); ++it) {
228     if ((it->address() == addr.address) && (it->protocol() == proto_name)) {
229       LOG(INFO) << "Redundant relay address: " << proto_name
230                 << " @ " << addr.address.ToString();
231       return;
232     }
233   }
234   AddAddress(addr.address, proto_name, false);
235 }
236 
SetReady()237 void RelayPort::SetReady() {
238   if (!ready_) {
239     ready_ = true;
240     SignalAddressReady(this);
241   }
242 }
243 
ServerAddress(size_t index) const244 const ProtocolAddress * RelayPort::ServerAddress(size_t index) const {
245   if (index < server_addr_.size())
246     return &server_addr_[index];
247   return NULL;
248 }
249 
HasMagicCookie(const char * data,size_t size)250 bool RelayPort::HasMagicCookie(const char* data, size_t size) {
251   if (size < 24 + magic_cookie_.size()) {
252     return false;
253   } else {
254     return 0 == std::memcmp(data + 24,
255                             magic_cookie_.c_str(),
256                             magic_cookie_.size());
257   }
258 }
259 
PrepareAddress()260 void RelayPort::PrepareAddress() {
261   // We initiate a connect on the first entry.  If this completes, it will fill
262   // in the server address as the address of this port.
263   ASSERT(entries_.size() == 1);
264   entries_[0]->Connect();
265   ready_ = false;
266 }
267 
CreateConnection(const Candidate & address,CandidateOrigin origin)268 Connection* RelayPort::CreateConnection(const Candidate& address,
269                                         CandidateOrigin origin) {
270   // We only create conns to non-udp sockets if they are incoming on this port
271   if ((address.protocol() != "udp") && (origin != ORIGIN_THIS_PORT)) {
272     return 0;
273   }
274 
275   // We don't support loopback on relays
276   if (address.type() == type()) {
277     return 0;
278   }
279 
280   size_t index = 0;
281   for (size_t i = 0; i < candidates().size(); ++i) {
282     const Candidate& local = candidates()[i];
283     if (local.protocol() == address.protocol()) {
284       index = i;
285       break;
286     }
287   }
288 
289   Connection * conn = new ProxyConnection(this, index, address);
290   AddConnection(conn);
291   return conn;
292 }
293 
SendTo(const void * data,size_t size,const talk_base::SocketAddress & addr,bool payload)294 int RelayPort::SendTo(const void* data, size_t size,
295                       const talk_base::SocketAddress& addr, bool payload) {
296   // Try to find an entry for this specific address.  Note that the first entry
297   // created was not given an address initially, so it can be set to the first
298   // address that comes along.
299   RelayEntry* entry = 0;
300 
301   for (size_t i = 0; i < entries_.size(); ++i) {
302     if (entries_[i]->address().IsAny() && payload) {
303       entry = entries_[i];
304       entry->set_address(addr);
305       break;
306     } else if (entries_[i]->address() == addr) {
307       entry = entries_[i];
308       break;
309     }
310   }
311 
312   // If we did not find one, then we make a new one.  This will not be useable
313   // until it becomes connected, however.
314   if (!entry && payload) {
315     entry = new RelayEntry(this, addr);
316     if (!entries_.empty()) {
317       entry->SetServerIndex(entries_[0]->ServerIndex());
318     }
319     entry->Connect();
320     entries_.push_back(entry);
321   }
322 
323   // If the entry is connected, then we can send on it (though wrapping may
324   // still be necessary).  Otherwise, we can't yet use this connection, so we
325   // default to the first one.
326   if (!entry || !entry->connected()) {
327     ASSERT(!entries_.empty());
328     entry = entries_[0];
329     if (!entry->connected()) {
330       error_ = EWOULDBLOCK;
331       return SOCKET_ERROR;
332     }
333   }
334 
335   // Send the actual contents to the server using the usual mechanism.
336   int sent = entry->SendTo(data, size, addr);
337   if (sent <= 0) {
338     ASSERT(sent < 0);
339     error_ = entry->GetError();
340     return SOCKET_ERROR;
341   }
342   // The caller of the function is expecting the number of user data bytes,
343   // rather than the size of the packet.
344   return size;
345 }
346 
SetOption(talk_base::Socket::Option opt,int value)347 int RelayPort::SetOption(talk_base::Socket::Option opt, int value) {
348   int result = 0;
349   for (size_t i = 0; i < entries_.size(); ++i) {
350     if (entries_[i]->SetSocketOption(opt, value) < 0) {
351       result = -1;
352       error_ = entries_[i]->GetError();
353     }
354   }
355   options_.push_back(OptionValue(opt, value));
356   return result;
357 }
358 
GetError()359 int RelayPort::GetError() {
360   return error_;
361 }
362 
OnReadPacket(const char * data,size_t size,const talk_base::SocketAddress & remote_addr)363 void RelayPort::OnReadPacket(
364     const char* data, size_t size,
365     const talk_base::SocketAddress& remote_addr) {
366   if (Connection* conn = GetConnection(remote_addr)) {
367     conn->OnReadPacket(data, size);
368   } else {
369     Port::OnReadPacket(data, size, remote_addr);
370   }
371 }
372 
RelayConnection(const ProtocolAddress * protocol_address,talk_base::AsyncPacketSocket * socket,talk_base::Thread * thread)373 RelayConnection::RelayConnection(const ProtocolAddress* protocol_address,
374                                  talk_base::AsyncPacketSocket* socket,
375                                  talk_base::Thread* thread)
376     : socket_(socket),
377       protocol_address_(protocol_address) {
378   request_manager_ = new StunRequestManager(thread);
379   request_manager_->SignalSendPacket.connect(this,
380                                              &RelayConnection::OnSendPacket);
381 }
382 
~RelayConnection()383 RelayConnection::~RelayConnection() {
384   delete request_manager_;
385   delete socket_;
386 }
387 
SetSocketOption(talk_base::Socket::Option opt,int value)388 int RelayConnection::SetSocketOption(talk_base::Socket::Option opt,
389                                      int value) {
390   if (socket_) {
391     return socket_->SetOption(opt, value);
392   }
393   return 0;
394 }
395 
CheckResponse(StunMessage * msg)396 bool RelayConnection::CheckResponse(StunMessage* msg) {
397   return request_manager_->CheckResponse(msg);
398 }
399 
OnSendPacket(const void * data,size_t size,StunRequest * req)400 void RelayConnection::OnSendPacket(const void* data, size_t size,
401                                    StunRequest* req) {
402   int sent = socket_->SendTo(data, size, GetAddress());
403   if (sent <= 0) {
404     LOG(LS_VERBOSE) << "OnSendPacket: failed sending to " << GetAddress() <<
405         std::strerror(socket_->GetError());
406     ASSERT(sent < 0);
407   }
408 }
409 
Send(const void * pv,size_t cb)410 int RelayConnection::Send(const void* pv, size_t cb) {
411   return socket_->SendTo(pv, cb, GetAddress());
412 }
413 
SendAllocateRequest(RelayEntry * entry,int delay)414 void RelayConnection::SendAllocateRequest(RelayEntry* entry, int delay) {
415   request_manager_->SendDelayed(new AllocateRequest(entry, this), delay);
416 }
417 
RelayEntry(RelayPort * port,const talk_base::SocketAddress & ext_addr)418 RelayEntry::RelayEntry(RelayPort* port,
419                        const talk_base::SocketAddress& ext_addr)
420     : port_(port), ext_addr_(ext_addr),
421       server_index_(0), connected_(false), locked_(false),
422       current_connection_(NULL) {
423 }
424 
~RelayEntry()425 RelayEntry::~RelayEntry() {
426   // Remove all RelayConnections and dispose sockets.
427   delete current_connection_;
428   current_connection_ = NULL;
429 }
430 
Connect()431 void RelayEntry::Connect() {
432   // If we're already connected, return.
433   if (connected_)
434     return;
435 
436   // If we've exhausted all options, bail out.
437   const ProtocolAddress* ra = port()->ServerAddress(server_index_);
438   if (!ra) {
439     LOG(LS_WARNING) << "No more relay addresses left to try";
440     return;
441   }
442 
443   // Remove any previous connection.
444   if (current_connection_) {
445     port()->thread()->Dispose(current_connection_);
446     current_connection_ = NULL;
447   }
448 
449   // Try to set up our new socket.
450   LOG(LS_INFO) << "Connecting to relay via " << ProtoToString(ra->proto) <<
451       " @ " << ra->address.ToString();
452 
453   talk_base::AsyncPacketSocket* socket = NULL;
454 
455   if (ra->proto == PROTO_UDP) {
456     // UDP sockets are simple.
457     socket = port_->socket_factory()->CreateUdpSocket(
458         talk_base::SocketAddress(port_->ip_, 0),
459         port_->min_port_, port_->max_port_);
460   } else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) {
461     socket = port_->socket_factory()->CreateClientTcpSocket(
462         talk_base::SocketAddress(port_->ip_, 0), ra->address,
463         port_->proxy(), port_->user_agent(), ra->proto == PROTO_SSLTCP);
464   } else {
465     LOG(LS_WARNING) << "Unknown protocol (" << ra->proto << ")";
466   }
467 
468   if (!socket) {
469     LOG(LS_WARNING) << "Socket creation failed";
470   }
471 
472   // If we failed to get a socket, move on to the next protocol.
473   if (!socket) {
474     port()->thread()->Post(this, kMessageConnectTimeout);
475     return;
476   }
477 
478   // Otherwise, create the new connection and configure any socket options.
479   socket->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket);
480   current_connection_ = new RelayConnection(ra, socket, port()->thread());
481   for (size_t i = 0; i < port_->options().size(); ++i) {
482     current_connection_->SetSocketOption(port_->options()[i].first,
483                                          port_->options()[i].second);
484   }
485 
486   // If we're trying UDP, start binding requests.
487   // If we're trying TCP, wait for connection with a fixed timeout.
488   if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
489     socket->SignalClose.connect(this, &RelayEntry::OnSocketClose);
490     socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
491     port()->thread()->PostDelayed(kSoftConnectTimeoutMs, this,
492                                   kMessageConnectTimeout);
493   } else {
494     current_connection_->SendAllocateRequest(this, 0);
495   }
496 }
497 
GetError()498 int RelayEntry::GetError() {
499   if (current_connection_ != NULL) {
500     return current_connection_->GetError();
501   }
502   return 0;
503 }
504 
GetBestConnection(RelayConnection * conn1,RelayConnection * conn2)505 RelayConnection* RelayEntry::GetBestConnection(RelayConnection* conn1,
506                                                RelayConnection* conn2) {
507   return conn1->GetProtocol() <= conn2->GetProtocol() ? conn1 : conn2;
508 }
509 
OnConnect(const talk_base::SocketAddress & mapped_addr,RelayConnection * connection)510 void RelayEntry::OnConnect(const talk_base::SocketAddress& mapped_addr,
511                            RelayConnection* connection) {
512   // We are connected, notify our parent.
513   ProtocolType proto = PROTO_UDP;
514   LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto)
515             << " @ " << mapped_addr.ToString();
516   connected_ = true;
517 
518   port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
519   port_->SetReady();
520 }
521 
SendTo(const void * data,size_t size,const talk_base::SocketAddress & addr)522 int RelayEntry::SendTo(const void* data, size_t size,
523                        const talk_base::SocketAddress& addr) {
524   // If this connection is locked to the address given, then we can send the
525   // packet with no wrapper.
526   if (locked_ && (ext_addr_ == addr))
527     return SendPacket(data, size);
528 
529   // Otherwise, we must wrap the given data in a STUN SEND request so that we
530   // can communicate the destination address to the server.
531   //
532   // Note that we do not use a StunRequest here.  This is because there is
533   // likely no reason to resend this packet. If it is late, we just drop it.
534   // The next send to this address will try again.
535 
536   StunMessage request;
537   request.SetType(STUN_SEND_REQUEST);
538   request.SetTransactionID(talk_base::CreateRandomString(16));
539 
540   StunByteStringAttribute* magic_cookie_attr =
541       StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
542   magic_cookie_attr->CopyBytes(port_->magic_cookie().c_str(),
543                                port_->magic_cookie().size());
544   request.AddAttribute(magic_cookie_attr);
545 
546   StunByteStringAttribute* username_attr =
547       StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
548   username_attr->CopyBytes(port_->username_fragment().c_str(),
549                            port_->username_fragment().size());
550   request.AddAttribute(username_attr);
551 
552   StunAddressAttribute* addr_attr =
553       StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
554   addr_attr->SetFamily(1);
555   addr_attr->SetIP(addr.ip());
556   addr_attr->SetPort(addr.port());
557   request.AddAttribute(addr_attr);
558 
559   // Attempt to lock
560   if (ext_addr_ == addr) {
561     StunUInt32Attribute* options_attr =
562       StunAttribute::CreateUInt32(STUN_ATTR_OPTIONS);
563     options_attr->SetValue(0x1);
564     request.AddAttribute(options_attr);
565   }
566 
567   StunByteStringAttribute* data_attr =
568       StunAttribute::CreateByteString(STUN_ATTR_DATA);
569   data_attr->CopyBytes(data, size);
570   request.AddAttribute(data_attr);
571 
572   // TODO: compute the HMAC.
573 
574   talk_base::ByteBuffer buf;
575   request.Write(&buf);
576 
577   return SendPacket(buf.Data(), buf.Length());
578 }
579 
ScheduleKeepAlive()580 void RelayEntry::ScheduleKeepAlive() {
581   if (current_connection_) {
582     current_connection_->SendAllocateRequest(this, kKeepAliveDelay);
583   }
584 }
585 
SetSocketOption(talk_base::Socket::Option opt,int value)586 int RelayEntry::SetSocketOption(talk_base::Socket::Option opt, int value) {
587   // Set the option on all available sockets.
588   int socket_error = 0;
589   if (current_connection_) {
590     socket_error = current_connection_->SetSocketOption(opt, value);
591   }
592   return socket_error;
593 }
594 
HandleConnectFailure(talk_base::AsyncPacketSocket * socket)595 void RelayEntry::HandleConnectFailure(
596     talk_base::AsyncPacketSocket* socket) {
597   // Make sure it's the current connection that has failed, it might
598   // be an old socked that has not yet been disposed.
599   if (!socket || socket == current_connection_->socket()) {
600     if (current_connection_)
601       port()->SignalConnectFailure(current_connection_->protocol_address());
602 
603     // Try to connect to the next server address.
604     server_index_ += 1;
605     Connect();
606   }
607 }
608 
OnMessage(talk_base::Message * pmsg)609 void RelayEntry::OnMessage(talk_base::Message *pmsg) {
610   ASSERT(pmsg->message_id == kMessageConnectTimeout);
611   if (current_connection_) {
612     const ProtocolAddress* ra = current_connection_->protocol_address();
613     LOG(LS_WARNING) << "Relay " << ra->proto << " connection to " <<
614         ra->address << " timed out";
615 
616     // Currently we connect to each server address in sequence. If we
617     // have more addresses to try, treat this is an error and move on to
618     // the next address, otherwise give this connection more time and
619     // await the real timeout.
620     //
621     // TODO: Connect to servers in parallel to speed up connect time
622     // and to avoid giving up too early.
623     port_->SignalSoftTimeout(ra);
624     HandleConnectFailure(current_connection_->socket());
625   } else {
626     HandleConnectFailure(NULL);
627   }
628 }
629 
OnSocketConnect(talk_base::AsyncPacketSocket * socket)630 void RelayEntry::OnSocketConnect(talk_base::AsyncPacketSocket* socket) {
631   LOG(INFO) << "relay tcp connected to " <<
632       socket->GetRemoteAddress().ToString();
633   if (current_connection_ != NULL) {
634     current_connection_->SendAllocateRequest(this, 0);
635   }
636 }
637 
OnSocketClose(talk_base::AsyncPacketSocket * socket,int error)638 void RelayEntry::OnSocketClose(talk_base::AsyncPacketSocket* socket,
639                                int error) {
640   PLOG(LERROR, error) << "Relay connection failed: socket closed";
641   HandleConnectFailure(socket);
642 }
643 
OnReadPacket(talk_base::AsyncPacketSocket * socket,const char * data,size_t size,const talk_base::SocketAddress & remote_addr)644 void RelayEntry::OnReadPacket(talk_base::AsyncPacketSocket* socket,
645                               const char* data, size_t size,
646                               const talk_base::SocketAddress& remote_addr) {
647   // ASSERT(remote_addr == port_->server_addr());
648   // TODO: are we worried about this?
649 
650   if (current_connection_ == NULL || socket != current_connection_->socket()) {
651     // This packet comes from an unknown address.
652     LOG(WARNING) << "Dropping packet: unknown address";
653     return;
654   }
655 
656   // If the magic cookie is not present, then this is an unwrapped packet sent
657   // by the server,  The actual remote address is the one we recorded.
658   if (!port_->HasMagicCookie(data, size)) {
659     if (locked_) {
660       port_->OnReadPacket(data, size, ext_addr_);
661     } else {
662       LOG(WARNING) << "Dropping packet: entry not locked";
663     }
664     return;
665   }
666 
667   talk_base::ByteBuffer buf(data, size);
668   StunMessage msg;
669   if (!msg.Read(&buf)) {
670     LOG(INFO) << "Incoming packet was not STUN";
671     return;
672   }
673 
674   // The incoming packet should be a STUN ALLOCATE response, SEND response, or
675   // DATA indication.
676   if (current_connection_->CheckResponse(&msg)) {
677     return;
678   } else if (msg.type() == STUN_SEND_RESPONSE) {
679     if (const StunUInt32Attribute* options_attr =
680         msg.GetUInt32(STUN_ATTR_OPTIONS)) {
681       if (options_attr->value() & 0x1) {
682         locked_ = true;
683       }
684     }
685     return;
686   } else if (msg.type() != STUN_DATA_INDICATION) {
687     LOG(INFO) << "Received BAD stun type from server: " << msg.type();
688     return;
689   }
690 
691   // This must be a data indication.
692 
693   const StunAddressAttribute* addr_attr =
694       msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
695   if (!addr_attr) {
696     LOG(INFO) << "Data indication has no source address";
697     return;
698   } else if (addr_attr->family() != 1) {
699     LOG(INFO) << "Source address has bad family";
700     return;
701   }
702 
703   talk_base::SocketAddress remote_addr2(addr_attr->ip(), addr_attr->port());
704 
705   const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
706   if (!data_attr) {
707     LOG(INFO) << "Data indication has no data";
708     return;
709   }
710 
711   // Process the actual data and remote address in the normal manner.
712   port_->OnReadPacket(data_attr->bytes(), data_attr->length(), remote_addr2);
713 }
714 
SendPacket(const void * data,size_t size)715 int RelayEntry::SendPacket(const void* data, size_t size) {
716   int sent = 0;
717   if (current_connection_) {
718     // We are connected, no need to send packets anywere else than to
719     // the current connection.
720     sent = current_connection_->Send(data, size);
721   }
722   return sent;
723 }
724 
AllocateRequest(RelayEntry * entry,RelayConnection * connection)725 AllocateRequest::AllocateRequest(RelayEntry* entry,
726                                  RelayConnection* connection) :
727     entry_(entry), connection_(connection) {
728   start_time_ = talk_base::Time();
729 }
730 
Prepare(StunMessage * request)731 void AllocateRequest::Prepare(StunMessage* request) {
732   request->SetType(STUN_ALLOCATE_REQUEST);
733 
734   StunByteStringAttribute* magic_cookie_attr =
735       StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
736   magic_cookie_attr->CopyBytes(
737       entry_->port()->magic_cookie().c_str(),
738       entry_->port()->magic_cookie().size());
739   request->AddAttribute(magic_cookie_attr);
740 
741   StunByteStringAttribute* username_attr =
742       StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
743   username_attr->CopyBytes(
744       entry_->port()->username_fragment().c_str(),
745       entry_->port()->username_fragment().size());
746   request->AddAttribute(username_attr);
747 }
748 
GetNextDelay()749 int AllocateRequest::GetNextDelay() {
750   int delay = 100 * talk_base::_max(1 << count_, 2);
751   count_ += 1;
752   if (count_ == 5)
753     timeout_ = true;
754   return delay;
755 }
756 
OnResponse(StunMessage * response)757 void AllocateRequest::OnResponse(StunMessage* response) {
758   const StunAddressAttribute* addr_attr =
759       response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
760   if (!addr_attr) {
761     LOG(INFO) << "Allocate response missing mapped address.";
762   } else if (addr_attr->family() != 1) {
763     LOG(INFO) << "Mapped address has bad family";
764   } else {
765     talk_base::SocketAddress addr(addr_attr->ip(), addr_attr->port());
766     entry_->OnConnect(addr, connection_);
767   }
768 
769   // We will do a keep-alive regardless of whether this request suceeds.
770   // This should have almost no impact on network usage.
771   entry_->ScheduleKeepAlive();
772 }
773 
OnErrorResponse(StunMessage * response)774 void AllocateRequest::OnErrorResponse(StunMessage* response) {
775   const StunErrorCodeAttribute* attr = response->GetErrorCode();
776   if (!attr) {
777     LOG(INFO) << "Bad allocate response error code";
778   } else {
779     LOG(INFO) << "Allocate error response:"
780               << " code=" << static_cast<int>(attr->error_code())
781               << " reason='" << attr->reason() << "'";
782   }
783 
784   if (talk_base::TimeSince(start_time_) <= kRetryTimeout)
785     entry_->ScheduleKeepAlive();
786 }
787 
OnTimeout()788 void AllocateRequest::OnTimeout() {
789   LOG(INFO) << "Allocate request timed out";
790   entry_->HandleConnectFailure(connection_->socket());
791 }
792 
793 }  // namespace cricket
794