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