⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 relayserver.cxx

📁 由GOOGLE的JINGLE项目中移植的网络库
💻 CXX
📖 第 1 页 / 共 2 页
字号:
/* * libjingle * Copyright 2004--2005, Google Inc. * * Redistribution and use in source and binary forms, with or without  * modification, are permitted provided that the following conditions are met: * *  1. Redistributions of source code must retain the above copyright notice,  *     this list of conditions and the following disclaimer. *  2. Redistributions in binary form must reproduce the above copyright notice, *     this list of conditions and the following disclaimer in the documentation *     and/or other materials provided with the distribution. *  3. The name of the author may not be used to endorse or promote products  *     derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#if defined(_MSC_VER) && _MSC_VER < 1300
#pragma warning(disable:4786)
#endif
#include "relayserver.h"#include "helpers.h"#include <algorithm>#include <cassert>#include <cstring>namespace cricket {// By default, we require a ping every 90 seconds.const int MAX_LIFETIME = 15 * 60 * 1000;// The number of bytes in each of the usernames we use.const uint32 USERNAME_LENGTH = 16;// Calls SendTo on the given socket and logs any bad results.void Send(AsyncPacketSocket* socket, const char* bytes, size_t size,          const SocketAddress& addr) {  int result = socket->SendTo(bytes, size, addr);  if (result < int(size)) {    /// std::cerr << "SendTo wrote only " << result << " of " << int(size)      ///        << " bytes" << std::endl;  } else if (result < 0) {    /// std::cerr << "SendTo: " << std::strerror(errno) << std::endl;  }}// Sends the given STUN message on the given socket.void SendStun(const StunMessage& msg,              AsyncPacketSocket* socket,              const SocketAddress& addr) {  ByteBuffer buf;  msg.Write(&buf);  Send(socket, buf.Data(), buf.Length(), addr);}// Constructs a STUN error response and sends it on the given socket.void SendStunError(const StunMessage& msg, AsyncPacketSocket* socket,                   const SocketAddress& remote_addr, int error_code,                   const char* error_desc, const std::string& magic_cookie) {  StunMessage err_msg;  err_msg.SetType(GetStunErrorResponseType(msg.type()));  err_msg.SetTransactionID(msg.transaction_id());  StunByteStringAttribute* magic_cookie_attr =      StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);  if (magic_cookie.size() == 0)    magic_cookie_attr->CopyBytes(cricket::STUN_MAGIC_COOKIE_VALUE, 4);  else    magic_cookie_attr->CopyBytes(magic_cookie.c_str(), magic_cookie.size());  err_msg.AddAttribute(magic_cookie_attr);  StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();  err_code->SetErrorClass(error_code / 100);  err_code->SetNumber(error_code % 100);  err_code->SetReason(error_desc);  err_msg.AddAttribute(err_code);  SendStun(err_msg, socket, remote_addr);}RelayServer::RelayServer(Thread* thread) : thread_(thread) {}RelayServer::~RelayServer() {
	unsigned i;  for (i = 0; i < internal_sockets_.size(); i++)    delete internal_sockets_[i];  for (i = 0; i < external_sockets_.size(); i++)    delete external_sockets_[i];}void RelayServer::AddInternalSocket(AsyncPacketSocket* socket) {  assert(internal_sockets_.end() ==      std::find(internal_sockets_.begin(), internal_sockets_.end(), socket));  internal_sockets_.push_back(socket);  socket->SignalReadPacket.connect(this, &RelayServer::OnInternalPacket);}void RelayServer::RemoveInternalSocket(AsyncPacketSocket* socket) {  SocketList::iterator iter =      std::find(internal_sockets_.begin(), internal_sockets_.end(), socket);  assert(iter != internal_sockets_.end());  internal_sockets_.erase(iter);  socket->SignalReadPacket.disconnect(this);}void RelayServer::AddExternalSocket(AsyncPacketSocket* socket) {  assert(external_sockets_.end() ==      std::find(external_sockets_.begin(), external_sockets_.end(), socket));  external_sockets_.push_back(socket);  socket->SignalReadPacket.connect(this, &RelayServer::OnExternalPacket);}void RelayServer::RemoveExternalSocket(AsyncPacketSocket* socket) {  SocketList::iterator iter =      std::find(external_sockets_.begin(), external_sockets_.end(), socket);  assert(iter != external_sockets_.end());  external_sockets_.erase(iter);  socket->SignalReadPacket.disconnect(this);}void RelayServer::OnInternalPacket(    const char* bytes, size_t size, const SocketAddress& remote_addr,    AsyncPacketSocket* socket) {  // Get the address of the connection we just received on.  SocketAddressPair ap(remote_addr, socket->GetLocalAddress());  assert(!ap.destination().IsAny());  // If this did not come from an existing connection, it should be a STUN  // allocate request.  ConnectionMap::iterator piter = connections_.find(ap);  if (piter == connections_.end()) {    HandleStunAllocate(bytes, size, ap, socket);    return;  }  RelayServerConnection* int_conn = piter->second;  // Handle STUN requests to the server itself.  if (int_conn->binding()->HasMagicCookie(bytes, size)) {    HandleStun(int_conn, bytes, size);    return;  }  // Otherwise, this is a non-wrapped packet that we are to forward.  Make sure  // that this connection has been locked.  (Otherwise, we would not know what  // address to forward to.)  if (!int_conn->locked()) {///    std::cerr << "Dropping packet: connection not locked" << std::endl;    return;  }  // Forward this to the destination address into the connection.  RelayServerConnection* ext_conn = int_conn->binding()->GetExternalConnection(      int_conn->default_destination());  if (ext_conn) {    // TODO: Check the HMAC.    ext_conn->Send(bytes, size);  } else {    // This happens very often and is not an error.    //std::cerr << "Dropping packet: no external connection" << std::endl;  }}void RelayServer::OnExternalPacket(    const char* bytes, size_t size, const SocketAddress& remote_addr,    AsyncPacketSocket* socket) {  // Get the address of the connection we just received on.  SocketAddressPair ap(remote_addr, socket->GetLocalAddress());  assert(!ap.destination().IsAny());  // If this connection already exists, then forward the traffic.  ConnectionMap::iterator piter = connections_.find(ap);  if (piter != connections_.end()) {    // TODO: Check the HMAC.    RelayServerConnection* ext_conn = piter->second;    RelayServerConnection* int_conn =        ext_conn->binding()->GetInternalConnection(            ext_conn->addr_pair().source());    assert(int_conn);    int_conn->Send(bytes, size, ext_conn->addr_pair().source());    return;  }  // The first packet should always be a STUN / TURN packet.  If it isn't, then  // we should just ignore this packet.  StunMessage msg;  ByteBuffer buf = ByteBuffer(bytes, size);  if (!msg.Read(&buf)) {///    std::cerr << "Dropping packet: first packet not STUN" << std::endl;    return;  }  // The initial packet should have a username (which identifies the binding).  const StunByteStringAttribute* username_attr =      msg.GetByteString(STUN_ATTR_USERNAME);  if (!username_attr) {///    std::cerr << "Dropping packet: no username" << std::endl;    return;  }  uint32 length = _min(uint32(username_attr->length()), USERNAME_LENGTH);  std::string username(username_attr->bytes(), length);  // TODO: Check the HMAC.  // The binding should already be present.  BindingMap::iterator biter = bindings_.find(username);  if (biter == bindings_.end()) {    // TODO: Turn this back on.  This is the sign of a client bug.    //std::cerr << "Dropping packet: no binding with username" << std::endl;    return;  }  // Add this authenticted connection to the binding.  RelayServerConnection* ext_conn =      new RelayServerConnection(biter->second, ap, socket);  ext_conn->binding()->AddExternalConnection(ext_conn);  AddConnection(ext_conn);  // We always know where external packets should be forwarded, so we can lock  // them from the beginning.  ext_conn->Lock();  // Send this message on the appropriate internal connection.  RelayServerConnection* int_conn = ext_conn->binding()->GetInternalConnection(      ext_conn->addr_pair().source());  assert(int_conn);  int_conn->Send(bytes, size, ext_conn->addr_pair().source());}bool RelayServer::HandleStun(    const char* bytes, size_t size, const SocketAddress& remote_addr,    AsyncPacketSocket* socket, std::string* username, StunMessage* msg) {  // Parse this into a stun message.  ByteBuffer buf = ByteBuffer(bytes, size);  if (!msg->Read(&buf)) {    SendStunError(*msg, socket, remote_addr, 400, "Bad Request", "");    return false;  }  // The initial packet should have a username (which identifies the binding).  const StunByteStringAttribute* username_attr =      msg->GetByteString(STUN_ATTR_USERNAME);  if (!username_attr) {    SendStunError(*msg, socket, remote_addr, 432, "Missing Username", "");    return false;  }  // Record the username if requested.  if (username)    username->append(username_attr->bytes(), username_attr->length());  // TODO: Check for unknown attributes (<= 0x7fff)  return true;}void RelayServer::HandleStunAllocate(    const char* bytes, size_t size, const SocketAddressPair& ap,    AsyncPacketSocket* socket) {  // Make sure this is a valid STUN request.  StunMessage request;  std::string username;  if (!HandleStun(bytes, size, ap.source(), socket, &username, &request))    return;  // Make sure this is a an allocate request.  if (request.type() != STUN_ALLOCATE_REQUEST) {    SendStunError(request,                  socket,                  ap.source(),                  600,                  "Operation Not Supported",                  "");    return;  }  // TODO: Check the HMAC.  // Find or create the binding for this username.  RelayServerBinding* binding;  BindingMap::iterator biter = bindings_.find(username);  if (biter != bindings_.end()) {    binding = biter->second;  } else {    // NOTE: In the future, bindings will be created by the bot only.  This    //       else-branch will then disappear.    // Compute the appropriate lifetime for this binding.    uint32 lifetime = MAX_LIFETIME;    const StunUInt32Attribute* lifetime_attr =        request.GetUInt32(STUN_ATTR_LIFETIME);    if (lifetime_attr)      lifetime = _min(lifetime, lifetime_attr->value() * 1000);    binding = new RelayServerBinding(this, username, "0", lifetime);    binding->SignalTimeout.connect(this, &RelayServer::OnTimeout);    bindings_[username] = binding;///    std::cout << "Added new binding: " << bindings_.size() << " total" << std::endl;  }  // Add this connection to the binding.  It starts out unlocked.  RelayServerConnection* int_conn =      new RelayServerConnection(binding, ap, socket);  binding->AddInternalConnection(int_conn);  AddConnection(int_conn);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -