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
24namespace cricket {
25
26// By default, we require a ping every 90 seconds.
27const int MAX_LIFETIME = 15 * 60 * 1000;
28
29// The number of bytes in each of the usernames we use.
30const uint32_t USERNAME_LENGTH = 16;
31
32// Calls SendTo on the given socket and logs any bad results.
33void 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.
46void 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.
55void 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
81RelayServer::RelayServer(rtc::Thread* thread)
82  : thread_(thread), log_bindings_(true) {
83}
84
85RelayServer::~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
102void 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
109void 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
118void 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
125void 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
134void 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
142void 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
150int RelayServer::GetConnectionCount() const {
151  return static_cast<int>(connections_.size());
152}
153
154rtc::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
166bool 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
176void RelayServer::OnReadEvent(rtc::AsyncSocket* socket) {
177  ASSERT(server_sockets_.find(socket) != server_sockets_.end());
178  AcceptConnection(socket);
179}
180
181void 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
226void 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
295bool 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
323void 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
384void 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
411void 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
450void 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
509void RelayServer::AddConnection(RelayServerConnection* conn) {
510  ASSERT(connections_.find(conn->addr_pair()) == connections_.end());
511  connections_[conn->addr_pair()] = conn;
512}
513
514void RelayServer::RemoveConnection(RelayServerConnection* conn) {
515  ConnectionMap::iterator iter = connections_.find(conn->addr_pair());
516  ASSERT(iter != connections_.end());
517  connections_.erase(iter);
518}
519
520void 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
531void 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
544void 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
550void 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
571RelayServerConnection::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
579RelayServerConnection::~RelayServerConnection() {
580  // Remove this connection from the server's map (if it exists there).
581  binding_->server()->RemoveConnection(this);
582}
583
584void 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
591void 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
625void 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
632void 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
642void RelayServerConnection::Lock() {
643  locked_ = true;
644}
645
646void RelayServerConnection::Unlock() {
647  locked_ = false;
648}
649
650// IDs used for posted messages:
651const uint32_t MSG_LIFETIME_TIMER = 1;
652
653RelayServerBinding::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
673RelayServerBinding::~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
687void RelayServerBinding::AddInternalConnection(RelayServerConnection* conn) {
688  internal_connections_.push_back(conn);
689}
690
691void RelayServerBinding::AddExternalConnection(RelayServerConnection* conn) {
692  external_connections_.push_back(conn);
693}
694
695void RelayServerBinding::NoteUsed() {
696  last_used_ = rtc::Time();
697}
698
699bool 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
707RelayServerConnection* 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
722RelayServerConnection* 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
731void 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