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