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