3 * Copyright 2004--2005, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "talk/base/asyncpacketsocket.h"
29 #include "talk/base/helpers.h"
30 #include "talk/base/logging.h"
31 #include "talk/p2p/base/relayport.h"
35 static const uint32 kMessageConnectTimeout = 1;
36 static const int kKeepAliveDelay = 10 * 60 * 1000;
37 static const int kRetryTimeout = 50 * 1000; // ICE says 50 secs
38 // How long to wait for a socket to connect to remote host in milliseconds
39 // before trying another connection.
40 static const int kSoftConnectTimeoutMs = 3 * 1000;
42 // Handles a connection to one address/port/protocol combination for a
43 // particular RelayEntry.
44 class RelayConnection : public sigslot::has_slots<> {
46 RelayConnection(const ProtocolAddress* protocol_address,
47 talk_base::AsyncPacketSocket* socket,
48 talk_base::Thread* thread);
50 talk_base::AsyncPacketSocket* socket() const { return socket_; }
52 const ProtocolAddress* protocol_address() {
53 return protocol_address_;
56 talk_base::SocketAddress GetAddress() const {
57 return protocol_address_->address;
60 ProtocolType GetProtocol() const {
61 return protocol_address_->proto;
64 int SetSocketOption(talk_base::Socket::Option opt, int value);
66 // Validates a response to a STUN allocate request.
67 bool CheckResponse(StunMessage* msg);
69 // Sends data to the relay server.
70 int Send(const void* pv, size_t cb, const talk_base::PacketOptions& options);
72 // Sends a STUN allocate request message to the relay server.
73 void SendAllocateRequest(RelayEntry* entry, int delay);
75 // Return the latest error generated by the socket.
76 int GetError() { return socket_->GetError(); }
78 // Called on behalf of a StunRequest to write data to the socket. This is
79 // already STUN intended for the server, so no wrapping is necessary.
80 void OnSendPacket(const void* data, size_t size, StunRequest* req);
83 talk_base::AsyncPacketSocket* socket_;
84 const ProtocolAddress* protocol_address_;
85 StunRequestManager *request_manager_;
88 // Manages a number of connections to the relayserver, one for each
89 // available protocol. We aim to use each connection for only a
90 // specific destination address so that we can avoid wrapping every
91 // packet in a STUN send / data indication.
92 class RelayEntry : public talk_base::MessageHandler,
93 public sigslot::has_slots<> {
95 RelayEntry(RelayPort* port, const talk_base::SocketAddress& ext_addr);
98 RelayPort* port() { return port_; }
100 const talk_base::SocketAddress& address() const { return ext_addr_; }
101 void set_address(const talk_base::SocketAddress& addr) { ext_addr_ = addr; }
103 bool connected() const { return connected_; }
104 bool locked() const { return locked_; }
106 // Returns the last error on the socket of this entry.
109 // Returns the most preferred connection of the given
110 // ones. Connections are rated based on protocol in the order of:
111 // UDP, TCP and SSLTCP, where UDP is the most preferred protocol
112 static RelayConnection* GetBestConnection(RelayConnection* conn1,
113 RelayConnection* conn2);
115 // Sends the STUN requests to the server to initiate this connection.
118 // Called when this entry becomes connected. The address given is the one
119 // exposed to the outside world on the relay server.
120 void OnConnect(const talk_base::SocketAddress& mapped_addr,
121 RelayConnection* socket);
123 // Sends a packet to the given destination address using the socket of this
124 // entry. This will wrap the packet in STUN if necessary.
125 int SendTo(const void* data, size_t size,
126 const talk_base::SocketAddress& addr,
127 const talk_base::PacketOptions& options);
129 // Schedules a keep-alive allocate request.
130 void ScheduleKeepAlive();
132 void SetServerIndex(size_t sindex) { server_index_ = sindex; }
134 // Sets this option on the socket of each connection.
135 int SetSocketOption(talk_base::Socket::Option opt, int value);
137 size_t ServerIndex() const { return server_index_; }
139 // Try a different server address
140 void HandleConnectFailure(talk_base::AsyncPacketSocket* socket);
142 // Implementation of the MessageHandler Interface.
143 virtual void OnMessage(talk_base::Message *pmsg);
147 talk_base::SocketAddress ext_addr_;
148 size_t server_index_;
151 RelayConnection* current_connection_;
153 // Called when a TCP connection is established or fails
154 void OnSocketConnect(talk_base::AsyncPacketSocket* socket);
155 void OnSocketClose(talk_base::AsyncPacketSocket* socket, int error);
157 // Called when a packet is received on this socket.
159 talk_base::AsyncPacketSocket* socket,
160 const char* data, size_t size,
161 const talk_base::SocketAddress& remote_addr,
162 const talk_base::PacketTime& packet_time);
163 // Called when the socket is currently able to send.
164 void OnReadyToSend(talk_base::AsyncPacketSocket* socket);
166 // Sends the given data on the socket to the server with no wrapping. This
167 // returns the number of bytes written or -1 if an error occurred.
168 int SendPacket(const void* data, size_t size,
169 const talk_base::PacketOptions& options);
172 // Handles an allocate request for a particular RelayEntry.
173 class AllocateRequest : public StunRequest {
175 AllocateRequest(RelayEntry* entry, RelayConnection* connection);
176 virtual ~AllocateRequest() {}
178 virtual void Prepare(StunMessage* request);
180 virtual int GetNextDelay();
182 virtual void OnResponse(StunMessage* response);
183 virtual void OnErrorResponse(StunMessage* response);
184 virtual void OnTimeout();
188 RelayConnection* connection_;
192 RelayPort::RelayPort(
193 talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
194 talk_base::Network* network, const talk_base::IPAddress& ip,
195 int min_port, int max_port, const std::string& username,
196 const std::string& password)
197 : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port,
202 new RelayEntry(this, talk_base::SocketAddress()));
203 // TODO: set local preference value for TCP based candidates.
206 RelayPort::~RelayPort() {
207 for (size_t i = 0; i < entries_.size(); ++i)
209 thread()->Clear(this);
212 void RelayPort::AddServerAddress(const ProtocolAddress& addr) {
213 // Since HTTP proxies usually only allow 443,
214 // let's up the priority on PROTO_SSLTCP
215 if (addr.proto == PROTO_SSLTCP &&
216 (proxy().type == talk_base::PROXY_HTTPS ||
217 proxy().type == talk_base::PROXY_UNKNOWN)) {
218 server_addr_.push_front(addr);
220 server_addr_.push_back(addr);
224 void RelayPort::AddExternalAddress(const ProtocolAddress& addr) {
225 std::string proto_name = ProtoToString(addr.proto);
226 for (std::vector<ProtocolAddress>::iterator it = external_addr_.begin();
227 it != external_addr_.end(); ++it) {
228 if ((it->address == addr.address) && (it->proto == addr.proto)) {
229 LOG(INFO) << "Redundant relay address: " << proto_name
230 << " @ " << addr.address.ToSensitiveString();
234 external_addr_.push_back(addr);
237 void RelayPort::SetReady() {
239 std::vector<ProtocolAddress>::iterator iter;
240 for (iter = external_addr_.begin();
241 iter != external_addr_.end(); ++iter) {
242 std::string proto_name = ProtoToString(iter->proto);
243 AddAddress(iter->address, iter->address, proto_name,
244 RELAY_PORT_TYPE, ICE_TYPE_PREFERENCE_RELAY, false);
247 SignalPortComplete(this);
251 const ProtocolAddress * RelayPort::ServerAddress(size_t index) const {
252 if (index < server_addr_.size())
253 return &server_addr_[index];
257 bool RelayPort::HasMagicCookie(const char* data, size_t size) {
258 if (size < 24 + sizeof(TURN_MAGIC_COOKIE_VALUE)) {
261 return 0 == std::memcmp(data + 24, TURN_MAGIC_COOKIE_VALUE,
262 sizeof(TURN_MAGIC_COOKIE_VALUE));
266 void RelayPort::PrepareAddress() {
267 // We initiate a connect on the first entry. If this completes, it will fill
268 // in the server address as the address of this port.
269 ASSERT(entries_.size() == 1);
270 entries_[0]->Connect();
274 Connection* RelayPort::CreateConnection(const Candidate& address,
275 CandidateOrigin origin) {
276 // We only create conns to non-udp sockets if they are incoming on this port
277 if ((address.protocol() != UDP_PROTOCOL_NAME) &&
278 (origin != ORIGIN_THIS_PORT)) {
282 // We don't support loopback on relays
283 if (address.type() == Type()) {
287 if (!IsCompatibleAddress(address.address())) {
292 for (size_t i = 0; i < Candidates().size(); ++i) {
293 const Candidate& local = Candidates()[i];
294 if (local.protocol() == address.protocol()) {
300 Connection * conn = new ProxyConnection(this, index, address);
305 int RelayPort::SendTo(const void* data, size_t size,
306 const talk_base::SocketAddress& addr,
307 const talk_base::PacketOptions& options,
309 // Try to find an entry for this specific address. Note that the first entry
310 // created was not given an address initially, so it can be set to the first
311 // address that comes along.
312 RelayEntry* entry = 0;
314 for (size_t i = 0; i < entries_.size(); ++i) {
315 if (entries_[i]->address().IsNil() && payload) {
317 entry->set_address(addr);
319 } else if (entries_[i]->address() == addr) {
325 // If we did not find one, then we make a new one. This will not be useable
326 // until it becomes connected, however.
327 if (!entry && payload) {
328 entry = new RelayEntry(this, addr);
329 if (!entries_.empty()) {
330 entry->SetServerIndex(entries_[0]->ServerIndex());
333 entries_.push_back(entry);
336 // If the entry is connected, then we can send on it (though wrapping may
337 // still be necessary). Otherwise, we can't yet use this connection, so we
338 // default to the first one.
339 if (!entry || !entry->connected()) {
340 ASSERT(!entries_.empty());
342 if (!entry->connected()) {
343 error_ = EWOULDBLOCK;
348 // Send the actual contents to the server using the usual mechanism.
349 int sent = entry->SendTo(data, size, addr, options);
352 error_ = entry->GetError();
355 // The caller of the function is expecting the number of user data bytes,
356 // rather than the size of the packet.
357 return static_cast<int>(size);
360 int RelayPort::SetOption(talk_base::Socket::Option opt, int value) {
362 for (size_t i = 0; i < entries_.size(); ++i) {
363 if (entries_[i]->SetSocketOption(opt, value) < 0) {
365 error_ = entries_[i]->GetError();
368 options_.push_back(OptionValue(opt, value));
372 int RelayPort::GetOption(talk_base::Socket::Option opt, int* value) {
373 std::vector<OptionValue>::iterator it;
374 for (it = options_.begin(); it < options_.end(); ++it) {
375 if (it->first == opt) {
383 int RelayPort::GetError() {
387 void RelayPort::OnReadPacket(
388 const char* data, size_t size,
389 const talk_base::SocketAddress& remote_addr,
391 const talk_base::PacketTime& packet_time) {
392 if (Connection* conn = GetConnection(remote_addr)) {
393 conn->OnReadPacket(data, size, packet_time);
395 Port::OnReadPacket(data, size, remote_addr, proto);
399 RelayConnection::RelayConnection(const ProtocolAddress* protocol_address,
400 talk_base::AsyncPacketSocket* socket,
401 talk_base::Thread* thread)
403 protocol_address_(protocol_address) {
404 request_manager_ = new StunRequestManager(thread);
405 request_manager_->SignalSendPacket.connect(this,
406 &RelayConnection::OnSendPacket);
409 RelayConnection::~RelayConnection() {
410 delete request_manager_;
414 int RelayConnection::SetSocketOption(talk_base::Socket::Option opt,
417 return socket_->SetOption(opt, value);
422 bool RelayConnection::CheckResponse(StunMessage* msg) {
423 return request_manager_->CheckResponse(msg);
426 void RelayConnection::OnSendPacket(const void* data, size_t size,
428 // TODO(mallinath) Find a way to get DSCP value from Port.
429 talk_base::PacketOptions options; // Default dscp set to NO_CHANGE.
430 int sent = socket_->SendTo(data, size, GetAddress(), options);
432 LOG(LS_VERBOSE) << "OnSendPacket: failed sending to " << GetAddress() <<
433 std::strerror(socket_->GetError());
438 int RelayConnection::Send(const void* pv, size_t cb,
439 const talk_base::PacketOptions& options) {
440 return socket_->SendTo(pv, cb, GetAddress(), options);
443 void RelayConnection::SendAllocateRequest(RelayEntry* entry, int delay) {
444 request_manager_->SendDelayed(new AllocateRequest(entry, this), delay);
447 RelayEntry::RelayEntry(RelayPort* port,
448 const talk_base::SocketAddress& ext_addr)
449 : port_(port), ext_addr_(ext_addr),
450 server_index_(0), connected_(false), locked_(false),
451 current_connection_(NULL) {
454 RelayEntry::~RelayEntry() {
455 // Remove all RelayConnections and dispose sockets.
456 delete current_connection_;
457 current_connection_ = NULL;
460 void RelayEntry::Connect() {
461 // If we're already connected, return.
465 // If we've exhausted all options, bail out.
466 const ProtocolAddress* ra = port()->ServerAddress(server_index_);
468 LOG(LS_WARNING) << "No more relay addresses left to try";
472 // Remove any previous connection.
473 if (current_connection_) {
474 port()->thread()->Dispose(current_connection_);
475 current_connection_ = NULL;
478 // Try to set up our new socket.
479 LOG(LS_INFO) << "Connecting to relay via " << ProtoToString(ra->proto) <<
480 " @ " << ra->address.ToSensitiveString();
482 talk_base::AsyncPacketSocket* socket = NULL;
484 if (ra->proto == PROTO_UDP) {
485 // UDP sockets are simple.
486 socket = port_->socket_factory()->CreateUdpSocket(
487 talk_base::SocketAddress(port_->ip(), 0),
488 port_->min_port(), port_->max_port());
489 } else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) {
490 int opts = (ra->proto == PROTO_SSLTCP) ?
491 talk_base::PacketSocketFactory::OPT_SSLTCP : 0;
492 socket = port_->socket_factory()->CreateClientTcpSocket(
493 talk_base::SocketAddress(port_->ip(), 0), ra->address,
494 port_->proxy(), port_->user_agent(), opts);
496 LOG(LS_WARNING) << "Unknown protocol (" << ra->proto << ")";
500 LOG(LS_WARNING) << "Socket creation failed";
503 // If we failed to get a socket, move on to the next protocol.
505 port()->thread()->Post(this, kMessageConnectTimeout);
509 // Otherwise, create the new connection and configure any socket options.
510 socket->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket);
511 socket->SignalReadyToSend.connect(this, &RelayEntry::OnReadyToSend);
512 current_connection_ = new RelayConnection(ra, socket, port()->thread());
513 for (size_t i = 0; i < port_->options().size(); ++i) {
514 current_connection_->SetSocketOption(port_->options()[i].first,
515 port_->options()[i].second);
518 // If we're trying UDP, start binding requests.
519 // If we're trying TCP, wait for connection with a fixed timeout.
520 if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
521 socket->SignalClose.connect(this, &RelayEntry::OnSocketClose);
522 socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
523 port()->thread()->PostDelayed(kSoftConnectTimeoutMs, this,
524 kMessageConnectTimeout);
526 current_connection_->SendAllocateRequest(this, 0);
530 int RelayEntry::GetError() {
531 if (current_connection_ != NULL) {
532 return current_connection_->GetError();
537 RelayConnection* RelayEntry::GetBestConnection(RelayConnection* conn1,
538 RelayConnection* conn2) {
539 return conn1->GetProtocol() <= conn2->GetProtocol() ? conn1 : conn2;
542 void RelayEntry::OnConnect(const talk_base::SocketAddress& mapped_addr,
543 RelayConnection* connection) {
544 // We are connected, notify our parent.
545 ProtocolType proto = PROTO_UDP;
546 LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto)
547 << " @ " << mapped_addr.ToSensitiveString();
550 // In case of Gturn related address is set to null socket address.
551 // This is due to mapped address stun attribute is used for allocated
553 port_->set_related_address(talk_base::SocketAddress());
554 port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
558 int RelayEntry::SendTo(const void* data, size_t size,
559 const talk_base::SocketAddress& addr,
560 const talk_base::PacketOptions& options) {
561 // If this connection is locked to the address given, then we can send the
562 // packet with no wrapper.
563 if (locked_ && (ext_addr_ == addr))
564 return SendPacket(data, size, options);
566 // Otherwise, we must wrap the given data in a STUN SEND request so that we
567 // can communicate the destination address to the server.
569 // Note that we do not use a StunRequest here. This is because there is
570 // likely no reason to resend this packet. If it is late, we just drop it.
571 // The next send to this address will try again.
573 RelayMessage request;
574 request.SetType(STUN_SEND_REQUEST);
576 StunByteStringAttribute* magic_cookie_attr =
577 StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
578 magic_cookie_attr->CopyBytes(TURN_MAGIC_COOKIE_VALUE,
579 sizeof(TURN_MAGIC_COOKIE_VALUE));
580 VERIFY(request.AddAttribute(magic_cookie_attr));
582 StunByteStringAttribute* username_attr =
583 StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
584 username_attr->CopyBytes(port_->username_fragment().c_str(),
585 port_->username_fragment().size());
586 VERIFY(request.AddAttribute(username_attr));
588 StunAddressAttribute* addr_attr =
589 StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
590 addr_attr->SetIP(addr.ipaddr());
591 addr_attr->SetPort(addr.port());
592 VERIFY(request.AddAttribute(addr_attr));
595 if (ext_addr_ == addr) {
596 StunUInt32Attribute* options_attr =
597 StunAttribute::CreateUInt32(STUN_ATTR_OPTIONS);
598 options_attr->SetValue(0x1);
599 VERIFY(request.AddAttribute(options_attr));
602 StunByteStringAttribute* data_attr =
603 StunAttribute::CreateByteString(STUN_ATTR_DATA);
604 data_attr->CopyBytes(data, size);
605 VERIFY(request.AddAttribute(data_attr));
607 // TODO: compute the HMAC.
609 talk_base::ByteBuffer buf;
612 return SendPacket(buf.Data(), buf.Length(), options);
615 void RelayEntry::ScheduleKeepAlive() {
616 if (current_connection_) {
617 current_connection_->SendAllocateRequest(this, kKeepAliveDelay);
621 int RelayEntry::SetSocketOption(talk_base::Socket::Option opt, int value) {
622 // Set the option on all available sockets.
623 int socket_error = 0;
624 if (current_connection_) {
625 socket_error = current_connection_->SetSocketOption(opt, value);
630 void RelayEntry::HandleConnectFailure(
631 talk_base::AsyncPacketSocket* socket) {
632 // Make sure it's the current connection that has failed, it might
633 // be an old socked that has not yet been disposed.
635 (current_connection_ && socket == current_connection_->socket())) {
636 if (current_connection_)
637 port()->SignalConnectFailure(current_connection_->protocol_address());
639 // Try to connect to the next server address.
645 void RelayEntry::OnMessage(talk_base::Message *pmsg) {
646 ASSERT(pmsg->message_id == kMessageConnectTimeout);
647 if (current_connection_) {
648 const ProtocolAddress* ra = current_connection_->protocol_address();
649 LOG(LS_WARNING) << "Relay " << ra->proto << " connection to " <<
650 ra->address << " timed out";
652 // Currently we connect to each server address in sequence. If we
653 // have more addresses to try, treat this is an error and move on to
654 // the next address, otherwise give this connection more time and
655 // await the real timeout.
657 // TODO: Connect to servers in parallel to speed up connect time
658 // and to avoid giving up too early.
659 port_->SignalSoftTimeout(ra);
660 HandleConnectFailure(current_connection_->socket());
662 HandleConnectFailure(NULL);
666 void RelayEntry::OnSocketConnect(talk_base::AsyncPacketSocket* socket) {
667 LOG(INFO) << "relay tcp connected to " <<
668 socket->GetRemoteAddress().ToSensitiveString();
669 if (current_connection_ != NULL) {
670 current_connection_->SendAllocateRequest(this, 0);
674 void RelayEntry::OnSocketClose(talk_base::AsyncPacketSocket* socket,
676 PLOG(LERROR, error) << "Relay connection failed: socket closed";
677 HandleConnectFailure(socket);
680 void RelayEntry::OnReadPacket(
681 talk_base::AsyncPacketSocket* socket,
682 const char* data, size_t size,
683 const talk_base::SocketAddress& remote_addr,
684 const talk_base::PacketTime& packet_time) {
685 // ASSERT(remote_addr == port_->server_addr());
686 // TODO: are we worried about this?
688 if (current_connection_ == NULL || socket != current_connection_->socket()) {
689 // This packet comes from an unknown address.
690 LOG(WARNING) << "Dropping packet: unknown address";
694 // If the magic cookie is not present, then this is an unwrapped packet sent
695 // by the server, The actual remote address is the one we recorded.
696 if (!port_->HasMagicCookie(data, size)) {
698 port_->OnReadPacket(data, size, ext_addr_, PROTO_UDP, packet_time);
700 LOG(WARNING) << "Dropping packet: entry not locked";
705 talk_base::ByteBuffer buf(data, size);
707 if (!msg.Read(&buf)) {
708 LOG(INFO) << "Incoming packet was not STUN";
712 // The incoming packet should be a STUN ALLOCATE response, SEND response, or
714 if (current_connection_->CheckResponse(&msg)) {
716 } else if (msg.type() == STUN_SEND_RESPONSE) {
717 if (const StunUInt32Attribute* options_attr =
718 msg.GetUInt32(STUN_ATTR_OPTIONS)) {
719 if (options_attr->value() & 0x1) {
724 } else if (msg.type() != STUN_DATA_INDICATION) {
725 LOG(INFO) << "Received BAD stun type from server: " << msg.type();
729 // This must be a data indication.
731 const StunAddressAttribute* addr_attr =
732 msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
734 LOG(INFO) << "Data indication has no source address";
736 } else if (addr_attr->family() != 1) {
737 LOG(INFO) << "Source address has bad family";
741 talk_base::SocketAddress remote_addr2(addr_attr->ipaddr(), addr_attr->port());
743 const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
745 LOG(INFO) << "Data indication has no data";
749 // Process the actual data and remote address in the normal manner.
750 port_->OnReadPacket(data_attr->bytes(), data_attr->length(), remote_addr2,
751 PROTO_UDP, packet_time);
754 void RelayEntry::OnReadyToSend(talk_base::AsyncPacketSocket* socket) {
756 port_->OnReadyToSend();
760 int RelayEntry::SendPacket(const void* data, size_t size,
761 const talk_base::PacketOptions& options) {
763 if (current_connection_) {
764 // We are connected, no need to send packets anywere else than to
765 // the current connection.
766 sent = current_connection_->Send(data, size, options);
771 AllocateRequest::AllocateRequest(RelayEntry* entry,
772 RelayConnection* connection)
773 : StunRequest(new RelayMessage()),
775 connection_(connection) {
776 start_time_ = talk_base::Time();
779 void AllocateRequest::Prepare(StunMessage* request) {
780 request->SetType(STUN_ALLOCATE_REQUEST);
782 StunByteStringAttribute* username_attr =
783 StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
784 username_attr->CopyBytes(
785 entry_->port()->username_fragment().c_str(),
786 entry_->port()->username_fragment().size());
787 VERIFY(request->AddAttribute(username_attr));
790 int AllocateRequest::GetNextDelay() {
791 int delay = 100 * talk_base::_max(1 << count_, 2);
798 void AllocateRequest::OnResponse(StunMessage* response) {
799 const StunAddressAttribute* addr_attr =
800 response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
802 LOG(INFO) << "Allocate response missing mapped address.";
803 } else if (addr_attr->family() != 1) {
804 LOG(INFO) << "Mapped address has bad family";
806 talk_base::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
807 entry_->OnConnect(addr, connection_);
810 // We will do a keep-alive regardless of whether this request suceeds.
811 // This should have almost no impact on network usage.
812 entry_->ScheduleKeepAlive();
815 void AllocateRequest::OnErrorResponse(StunMessage* response) {
816 const StunErrorCodeAttribute* attr = response->GetErrorCode();
818 LOG(INFO) << "Bad allocate response error code";
820 LOG(INFO) << "Allocate error response:"
821 << " code=" << attr->code()
822 << " reason='" << attr->reason() << "'";
825 if (talk_base::TimeSince(start_time_) <= kRetryTimeout)
826 entry_->ScheduleKeepAlive();
829 void AllocateRequest::OnTimeout() {
830 LOG(INFO) << "Allocate request timed out";
831 entry_->HandleConnectFailure(connection_->socket());
834 } // namespace cricket