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