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