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