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