Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/p2p/base/relayserver.h"
     12 
     13 #ifdef WEBRTC_POSIX
     14 #include <errno.h>
     15 #endif  // WEBRTC_POSIX
     16 
     17 #include <algorithm>
     18 
     19 #include "webrtc/base/asynctcpsocket.h"
     20 #include "webrtc/base/helpers.h"
     21 #include "webrtc/base/logging.h"
     22 #include "webrtc/base/socketadapters.h"
     23 
     24 namespace cricket {
     25 
     26 // By default, we require a ping every 90 seconds.
     27 const int MAX_LIFETIME = 15 * 60 * 1000;
     28 
     29 // The number of bytes in each of the usernames we use.
     30 const uint32_t USERNAME_LENGTH = 16;
     31 
     32 // Calls SendTo on the given socket and logs any bad results.
     33 void Send(rtc::AsyncPacketSocket* socket, const char* bytes, size_t size,
     34           const rtc::SocketAddress& addr) {
     35   rtc::PacketOptions options;
     36   int result = socket->SendTo(bytes, size, addr, options);
     37   if (result < static_cast<int>(size)) {
     38     LOG(LS_ERROR) << "SendTo wrote only " << result << " of " << size
     39                   << " bytes";
     40   } else if (result < 0) {
     41     LOG_ERR(LS_ERROR) << "SendTo";
     42   }
     43 }
     44 
     45 // Sends the given STUN message on the given socket.
     46 void SendStun(const StunMessage& msg,
     47               rtc::AsyncPacketSocket* socket,
     48               const rtc::SocketAddress& addr) {
     49   rtc::ByteBuffer buf;
     50   msg.Write(&buf);
     51   Send(socket, buf.Data(), buf.Length(), addr);
     52 }
     53 
     54 // Constructs a STUN error response and sends it on the given socket.
     55 void SendStunError(const StunMessage& msg, rtc::AsyncPacketSocket* socket,
     56                    const rtc::SocketAddress& remote_addr, int error_code,
     57                    const char* error_desc, const std::string& magic_cookie) {
     58   RelayMessage err_msg;
     59   err_msg.SetType(GetStunErrorResponseType(msg.type()));
     60   err_msg.SetTransactionID(msg.transaction_id());
     61 
     62   StunByteStringAttribute* magic_cookie_attr =
     63       StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
     64   if (magic_cookie.size() == 0) {
     65     magic_cookie_attr->CopyBytes(cricket::TURN_MAGIC_COOKIE_VALUE,
     66                                  sizeof(cricket::TURN_MAGIC_COOKIE_VALUE));
     67   } else {
     68     magic_cookie_attr->CopyBytes(magic_cookie.c_str(), magic_cookie.size());
     69   }
     70   err_msg.AddAttribute(magic_cookie_attr);
     71 
     72   StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
     73   err_code->SetClass(error_code / 100);
     74   err_code->SetNumber(error_code % 100);
     75   err_code->SetReason(error_desc);
     76   err_msg.AddAttribute(err_code);
     77 
     78   SendStun(err_msg, socket, remote_addr);
     79 }
     80 
     81 RelayServer::RelayServer(rtc::Thread* thread)
     82   : thread_(thread), log_bindings_(true) {
     83 }
     84 
     85 RelayServer::~RelayServer() {
     86   // Deleting the binding will cause it to be removed from the map.
     87   while (!bindings_.empty())
     88     delete bindings_.begin()->second;
     89   for (size_t i = 0; i < internal_sockets_.size(); ++i)
     90     delete internal_sockets_[i];
     91   for (size_t i = 0; i < external_sockets_.size(); ++i)
     92     delete external_sockets_[i];
     93   for (size_t i = 0; i < removed_sockets_.size(); ++i)
     94     delete removed_sockets_[i];
     95   while (!server_sockets_.empty()) {
     96     rtc::AsyncSocket* socket = server_sockets_.begin()->first;
     97     server_sockets_.erase(server_sockets_.begin()->first);
     98     delete socket;
     99   }
    100 }
    101 
    102 void RelayServer::AddInternalSocket(rtc::AsyncPacketSocket* socket) {
    103   ASSERT(internal_sockets_.end() ==
    104       std::find(internal_sockets_.begin(), internal_sockets_.end(), socket));
    105   internal_sockets_.push_back(socket);
    106   socket->SignalReadPacket.connect(this, &RelayServer::OnInternalPacket);
    107 }
    108 
    109 void RelayServer::RemoveInternalSocket(rtc::AsyncPacketSocket* socket) {
    110   SocketList::iterator iter =
    111       std::find(internal_sockets_.begin(), internal_sockets_.end(), socket);
    112   ASSERT(iter != internal_sockets_.end());
    113   internal_sockets_.erase(iter);
    114   removed_sockets_.push_back(socket);
    115   socket->SignalReadPacket.disconnect(this);
    116 }
    117 
    118 void RelayServer::AddExternalSocket(rtc::AsyncPacketSocket* socket) {
    119   ASSERT(external_sockets_.end() ==
    120       std::find(external_sockets_.begin(), external_sockets_.end(), socket));
    121   external_sockets_.push_back(socket);
    122   socket->SignalReadPacket.connect(this, &RelayServer::OnExternalPacket);
    123 }
    124 
    125 void RelayServer::RemoveExternalSocket(rtc::AsyncPacketSocket* socket) {
    126   SocketList::iterator iter =
    127       std::find(external_sockets_.begin(), external_sockets_.end(), socket);
    128   ASSERT(iter != external_sockets_.end());
    129   external_sockets_.erase(iter);
    130   removed_sockets_.push_back(socket);
    131   socket->SignalReadPacket.disconnect(this);
    132 }
    133 
    134 void RelayServer::AddInternalServerSocket(rtc::AsyncSocket* socket,
    135                                           cricket::ProtocolType proto) {
    136   ASSERT(server_sockets_.end() ==
    137          server_sockets_.find(socket));
    138   server_sockets_[socket] = proto;
    139   socket->SignalReadEvent.connect(this, &RelayServer::OnReadEvent);
    140 }
    141 
    142 void RelayServer::RemoveInternalServerSocket(
    143     rtc::AsyncSocket* socket) {
    144   ServerSocketMap::iterator iter = server_sockets_.find(socket);
    145   ASSERT(iter != server_sockets_.end());
    146   server_sockets_.erase(iter);
    147   socket->SignalReadEvent.disconnect(this);
    148 }
    149 
    150 int RelayServer::GetConnectionCount() const {
    151   return static_cast<int>(connections_.size());
    152 }
    153 
    154 rtc::SocketAddressPair RelayServer::GetConnection(int connection) const {
    155   int i = 0;
    156   for (ConnectionMap::const_iterator it = connections_.begin();
    157        it != connections_.end(); ++it) {
    158     if (i == connection) {
    159       return it->second->addr_pair();
    160     }
    161     ++i;
    162   }
    163   return rtc::SocketAddressPair();
    164 }
    165 
    166 bool RelayServer::HasConnection(const rtc::SocketAddress& address) const {
    167   for (ConnectionMap::const_iterator it = connections_.begin();
    168        it != connections_.end(); ++it) {
    169     if (it->second->addr_pair().destination() == address) {
    170       return true;
    171     }
    172   }
    173   return false;
    174 }
    175 
    176 void RelayServer::OnReadEvent(rtc::AsyncSocket* socket) {
    177   ASSERT(server_sockets_.find(socket) != server_sockets_.end());
    178   AcceptConnection(socket);
    179 }
    180 
    181 void RelayServer::OnInternalPacket(
    182     rtc::AsyncPacketSocket* socket, const char* bytes, size_t size,
    183     const rtc::SocketAddress& remote_addr,
    184     const rtc::PacketTime& packet_time) {
    185 
    186   // Get the address of the connection we just received on.
    187   rtc::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
    188   ASSERT(!ap.destination().IsNil());
    189 
    190   // If this did not come from an existing connection, it should be a STUN
    191   // allocate request.
    192   ConnectionMap::iterator piter = connections_.find(ap);
    193   if (piter == connections_.end()) {
    194     HandleStunAllocate(bytes, size, ap, socket);
    195     return;
    196   }
    197 
    198   RelayServerConnection* int_conn = piter->second;
    199 
    200   // Handle STUN requests to the server itself.
    201   if (int_conn->binding()->HasMagicCookie(bytes, size)) {
    202     HandleStun(int_conn, bytes, size);
    203     return;
    204   }
    205 
    206   // Otherwise, this is a non-wrapped packet that we are to forward.  Make sure
    207   // that this connection has been locked.  (Otherwise, we would not know what
    208   // address to forward to.)
    209   if (!int_conn->locked()) {
    210     LOG(LS_WARNING) << "Dropping packet: connection not locked";
    211     return;
    212   }
    213 
    214   // Forward this to the destination address into the connection.
    215   RelayServerConnection* ext_conn = int_conn->binding()->GetExternalConnection(
    216       int_conn->default_destination());
    217   if (ext_conn && ext_conn->locked()) {
    218     // TODO: Check the HMAC.
    219     ext_conn->Send(bytes, size);
    220   } else {
    221     // This happens very often and is not an error.
    222     LOG(LS_INFO) << "Dropping packet: no external connection";
    223   }
    224 }
    225 
    226 void RelayServer::OnExternalPacket(
    227     rtc::AsyncPacketSocket* socket, const char* bytes, size_t size,
    228     const rtc::SocketAddress& remote_addr,
    229     const rtc::PacketTime& packet_time) {
    230 
    231   // Get the address of the connection we just received on.
    232   rtc::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
    233   ASSERT(!ap.destination().IsNil());
    234 
    235   // If this connection already exists, then forward the traffic.
    236   ConnectionMap::iterator piter = connections_.find(ap);
    237   if (piter != connections_.end()) {
    238     // TODO: Check the HMAC.
    239     RelayServerConnection* ext_conn = piter->second;
    240     RelayServerConnection* int_conn =
    241         ext_conn->binding()->GetInternalConnection(
    242             ext_conn->addr_pair().source());
    243     ASSERT(int_conn != NULL);
    244     int_conn->Send(bytes, size, ext_conn->addr_pair().source());
    245     ext_conn->Lock();  // allow outgoing packets
    246     return;
    247   }
    248 
    249   // The first packet should always be a STUN / TURN packet.  If it isn't, then
    250   // we should just ignore this packet.
    251   RelayMessage msg;
    252   rtc::ByteBuffer buf(bytes, size);
    253   if (!msg.Read(&buf)) {
    254     LOG(LS_WARNING) << "Dropping packet: first packet not STUN";
    255     return;
    256   }
    257 
    258   // The initial packet should have a username (which identifies the binding).
    259   const StunByteStringAttribute* username_attr =
    260       msg.GetByteString(STUN_ATTR_USERNAME);
    261   if (!username_attr) {
    262     LOG(LS_WARNING) << "Dropping packet: no username";
    263     return;
    264   }
    265 
    266   uint32_t length =
    267       std::min(static_cast<uint32_t>(username_attr->length()), USERNAME_LENGTH);
    268   std::string username(username_attr->bytes(), length);
    269   // TODO: Check the HMAC.
    270 
    271   // The binding should already be present.
    272   BindingMap::iterator biter = bindings_.find(username);
    273   if (biter == bindings_.end()) {
    274     LOG(LS_WARNING) << "Dropping packet: no binding with username";
    275     return;
    276   }
    277 
    278   // Add this authenticted connection to the binding.
    279   RelayServerConnection* ext_conn =
    280       new RelayServerConnection(biter->second, ap, socket);
    281   ext_conn->binding()->AddExternalConnection(ext_conn);
    282   AddConnection(ext_conn);
    283 
    284   // We always know where external packets should be forwarded, so we can lock
    285   // them from the beginning.
    286   ext_conn->Lock();
    287 
    288   // Send this message on the appropriate internal connection.
    289   RelayServerConnection* int_conn = ext_conn->binding()->GetInternalConnection(
    290       ext_conn->addr_pair().source());
    291   ASSERT(int_conn != NULL);
    292   int_conn->Send(bytes, size, ext_conn->addr_pair().source());
    293 }
    294 
    295 bool RelayServer::HandleStun(
    296     const char* bytes, size_t size, const rtc::SocketAddress& remote_addr,
    297     rtc::AsyncPacketSocket* socket, std::string* username,
    298     StunMessage* msg) {
    299 
    300   // Parse this into a stun message. Eat the message if this fails.
    301   rtc::ByteBuffer buf(bytes, size);
    302   if (!msg->Read(&buf)) {
    303     return false;
    304   }
    305 
    306   // The initial packet should have a username (which identifies the binding).
    307   const StunByteStringAttribute* username_attr =
    308       msg->GetByteString(STUN_ATTR_USERNAME);
    309   if (!username_attr) {
    310     SendStunError(*msg, socket, remote_addr, 432, "Missing Username", "");
    311     return false;
    312   }
    313 
    314   // Record the username if requested.
    315   if (username)
    316     username->append(username_attr->bytes(), username_attr->length());
    317 
    318   // TODO: Check for unknown attributes (<= 0x7fff)
    319 
    320   return true;
    321 }
    322 
    323 void RelayServer::HandleStunAllocate(
    324     const char* bytes, size_t size, const rtc::SocketAddressPair& ap,
    325     rtc::AsyncPacketSocket* socket) {
    326 
    327   // Make sure this is a valid STUN request.
    328   RelayMessage request;
    329   std::string username;
    330   if (!HandleStun(bytes, size, ap.source(), socket, &username, &request))
    331     return;
    332 
    333   // Make sure this is a an allocate request.
    334   if (request.type() != STUN_ALLOCATE_REQUEST) {
    335     SendStunError(request,
    336                   socket,
    337                   ap.source(),
    338                   600,
    339                   "Operation Not Supported",
    340                   "");
    341     return;
    342   }
    343 
    344   // TODO: Check the HMAC.
    345 
    346   // Find or create the binding for this username.
    347 
    348   RelayServerBinding* binding;
    349 
    350   BindingMap::iterator biter = bindings_.find(username);
    351   if (biter != bindings_.end()) {
    352     binding = biter->second;
    353   } else {
    354     // NOTE: In the future, bindings will be created by the bot only.  This
    355     //       else-branch will then disappear.
    356 
    357     // Compute the appropriate lifetime for this binding.
    358     uint32_t lifetime = MAX_LIFETIME;
    359     const StunUInt32Attribute* lifetime_attr =
    360         request.GetUInt32(STUN_ATTR_LIFETIME);
    361     if (lifetime_attr)
    362       lifetime = std::min(lifetime, lifetime_attr->value() * 1000);
    363 
    364     binding = new RelayServerBinding(this, username, "0", lifetime);
    365     binding->SignalTimeout.connect(this, &RelayServer::OnTimeout);
    366     bindings_[username] = binding;
    367 
    368     if (log_bindings_) {
    369       LOG(LS_INFO) << "Added new binding " << username << ", "
    370                    << bindings_.size() << " total";
    371     }
    372   }
    373 
    374   // Add this connection to the binding.  It starts out unlocked.
    375   RelayServerConnection* int_conn =
    376       new RelayServerConnection(binding, ap, socket);
    377   binding->AddInternalConnection(int_conn);
    378   AddConnection(int_conn);
    379 
    380   // Now that we have a connection, this other method takes over.
    381   HandleStunAllocate(int_conn, request);
    382 }
    383 
    384 void RelayServer::HandleStun(
    385     RelayServerConnection* int_conn, const char* bytes, size_t size) {
    386 
    387   // Make sure this is a valid STUN request.
    388   RelayMessage request;
    389   std::string username;
    390   if (!HandleStun(bytes, size, int_conn->addr_pair().source(),
    391                   int_conn->socket(), &username, &request))
    392     return;
    393 
    394   // Make sure the username is the one were were expecting.
    395   if (username != int_conn->binding()->username()) {
    396     int_conn->SendStunError(request, 430, "Stale Credentials");
    397     return;
    398   }
    399 
    400   // TODO: Check the HMAC.
    401 
    402   // Send this request to the appropriate handler.
    403   if (request.type() == STUN_SEND_REQUEST)
    404     HandleStunSend(int_conn, request);
    405   else if (request.type() == STUN_ALLOCATE_REQUEST)
    406     HandleStunAllocate(int_conn, request);
    407   else
    408     int_conn->SendStunError(request, 600, "Operation Not Supported");
    409 }
    410 
    411 void RelayServer::HandleStunAllocate(
    412     RelayServerConnection* int_conn, const StunMessage& request) {
    413 
    414   // Create a response message that includes an address with which external
    415   // clients can communicate.
    416 
    417   RelayMessage response;
    418   response.SetType(STUN_ALLOCATE_RESPONSE);
    419   response.SetTransactionID(request.transaction_id());
    420 
    421   StunByteStringAttribute* magic_cookie_attr =
    422       StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
    423   magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
    424                                int_conn->binding()->magic_cookie().size());
    425   response.AddAttribute(magic_cookie_attr);
    426 
    427   size_t index = rand() % external_sockets_.size();
    428   rtc::SocketAddress ext_addr =
    429       external_sockets_[index]->GetLocalAddress();
    430 
    431   StunAddressAttribute* addr_attr =
    432       StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
    433   addr_attr->SetIP(ext_addr.ipaddr());
    434   addr_attr->SetPort(ext_addr.port());
    435   response.AddAttribute(addr_attr);
    436 
    437   StunUInt32Attribute* res_lifetime_attr =
    438       StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
    439   res_lifetime_attr->SetValue(int_conn->binding()->lifetime() / 1000);
    440   response.AddAttribute(res_lifetime_attr);
    441 
    442   // TODO: Support transport-prefs (preallocate RTCP port).
    443   // TODO: Support bandwidth restrictions.
    444   // TODO: Add message integrity check.
    445 
    446   // Send a response to the caller.
    447   int_conn->SendStun(response);
    448 }
    449 
    450 void RelayServer::HandleStunSend(
    451     RelayServerConnection* int_conn, const StunMessage& request) {
    452 
    453   const StunAddressAttribute* addr_attr =
    454       request.GetAddress(STUN_ATTR_DESTINATION_ADDRESS);
    455   if (!addr_attr) {
    456     int_conn->SendStunError(request, 400, "Bad Request");
    457     return;
    458   }
    459 
    460   const StunByteStringAttribute* data_attr =
    461       request.GetByteString(STUN_ATTR_DATA);
    462   if (!data_attr) {
    463     int_conn->SendStunError(request, 400, "Bad Request");
    464     return;
    465   }
    466 
    467   rtc::SocketAddress ext_addr(addr_attr->ipaddr(), addr_attr->port());
    468   RelayServerConnection* ext_conn =
    469       int_conn->binding()->GetExternalConnection(ext_addr);
    470   if (!ext_conn) {
    471     // Create a new connection to establish the relationship with this binding.
    472     ASSERT(external_sockets_.size() == 1);
    473     rtc::AsyncPacketSocket* socket = external_sockets_[0];
    474     rtc::SocketAddressPair ap(ext_addr, socket->GetLocalAddress());
    475     ext_conn = new RelayServerConnection(int_conn->binding(), ap, socket);
    476     ext_conn->binding()->AddExternalConnection(ext_conn);
    477     AddConnection(ext_conn);
    478   }
    479 
    480   // If this connection has pinged us, then allow outgoing traffic.
    481   if (ext_conn->locked())
    482     ext_conn->Send(data_attr->bytes(), data_attr->length());
    483 
    484   const StunUInt32Attribute* options_attr =
    485       request.GetUInt32(STUN_ATTR_OPTIONS);
    486   if (options_attr && (options_attr->value() & 0x01)) {
    487     int_conn->set_default_destination(ext_addr);
    488     int_conn->Lock();
    489 
    490     RelayMessage response;
    491     response.SetType(STUN_SEND_RESPONSE);
    492     response.SetTransactionID(request.transaction_id());
    493 
    494     StunByteStringAttribute* magic_cookie_attr =
    495         StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
    496     magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
    497                                  int_conn->binding()->magic_cookie().size());
    498     response.AddAttribute(magic_cookie_attr);
    499 
    500     StunUInt32Attribute* options2_attr =
    501       StunAttribute::CreateUInt32(cricket::STUN_ATTR_OPTIONS);
    502     options2_attr->SetValue(0x01);
    503     response.AddAttribute(options2_attr);
    504 
    505     int_conn->SendStun(response);
    506   }
    507 }
    508 
    509 void RelayServer::AddConnection(RelayServerConnection* conn) {
    510   ASSERT(connections_.find(conn->addr_pair()) == connections_.end());
    511   connections_[conn->addr_pair()] = conn;
    512 }
    513 
    514 void RelayServer::RemoveConnection(RelayServerConnection* conn) {
    515   ConnectionMap::iterator iter = connections_.find(conn->addr_pair());
    516   ASSERT(iter != connections_.end());
    517   connections_.erase(iter);
    518 }
    519 
    520 void RelayServer::RemoveBinding(RelayServerBinding* binding) {
    521   BindingMap::iterator iter = bindings_.find(binding->username());
    522   ASSERT(iter != bindings_.end());
    523   bindings_.erase(iter);
    524 
    525   if (log_bindings_) {
    526     LOG(LS_INFO) << "Removed binding " << binding->username() << ", "
    527                  << bindings_.size() << " remaining";
    528   }
    529 }
    530 
    531 void RelayServer::OnMessage(rtc::Message *pmsg) {
    532 #if ENABLE_DEBUG
    533   static const uint32_t kMessageAcceptConnection = 1;
    534   ASSERT(pmsg->message_id == kMessageAcceptConnection);
    535 #endif
    536   rtc::MessageData* data = pmsg->pdata;
    537   rtc::AsyncSocket* socket =
    538       static_cast <rtc::TypedMessageData<rtc::AsyncSocket*>*>
    539       (data)->data();
    540   AcceptConnection(socket);
    541   delete data;
    542 }
    543 
    544 void RelayServer::OnTimeout(RelayServerBinding* binding) {
    545   // This call will result in all of the necessary clean-up. We can't call
    546   // delete here, because you can't delete an object that is signaling you.
    547   thread_->Dispose(binding);
    548 }
    549 
    550 void RelayServer::AcceptConnection(rtc::AsyncSocket* server_socket) {
    551   // Check if someone is trying to connect to us.
    552   rtc::SocketAddress accept_addr;
    553   rtc::AsyncSocket* accepted_socket =
    554       server_socket->Accept(&accept_addr);
    555   if (accepted_socket != NULL) {
    556     // We had someone trying to connect, now check which protocol to
    557     // use and create a packet socket.
    558     ASSERT(server_sockets_[server_socket] == cricket::PROTO_TCP ||
    559            server_sockets_[server_socket] == cricket::PROTO_SSLTCP);
    560     if (server_sockets_[server_socket] == cricket::PROTO_SSLTCP) {
    561       accepted_socket = new rtc::AsyncSSLServerSocket(accepted_socket);
    562     }
    563     rtc::AsyncTCPSocket* tcp_socket =
    564         new rtc::AsyncTCPSocket(accepted_socket, false);
    565 
    566     // Finally add the socket so it can start communicating with the client.
    567     AddInternalSocket(tcp_socket);
    568   }
    569 }
    570 
    571 RelayServerConnection::RelayServerConnection(
    572     RelayServerBinding* binding, const rtc::SocketAddressPair& addrs,
    573     rtc::AsyncPacketSocket* socket)
    574   : binding_(binding), addr_pair_(addrs), socket_(socket), locked_(false) {
    575   // The creation of a new connection constitutes a use of the binding.
    576   binding_->NoteUsed();
    577 }
    578 
    579 RelayServerConnection::~RelayServerConnection() {
    580   // Remove this connection from the server's map (if it exists there).
    581   binding_->server()->RemoveConnection(this);
    582 }
    583 
    584 void RelayServerConnection::Send(const char* data, size_t size) {
    585   // Note that the binding has been used again.
    586   binding_->NoteUsed();
    587 
    588   cricket::Send(socket_, data, size, addr_pair_.source());
    589 }
    590 
    591 void RelayServerConnection::Send(
    592     const char* data, size_t size, const rtc::SocketAddress& from_addr) {
    593   // If the from address is known to the client, we don't need to send it.
    594   if (locked() && (from_addr == default_dest_)) {
    595     Send(data, size);
    596     return;
    597   }
    598 
    599   // Wrap the given data in a data-indication packet.
    600 
    601   RelayMessage msg;
    602   msg.SetType(STUN_DATA_INDICATION);
    603 
    604   StunByteStringAttribute* magic_cookie_attr =
    605       StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
    606   magic_cookie_attr->CopyBytes(binding_->magic_cookie().c_str(),
    607                                binding_->magic_cookie().size());
    608   msg.AddAttribute(magic_cookie_attr);
    609 
    610   StunAddressAttribute* addr_attr =
    611       StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
    612   addr_attr->SetIP(from_addr.ipaddr());
    613   addr_attr->SetPort(from_addr.port());
    614   msg.AddAttribute(addr_attr);
    615 
    616   StunByteStringAttribute* data_attr =
    617       StunAttribute::CreateByteString(STUN_ATTR_DATA);
    618   ASSERT(size <= 65536);
    619   data_attr->CopyBytes(data, uint16_t(size));
    620   msg.AddAttribute(data_attr);
    621 
    622   SendStun(msg);
    623 }
    624 
    625 void RelayServerConnection::SendStun(const StunMessage& msg) {
    626   // Note that the binding has been used again.
    627   binding_->NoteUsed();
    628 
    629   cricket::SendStun(msg, socket_, addr_pair_.source());
    630 }
    631 
    632 void RelayServerConnection::SendStunError(
    633       const StunMessage& request, int error_code, const char* error_desc) {
    634   // An error does not indicate use.  If no legitimate use off the binding
    635   // occurs, we want it to be cleaned up even if errors are still occuring.
    636 
    637   cricket::SendStunError(
    638       request, socket_, addr_pair_.source(), error_code, error_desc,
    639       binding_->magic_cookie());
    640 }
    641 
    642 void RelayServerConnection::Lock() {
    643   locked_ = true;
    644 }
    645 
    646 void RelayServerConnection::Unlock() {
    647   locked_ = false;
    648 }
    649 
    650 // IDs used for posted messages:
    651 const uint32_t MSG_LIFETIME_TIMER = 1;
    652 
    653 RelayServerBinding::RelayServerBinding(RelayServer* server,
    654                                        const std::string& username,
    655                                        const std::string& password,
    656                                        uint32_t lifetime)
    657     : server_(server),
    658       username_(username),
    659       password_(password),
    660       lifetime_(lifetime) {
    661   // For now, every connection uses the standard magic cookie value.
    662   magic_cookie_.append(
    663       reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE),
    664       sizeof(TURN_MAGIC_COOKIE_VALUE));
    665 
    666   // Initialize the last-used time to now.
    667   NoteUsed();
    668 
    669   // Set the first timeout check.
    670   server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER);
    671 }
    672 
    673 RelayServerBinding::~RelayServerBinding() {
    674   // Clear the outstanding timeout check.
    675   server_->thread()->Clear(this);
    676 
    677   // Clean up all of the connections.
    678   for (size_t i = 0; i < internal_connections_.size(); ++i)
    679     delete internal_connections_[i];
    680   for (size_t i = 0; i < external_connections_.size(); ++i)
    681     delete external_connections_[i];
    682 
    683   // Remove this binding from the server's map.
    684   server_->RemoveBinding(this);
    685 }
    686 
    687 void RelayServerBinding::AddInternalConnection(RelayServerConnection* conn) {
    688   internal_connections_.push_back(conn);
    689 }
    690 
    691 void RelayServerBinding::AddExternalConnection(RelayServerConnection* conn) {
    692   external_connections_.push_back(conn);
    693 }
    694 
    695 void RelayServerBinding::NoteUsed() {
    696   last_used_ = rtc::Time();
    697 }
    698 
    699 bool RelayServerBinding::HasMagicCookie(const char* bytes, size_t size) const {
    700   if (size < 24 + magic_cookie_.size()) {
    701     return false;
    702   } else {
    703     return memcmp(bytes + 24, magic_cookie_.c_str(), magic_cookie_.size()) == 0;
    704   }
    705 }
    706 
    707 RelayServerConnection* RelayServerBinding::GetInternalConnection(
    708     const rtc::SocketAddress& ext_addr) {
    709 
    710   // Look for an internal connection that is locked to this address.
    711   for (size_t i = 0; i < internal_connections_.size(); ++i) {
    712     if (internal_connections_[i]->locked() &&
    713         (ext_addr == internal_connections_[i]->default_destination()))
    714       return internal_connections_[i];
    715   }
    716 
    717   // If one was not found, we send to the first connection.
    718   ASSERT(internal_connections_.size() > 0);
    719   return internal_connections_[0];
    720 }
    721 
    722 RelayServerConnection* RelayServerBinding::GetExternalConnection(
    723     const rtc::SocketAddress& ext_addr) {
    724   for (size_t i = 0; i < external_connections_.size(); ++i) {
    725     if (ext_addr == external_connections_[i]->addr_pair().source())
    726       return external_connections_[i];
    727   }
    728   return 0;
    729 }
    730 
    731 void RelayServerBinding::OnMessage(rtc::Message *pmsg) {
    732   if (pmsg->message_id == MSG_LIFETIME_TIMER) {
    733     ASSERT(!pmsg->pdata);
    734 
    735     // If the lifetime timeout has been exceeded, then send a signal.
    736     // Otherwise, just keep waiting.
    737     if (rtc::Time() >= last_used_ + lifetime_) {
    738       LOG(LS_INFO) << "Expiring binding " << username_;
    739       SignalTimeout(this);
    740     } else {
    741       server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER);
    742     }
    743 
    744   } else {
    745     ASSERT(false);
    746   }
    747 }
    748 
    749 }  // namespace cricket
    750