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