Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2004--2005, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      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.
     15  *
     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.
     26  */
     27 
     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"
     32 
     33 namespace cricket {
     34 
     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;
     41 
     42 // Handles a connection to one address/port/protocol combination for a
     43 // particular RelayEntry.
     44 class RelayConnection : public sigslot::has_slots<> {
     45  public:
     46   RelayConnection(const ProtocolAddress* protocol_address,
     47                   talk_base::AsyncPacketSocket* socket,
     48                   talk_base::Thread* thread);
     49   ~RelayConnection();
     50   talk_base::AsyncPacketSocket* socket() const { return socket_; }
     51 
     52   const ProtocolAddress* protocol_address() {
     53     return protocol_address_;
     54   }
     55 
     56   talk_base::SocketAddress GetAddress() const {
     57     return protocol_address_->address;
     58   }
     59 
     60   ProtocolType GetProtocol() const {
     61     return protocol_address_->proto;
     62   }
     63 
     64   int SetSocketOption(talk_base::Socket::Option opt, int value);
     65 
     66   // Validates a response to a STUN allocate request.
     67   bool CheckResponse(StunMessage* msg);
     68 
     69   // Sends data to the relay server.
     70   int Send(const void* pv, size_t cb, const talk_base::PacketOptions& options);
     71 
     72   // Sends a STUN allocate request message to the relay server.
     73   void SendAllocateRequest(RelayEntry* entry, int delay);
     74 
     75   // Return the latest error generated by the socket.
     76   int GetError() { return socket_->GetError(); }
     77 
     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);
     81 
     82  private:
     83   talk_base::AsyncPacketSocket* socket_;
     84   const ProtocolAddress* protocol_address_;
     85   StunRequestManager *request_manager_;
     86 };
     87 
     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<> {
     94  public:
     95   RelayEntry(RelayPort* port, const talk_base::SocketAddress& ext_addr);
     96   ~RelayEntry();
     97 
     98   RelayPort* port() { return port_; }
     99 
    100   const talk_base::SocketAddress& address() const { return ext_addr_; }
    101   void set_address(const talk_base::SocketAddress& addr) { ext_addr_ = addr; }
    102 
    103   bool connected() const { return connected_; }
    104   bool locked() const { return locked_; }
    105 
    106   // Returns the last error on the socket of this entry.
    107   int GetError();
    108 
    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);
    114 
    115   // Sends the STUN requests to the server to initiate this connection.
    116   void Connect();
    117 
    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);
    122 
    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);
    128 
    129   // Schedules a keep-alive allocate request.
    130   void ScheduleKeepAlive();
    131 
    132   void SetServerIndex(size_t sindex) { server_index_ = sindex; }
    133 
    134   // Sets this option on the socket of each connection.
    135   int SetSocketOption(talk_base::Socket::Option opt, int value);
    136 
    137   size_t ServerIndex() const { return server_index_; }
    138 
    139   // Try a different server address
    140   void HandleConnectFailure(talk_base::AsyncPacketSocket* socket);
    141 
    142   // Implementation of the MessageHandler Interface.
    143   virtual void OnMessage(talk_base::Message *pmsg);
    144 
    145  private:
    146   RelayPort* port_;
    147   talk_base::SocketAddress ext_addr_;
    148   size_t server_index_;
    149   bool connected_;
    150   bool locked_;
    151   RelayConnection* current_connection_;
    152 
    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);
    156 
    157   // Called when a packet is received on this socket.
    158   void OnReadPacket(
    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);
    165 
    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);
    170 };
    171 
    172 // Handles an allocate request for a particular RelayEntry.
    173 class AllocateRequest : public StunRequest {
    174  public:
    175   AllocateRequest(RelayEntry* entry, RelayConnection* connection);
    176   virtual ~AllocateRequest() {}
    177 
    178   virtual void Prepare(StunMessage* request);
    179 
    180   virtual int GetNextDelay();
    181 
    182   virtual void OnResponse(StunMessage* response);
    183   virtual void OnErrorResponse(StunMessage* response);
    184   virtual void OnTimeout();
    185 
    186  private:
    187   RelayEntry* entry_;
    188   RelayConnection* connection_;
    189   uint32 start_time_;
    190 };
    191 
    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,
    198            username, password),
    199       ready_(false),
    200       error_(0) {
    201   entries_.push_back(
    202       new RelayEntry(this, talk_base::SocketAddress()));
    203   // TODO: set local preference value for TCP based candidates.
    204 }
    205 
    206 RelayPort::~RelayPort() {
    207   for (size_t i = 0; i < entries_.size(); ++i)
    208     delete entries_[i];
    209   thread()->Clear(this);
    210 }
    211 
    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);
    219   } else {
    220     server_addr_.push_back(addr);
    221   }
    222 }
    223 
    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();
    231       return;
    232     }
    233   }
    234   external_addr_.push_back(addr);
    235 }
    236 
    237 void RelayPort::SetReady() {
    238   if (!ready_) {
    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       // In case of Gturn, related address is set to null socket address.
    244       // This is due to as mapped address stun attribute is used for allocated
    245       // address.
    246       AddAddress(iter->address, iter->address, talk_base::SocketAddress(),
    247                  proto_name, RELAY_PORT_TYPE, ICE_TYPE_PREFERENCE_RELAY, false);
    248     }
    249     ready_ = true;
    250     SignalPortComplete(this);
    251   }
    252 }
    253 
    254 const ProtocolAddress * RelayPort::ServerAddress(size_t index) const {
    255   if (index < server_addr_.size())
    256     return &server_addr_[index];
    257   return NULL;
    258 }
    259 
    260 bool RelayPort::HasMagicCookie(const char* data, size_t size) {
    261   if (size < 24 + sizeof(TURN_MAGIC_COOKIE_VALUE)) {
    262     return false;
    263   } else {
    264     return memcmp(data + 24,
    265                   TURN_MAGIC_COOKIE_VALUE,
    266                   sizeof(TURN_MAGIC_COOKIE_VALUE)) == 0;
    267   }
    268 }
    269 
    270 void RelayPort::PrepareAddress() {
    271   // We initiate a connect on the first entry.  If this completes, it will fill
    272   // in the server address as the address of this port.
    273   ASSERT(entries_.size() == 1);
    274   entries_[0]->Connect();
    275   ready_ = false;
    276 }
    277 
    278 Connection* RelayPort::CreateConnection(const Candidate& address,
    279                                         CandidateOrigin origin) {
    280   // We only create conns to non-udp sockets if they are incoming on this port
    281   if ((address.protocol() != UDP_PROTOCOL_NAME) &&
    282       (origin != ORIGIN_THIS_PORT)) {
    283     return 0;
    284   }
    285 
    286   // We don't support loopback on relays
    287   if (address.type() == Type()) {
    288     return 0;
    289   }
    290 
    291   if (!IsCompatibleAddress(address.address())) {
    292     return 0;
    293   }
    294 
    295   size_t index = 0;
    296   for (size_t i = 0; i < Candidates().size(); ++i) {
    297     const Candidate& local = Candidates()[i];
    298     if (local.protocol() == address.protocol()) {
    299       index = i;
    300       break;
    301     }
    302   }
    303 
    304   Connection * conn = new ProxyConnection(this, index, address);
    305   AddConnection(conn);
    306   return conn;
    307 }
    308 
    309 int RelayPort::SendTo(const void* data, size_t size,
    310                       const talk_base::SocketAddress& addr,
    311                       const talk_base::PacketOptions& options,
    312                       bool payload) {
    313   // Try to find an entry for this specific address.  Note that the first entry
    314   // created was not given an address initially, so it can be set to the first
    315   // address that comes along.
    316   RelayEntry* entry = 0;
    317 
    318   for (size_t i = 0; i < entries_.size(); ++i) {
    319     if (entries_[i]->address().IsNil() && payload) {
    320       entry = entries_[i];
    321       entry->set_address(addr);
    322       break;
    323     } else if (entries_[i]->address() == addr) {
    324       entry = entries_[i];
    325       break;
    326     }
    327   }
    328 
    329   // If we did not find one, then we make a new one.  This will not be useable
    330   // until it becomes connected, however.
    331   if (!entry && payload) {
    332     entry = new RelayEntry(this, addr);
    333     if (!entries_.empty()) {
    334       entry->SetServerIndex(entries_[0]->ServerIndex());
    335     }
    336     entry->Connect();
    337     entries_.push_back(entry);
    338   }
    339 
    340   // If the entry is connected, then we can send on it (though wrapping may
    341   // still be necessary).  Otherwise, we can't yet use this connection, so we
    342   // default to the first one.
    343   if (!entry || !entry->connected()) {
    344     ASSERT(!entries_.empty());
    345     entry = entries_[0];
    346     if (!entry->connected()) {
    347       error_ = EWOULDBLOCK;
    348       return SOCKET_ERROR;
    349     }
    350   }
    351 
    352   // Send the actual contents to the server using the usual mechanism.
    353   int sent = entry->SendTo(data, size, addr, options);
    354   if (sent <= 0) {
    355     ASSERT(sent < 0);
    356     error_ = entry->GetError();
    357     return SOCKET_ERROR;
    358   }
    359   // The caller of the function is expecting the number of user data bytes,
    360   // rather than the size of the packet.
    361   return static_cast<int>(size);
    362 }
    363 
    364 int RelayPort::SetOption(talk_base::Socket::Option opt, int value) {
    365   int result = 0;
    366   for (size_t i = 0; i < entries_.size(); ++i) {
    367     if (entries_[i]->SetSocketOption(opt, value) < 0) {
    368       result = -1;
    369       error_ = entries_[i]->GetError();
    370     }
    371   }
    372   options_.push_back(OptionValue(opt, value));
    373   return result;
    374 }
    375 
    376 int RelayPort::GetOption(talk_base::Socket::Option opt, int* value) {
    377   std::vector<OptionValue>::iterator it;
    378   for (it = options_.begin(); it < options_.end(); ++it) {
    379     if (it->first == opt) {
    380       *value = it->second;
    381       return 0;
    382     }
    383   }
    384   return SOCKET_ERROR;
    385 }
    386 
    387 int RelayPort::GetError() {
    388   return error_;
    389 }
    390 
    391 void RelayPort::OnReadPacket(
    392     const char* data, size_t size,
    393     const talk_base::SocketAddress& remote_addr,
    394     ProtocolType proto,
    395     const talk_base::PacketTime& packet_time) {
    396   if (Connection* conn = GetConnection(remote_addr)) {
    397     conn->OnReadPacket(data, size, packet_time);
    398   } else {
    399     Port::OnReadPacket(data, size, remote_addr, proto);
    400   }
    401 }
    402 
    403 RelayConnection::RelayConnection(const ProtocolAddress* protocol_address,
    404                                  talk_base::AsyncPacketSocket* socket,
    405                                  talk_base::Thread* thread)
    406     : socket_(socket),
    407       protocol_address_(protocol_address) {
    408   request_manager_ = new StunRequestManager(thread);
    409   request_manager_->SignalSendPacket.connect(this,
    410                                              &RelayConnection::OnSendPacket);
    411 }
    412 
    413 RelayConnection::~RelayConnection() {
    414   delete request_manager_;
    415   delete socket_;
    416 }
    417 
    418 int RelayConnection::SetSocketOption(talk_base::Socket::Option opt,
    419                                      int value) {
    420   if (socket_) {
    421     return socket_->SetOption(opt, value);
    422   }
    423   return 0;
    424 }
    425 
    426 bool RelayConnection::CheckResponse(StunMessage* msg) {
    427   return request_manager_->CheckResponse(msg);
    428 }
    429 
    430 void RelayConnection::OnSendPacket(const void* data, size_t size,
    431                                    StunRequest* req) {
    432   // TODO(mallinath) Find a way to get DSCP value from Port.
    433   talk_base::PacketOptions options;  // Default dscp set to NO_CHANGE.
    434   int sent = socket_->SendTo(data, size, GetAddress(), options);
    435   if (sent <= 0) {
    436     LOG(LS_VERBOSE) << "OnSendPacket: failed sending to " << GetAddress() <<
    437         strerror(socket_->GetError());
    438     ASSERT(sent < 0);
    439   }
    440 }
    441 
    442 int RelayConnection::Send(const void* pv, size_t cb,
    443                           const talk_base::PacketOptions& options) {
    444   return socket_->SendTo(pv, cb, GetAddress(), options);
    445 }
    446 
    447 void RelayConnection::SendAllocateRequest(RelayEntry* entry, int delay) {
    448   request_manager_->SendDelayed(new AllocateRequest(entry, this), delay);
    449 }
    450 
    451 RelayEntry::RelayEntry(RelayPort* port,
    452                        const talk_base::SocketAddress& ext_addr)
    453     : port_(port), ext_addr_(ext_addr),
    454       server_index_(0), connected_(false), locked_(false),
    455       current_connection_(NULL) {
    456 }
    457 
    458 RelayEntry::~RelayEntry() {
    459   // Remove all RelayConnections and dispose sockets.
    460   delete current_connection_;
    461   current_connection_ = NULL;
    462 }
    463 
    464 void RelayEntry::Connect() {
    465   // If we're already connected, return.
    466   if (connected_)
    467     return;
    468 
    469   // If we've exhausted all options, bail out.
    470   const ProtocolAddress* ra = port()->ServerAddress(server_index_);
    471   if (!ra) {
    472     LOG(LS_WARNING) << "No more relay addresses left to try";
    473     return;
    474   }
    475 
    476   // Remove any previous connection.
    477   if (current_connection_) {
    478     port()->thread()->Dispose(current_connection_);
    479     current_connection_ = NULL;
    480   }
    481 
    482   // Try to set up our new socket.
    483   LOG(LS_INFO) << "Connecting to relay via " << ProtoToString(ra->proto) <<
    484       " @ " << ra->address.ToSensitiveString();
    485 
    486   talk_base::AsyncPacketSocket* socket = NULL;
    487 
    488   if (ra->proto == PROTO_UDP) {
    489     // UDP sockets are simple.
    490     socket = port_->socket_factory()->CreateUdpSocket(
    491         talk_base::SocketAddress(port_->ip(), 0),
    492         port_->min_port(), port_->max_port());
    493   } else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) {
    494     int opts = (ra->proto == PROTO_SSLTCP) ?
    495      talk_base::PacketSocketFactory::OPT_SSLTCP : 0;
    496     socket = port_->socket_factory()->CreateClientTcpSocket(
    497         talk_base::SocketAddress(port_->ip(), 0), ra->address,
    498         port_->proxy(), port_->user_agent(), opts);
    499   } else {
    500     LOG(LS_WARNING) << "Unknown protocol (" << ra->proto << ")";
    501   }
    502 
    503   if (!socket) {
    504     LOG(LS_WARNING) << "Socket creation failed";
    505   }
    506 
    507   // If we failed to get a socket, move on to the next protocol.
    508   if (!socket) {
    509     port()->thread()->Post(this, kMessageConnectTimeout);
    510     return;
    511   }
    512 
    513   // Otherwise, create the new connection and configure any socket options.
    514   socket->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket);
    515   socket->SignalReadyToSend.connect(this, &RelayEntry::OnReadyToSend);
    516   current_connection_ = new RelayConnection(ra, socket, port()->thread());
    517   for (size_t i = 0; i < port_->options().size(); ++i) {
    518     current_connection_->SetSocketOption(port_->options()[i].first,
    519                                          port_->options()[i].second);
    520   }
    521 
    522   // If we're trying UDP, start binding requests.
    523   // If we're trying TCP, wait for connection with a fixed timeout.
    524   if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
    525     socket->SignalClose.connect(this, &RelayEntry::OnSocketClose);
    526     socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
    527     port()->thread()->PostDelayed(kSoftConnectTimeoutMs, this,
    528                                   kMessageConnectTimeout);
    529   } else {
    530     current_connection_->SendAllocateRequest(this, 0);
    531   }
    532 }
    533 
    534 int RelayEntry::GetError() {
    535   if (current_connection_ != NULL) {
    536     return current_connection_->GetError();
    537   }
    538   return 0;
    539 }
    540 
    541 RelayConnection* RelayEntry::GetBestConnection(RelayConnection* conn1,
    542                                                RelayConnection* conn2) {
    543   return conn1->GetProtocol() <= conn2->GetProtocol() ? conn1 : conn2;
    544 }
    545 
    546 void RelayEntry::OnConnect(const talk_base::SocketAddress& mapped_addr,
    547                            RelayConnection* connection) {
    548   // We are connected, notify our parent.
    549   ProtocolType proto = PROTO_UDP;
    550   LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto)
    551             << " @ " << mapped_addr.ToSensitiveString();
    552   connected_ = true;
    553 
    554   port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
    555   port_->SetReady();
    556 }
    557 
    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);
    565 
    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.
    568   //
    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.
    572 
    573   RelayMessage request;
    574   request.SetType(STUN_SEND_REQUEST);
    575 
    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));
    581 
    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));
    587 
    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));
    593 
    594   // Attempt to lock
    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));
    600   }
    601 
    602   StunByteStringAttribute* data_attr =
    603       StunAttribute::CreateByteString(STUN_ATTR_DATA);
    604   data_attr->CopyBytes(data, size);
    605   VERIFY(request.AddAttribute(data_attr));
    606 
    607   // TODO: compute the HMAC.
    608 
    609   talk_base::ByteBuffer buf;
    610   request.Write(&buf);
    611 
    612   return SendPacket(buf.Data(), buf.Length(), options);
    613 }
    614 
    615 void RelayEntry::ScheduleKeepAlive() {
    616   if (current_connection_) {
    617     current_connection_->SendAllocateRequest(this, kKeepAliveDelay);
    618   }
    619 }
    620 
    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);
    626   }
    627   return socket_error;
    628 }
    629 
    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.
    634   if (!socket ||
    635       (current_connection_ && socket == current_connection_->socket())) {
    636     if (current_connection_)
    637       port()->SignalConnectFailure(current_connection_->protocol_address());
    638 
    639     // Try to connect to the next server address.
    640     server_index_ += 1;
    641     Connect();
    642   }
    643 }
    644 
    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";
    651 
    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.
    656     //
    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());
    661   } else {
    662     HandleConnectFailure(NULL);
    663   }
    664 }
    665 
    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);
    671   }
    672 }
    673 
    674 void RelayEntry::OnSocketClose(talk_base::AsyncPacketSocket* socket,
    675                                int error) {
    676   PLOG(LERROR, error) << "Relay connection failed: socket closed";
    677   HandleConnectFailure(socket);
    678 }
    679 
    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?
    687 
    688   if (current_connection_ == NULL || socket != current_connection_->socket()) {
    689     // This packet comes from an unknown address.
    690     LOG(WARNING) << "Dropping packet: unknown address";
    691     return;
    692   }
    693 
    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)) {
    697     if (locked_) {
    698       port_->OnReadPacket(data, size, ext_addr_, PROTO_UDP, packet_time);
    699     } else {
    700       LOG(WARNING) << "Dropping packet: entry not locked";
    701     }
    702     return;
    703   }
    704 
    705   talk_base::ByteBuffer buf(data, size);
    706   RelayMessage msg;
    707   if (!msg.Read(&buf)) {
    708     LOG(INFO) << "Incoming packet was not STUN";
    709     return;
    710   }
    711 
    712   // The incoming packet should be a STUN ALLOCATE response, SEND response, or
    713   // DATA indication.
    714   if (current_connection_->CheckResponse(&msg)) {
    715     return;
    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) {
    720         locked_ = true;
    721       }
    722     }
    723     return;
    724   } else if (msg.type() != STUN_DATA_INDICATION) {
    725     LOG(INFO) << "Received BAD stun type from server: " << msg.type();
    726     return;
    727   }
    728 
    729   // This must be a data indication.
    730 
    731   const StunAddressAttribute* addr_attr =
    732       msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
    733   if (!addr_attr) {
    734     LOG(INFO) << "Data indication has no source address";
    735     return;
    736   } else if (addr_attr->family() != 1) {
    737     LOG(INFO) << "Source address has bad family";
    738     return;
    739   }
    740 
    741   talk_base::SocketAddress remote_addr2(addr_attr->ipaddr(), addr_attr->port());
    742 
    743   const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
    744   if (!data_attr) {
    745     LOG(INFO) << "Data indication has no data";
    746     return;
    747   }
    748 
    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);
    752 }
    753 
    754 void RelayEntry::OnReadyToSend(talk_base::AsyncPacketSocket* socket) {
    755   if (connected()) {
    756     port_->OnReadyToSend();
    757   }
    758 }
    759 
    760 int RelayEntry::SendPacket(const void* data, size_t size,
    761                            const talk_base::PacketOptions& options) {
    762   int sent = 0;
    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);
    767   }
    768   return sent;
    769 }
    770 
    771 AllocateRequest::AllocateRequest(RelayEntry* entry,
    772                                  RelayConnection* connection)
    773     : StunRequest(new RelayMessage()),
    774       entry_(entry),
    775       connection_(connection) {
    776   start_time_ = talk_base::Time();
    777 }
    778 
    779 void AllocateRequest::Prepare(StunMessage* request) {
    780   request->SetType(STUN_ALLOCATE_REQUEST);
    781 
    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));
    788 }
    789 
    790 int AllocateRequest::GetNextDelay() {
    791   int delay = 100 * talk_base::_max(1 << count_, 2);
    792   count_ += 1;
    793   if (count_ == 5)
    794     timeout_ = true;
    795   return delay;
    796 }
    797 
    798 void AllocateRequest::OnResponse(StunMessage* response) {
    799   const StunAddressAttribute* addr_attr =
    800       response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
    801   if (!addr_attr) {
    802     LOG(INFO) << "Allocate response missing mapped address.";
    803   } else if (addr_attr->family() != 1) {
    804     LOG(INFO) << "Mapped address has bad family";
    805   } else {
    806     talk_base::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
    807     entry_->OnConnect(addr, connection_);
    808   }
    809 
    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();
    813 }
    814 
    815 void AllocateRequest::OnErrorResponse(StunMessage* response) {
    816   const StunErrorCodeAttribute* attr = response->GetErrorCode();
    817   if (!attr) {
    818     LOG(INFO) << "Bad allocate response error code";
    819   } else {
    820     LOG(INFO) << "Allocate error response:"
    821               << " code=" << attr->code()
    822               << " reason='" << attr->reason() << "'";
    823   }
    824 
    825   if (talk_base::TimeSince(start_time_) <= kRetryTimeout)
    826     entry_->ScheduleKeepAlive();
    827 }
    828 
    829 void AllocateRequest::OnTimeout() {
    830   LOG(INFO) << "Allocate request timed out";
    831   entry_->HandleConnectFailure(connection_->socket());
    832 }
    833 
    834 }  // namespace cricket
    835