📄 relayserver.cxx
字号:
// Now that we have a connection, this other method takes over. HandleStunAllocate(int_conn, request);}void RelayServer::HandleStun( RelayServerConnection* int_conn, const char* bytes, size_t size) { // Make sure this is a valid STUN request. StunMessage request; std::string username; if (!HandleStun(bytes, size, int_conn->addr_pair().source(), int_conn->socket(), &username, &request)) return; // Make sure the username is the one were were expecting. if (username != int_conn->binding()->username()) { int_conn->SendStunError(request, 430, "Stale Credentials"); return; } // TODO: Check the HMAC. // Send this request to the appropriate handler. if (request.type() == STUN_SEND_REQUEST) HandleStunSend(int_conn, request); else if (request.type() == STUN_ALLOCATE_REQUEST) HandleStunAllocate(int_conn, request); else int_conn->SendStunError(request, 600, "Operation Not Supported");}void RelayServer::HandleStunAllocate( RelayServerConnection* int_conn, const StunMessage& request) { // Create a response message that includes an address with which external // clients can communicate. StunMessage response; response.SetType(STUN_ALLOCATE_RESPONSE); response.SetTransactionID(request.transaction_id()); StunByteStringAttribute* magic_cookie_attr = StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE); magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(), int_conn->binding()->magic_cookie().size()); response.AddAttribute(magic_cookie_attr); size_t index = rand() % external_sockets_.size(); SocketAddress ext_addr = external_sockets_[index]->GetLocalAddress(); StunAddressAttribute* addr_attr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); addr_attr->SetFamily(1); addr_attr->SetIP(ext_addr.ip()); addr_attr->SetPort(ext_addr.port()); response.AddAttribute(addr_attr); StunUInt32Attribute* res_lifetime_attr = StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME); res_lifetime_attr->SetValue(int_conn->binding()->lifetime() / 1000); response.AddAttribute(res_lifetime_attr); // TODO: Support transport-prefs (preallocate RTCP port). // TODO: Support bandwidth restrictions. // TODO: Add message integrity check. // Send a response to the caller. int_conn->SendStun(response);}void RelayServer::HandleStunSend( RelayServerConnection* int_conn, const StunMessage& request) { const StunAddressAttribute* addr_attr = request.GetAddress(STUN_ATTR_DESTINATION_ADDRESS); if (!addr_attr) { int_conn->SendStunError(request, 400, "Bad Request"); return; } const StunByteStringAttribute* data_attr = request.GetByteString(STUN_ATTR_DATA); if (!data_attr) { int_conn->SendStunError(request, 400, "Bad Request"); return; } SocketAddress ext_addr(addr_attr->ip(), addr_attr->port()); RelayServerConnection* ext_conn = int_conn->binding()->GetExternalConnection(ext_addr); if (!ext_conn) { // This happens very often and is not an error. //std::cerr << "Dropping packet: no external connection" << std::endl; return; } ext_conn->Send(data_attr->bytes(), data_attr->length()); const StunUInt32Attribute* options_attr = request.GetUInt32(STUN_ATTR_OPTIONS); if (options_attr && (options_attr->value() & 0x01 != 0)) { int_conn->set_default_destination(ext_addr); int_conn->Lock(); StunMessage response; response.SetType(STUN_SEND_RESPONSE); response.SetTransactionID(request.transaction_id()); StunByteStringAttribute* magic_cookie_attr = StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE); magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(), int_conn->binding()->magic_cookie().size()); response.AddAttribute(magic_cookie_attr); StunUInt32Attribute* options2_attr = StunAttribute::CreateUInt32(cricket::STUN_ATTR_OPTIONS); options2_attr->SetValue(0x01); response.AddAttribute(options2_attr); int_conn->SendStun(response); }}void RelayServer::AddConnection(RelayServerConnection* conn) { assert(connections_.find(conn->addr_pair()) == connections_.end()); connections_[conn->addr_pair()] = conn;}void RelayServer::RemoveConnection(RelayServerConnection* conn) { ConnectionMap::iterator iter = connections_.find(conn->addr_pair()); assert(iter != connections_.end()); connections_.erase(iter);}void RelayServer::RemoveBinding(RelayServerBinding* binding) { BindingMap::iterator iter = bindings_.find(binding->username()); assert(iter != bindings_.end()); bindings_.erase(iter);/// std::cout << "Removed a binding: " << bindings_.size() << " remaining" << std::endl;}void RelayServer::OnTimeout(RelayServerBinding* binding) { // This call will result in all of the necessary clean-up. delete binding;}RelayServerConnection::RelayServerConnection( RelayServerBinding* binding, const SocketAddressPair& addrs, AsyncPacketSocket* socket) : binding_(binding), addr_pair_(addrs), socket_(socket), locked_(false) { // The creation of a new connection constitutes a use of the binding. binding_->NoteUsed();}RelayServerConnection::~RelayServerConnection() { // Remove this connection from the server's map (if it exists there). binding_->server()->RemoveConnection(this);}void RelayServerConnection::Send(const char* data, size_t size) { // Note that the binding has been used again. binding_->NoteUsed(); cricket::Send(socket_, data, size, addr_pair_.source());}void RelayServerConnection::Send( const char* data, size_t size, const SocketAddress& from_addr) { // If the from address is known to the client, we don't need to send it. if (locked() && (from_addr == default_dest_)) { Send(data, size); return; } // Wrap the given data in a data-indication packet. StunMessage msg; msg.SetType(STUN_DATA_INDICATION); msg.SetTransactionID("0000000000000000"); StunByteStringAttribute* magic_cookie_attr = StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE); magic_cookie_attr->CopyBytes(binding_->magic_cookie().c_str(), binding_->magic_cookie().size()); msg.AddAttribute(magic_cookie_attr); StunAddressAttribute* addr_attr = StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2); addr_attr->SetFamily(1); addr_attr->SetIP(from_addr.ip()); addr_attr->SetPort(from_addr.port()); msg.AddAttribute(addr_attr); StunByteStringAttribute* data_attr = StunAttribute::CreateByteString(STUN_ATTR_DATA); assert(size <= 65536); data_attr->CopyBytes(data, uint16(size)); msg.AddAttribute(data_attr); SendStun(msg);}void RelayServerConnection::SendStun(const StunMessage& msg) { // Note that the binding has been used again. binding_->NoteUsed(); cricket::SendStun(msg, socket_, addr_pair_.source());}void RelayServerConnection::SendStunError( const StunMessage& request, int error_code, const char* error_desc) { // An error does not indicate use. If no legitimate use off the binding // occurs, we want it to be cleaned up even if errors are still occuring. cricket::SendStunError( request, socket_, addr_pair_.source(), error_code, error_desc, binding_->magic_cookie());}void RelayServerConnection::Lock() { locked_ = true;}void RelayServerConnection::Unlock() { locked_ = false;}// IDs used for posted messages:const uint32 MSG_LIFETIME_TIMER = 1;RelayServerBinding::RelayServerBinding( RelayServer* server, const std::string& username, const std::string& password, uint32 lifetime) : server_(server), username_(username), password_(password), lifetime_(lifetime) { // For now, every connection uses the standard magic cookie value. magic_cookie_.append( reinterpret_cast<const char*>(STUN_MAGIC_COOKIE_VALUE), 4); // Initialize the last-used time to now. NoteUsed(); // Set the first timeout check. server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER);}RelayServerBinding::~RelayServerBinding() { // Clear the outstanding timeout check. server_->thread()->Clear(this);
size_t i; // Clean up all of the connections. for (i = 0; i < internal_connections_.size(); ++i) delete internal_connections_[i]; for (i = 0; i < external_connections_.size(); ++i) delete external_connections_[i]; // Remove this binding from the server's map. server_->RemoveBinding(this);}void RelayServerBinding::AddInternalConnection(RelayServerConnection* conn) { internal_connections_.push_back(conn);}void RelayServerBinding::AddExternalConnection(RelayServerConnection* conn) { external_connections_.push_back(conn);}void RelayServerBinding::NoteUsed() { last_used_ = GetMillisecondCount();}bool RelayServerBinding::HasMagicCookie(const char* bytes, size_t size) const { if (size < 24 + magic_cookie_.size()) { return false; } else { return 0 == memcmp( bytes + 24, magic_cookie_.c_str(), magic_cookie_.size()); }}RelayServerConnection* RelayServerBinding::GetInternalConnection( const SocketAddress& ext_addr) { // Look for an internal connection that is locked to this address. for (size_t i = 0; i < internal_connections_.size(); ++i) { if (internal_connections_[i]->locked() && (ext_addr == internal_connections_[i]->default_destination())) return internal_connections_[i]; } // If one was not found, we send to the first connection. assert(internal_connections_.size() > 0); return internal_connections_[0];}RelayServerConnection* RelayServerBinding::GetExternalConnection( const SocketAddress& ext_addr) { for (size_t i = 0; i < external_connections_.size(); ++i) { if (ext_addr == external_connections_[i]->addr_pair().source()) return external_connections_[i]; } return 0;}void RelayServerBinding::OnMessage(Message *pmsg) { if (pmsg->message_id == MSG_LIFETIME_TIMER) { assert(!pmsg->pdata); // If the lifetime timeout has been exceeded, then send a signal. // Otherwise, just keep waiting. if (GetMillisecondCount() >= last_used_ + lifetime_) { SignalTimeout(this); } else { server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER); } } else { assert(false); }}} // namespace cricket
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -