diff options
Diffstat (limited to 'src/engine/shared/network_server.cpp')
| -rw-r--r-- | src/engine/shared/network_server.cpp | 568 |
1 files changed, 482 insertions, 86 deletions
diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp index e97a8eba..cc97981c 100644 --- a/src/engine/shared/network_server.cpp +++ b/src/engine/shared/network_server.cpp @@ -4,9 +4,48 @@ #include <engine/console.h> +#include "config.h" #include "netban.h" #include "network.h" - +#include <engine/external/md5/md5.h> +#include <engine/message.h> +#include <engine/shared/protocol.h> + +const int DummyMapCrc = 0x6c760ac4; +unsigned char g_aDummyMapData[] = { + 0x44, 0x41, 0x54, 0x41, 0x04, 0x00, 0x00, 0x00, 0x22, 0x01, 0x00, 0x00, + 0x14, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0xc3, 0x52, + 0xff, 0x7f, 0x00, 0x00, 0x20, 0x5c, 0xf6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x78, 0x9c, 0x63, 0x64, 0x60, 0x60, 0x60, 0x44, + 0xc2, 0x00, 0x00, 0x38, 0x00, 0x05 +}; + + +static SECURITY_TOKEN ToSecurityToken(const unsigned char *pData) +{ + return (int)pData[0] | (pData[1] << 8) | (pData[2] << 16) | (pData[3] << 24); +} bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int MaxClientsPerIP, int Flags) { @@ -29,12 +68,22 @@ bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int Ma m_MaxClientsPerIP = MaxClientsPerIP; + m_NumConAttempts = 0; + m_TimeNumConAttempts = time_get(); + + m_VConnHighLoad = false; + m_VConnNum = 0; + m_VConnFirst = 0; + + secure_random_fill(m_SecurityTokenSeed, sizeof(m_SecurityTokenSeed)); + for(int i = 0; i < NET_MAX_CLIENTS; i++) m_aSlots[i].m_Connection.Init(m_Socket, true); return true; } +/* int CNetServer::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser) { m_pfnNewClient = pfnNewClient; @@ -42,6 +91,16 @@ int CNetServer::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT p m_UserPtr = pUser; return 0; } +*/ + +int CNetServer::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_NEWCLIENT_NOAUTH pfnNewClientNoAuth, NETFUNC_DELCLIENT pfnDelClient, void *pUser) +{ + m_pfnNewClient = pfnNewClient; + m_pfnNewClientNoAuth = pfnNewClientNoAuth; + m_pfnDelClient = pfnDelClient; + m_UserPtr = pUser; + return 0; +} int CNetServer::Close() { @@ -69,22 +128,407 @@ int CNetServer::Drop(int ClientID, const char *pReason) int CNetServer::Update() { - int64 Now = time_get(); for(int i = 0; i < MaxClients(); i++) { m_aSlots[i].m_Connection.Update(); if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR) { - if(Now - m_aSlots[i].m_Connection.ConnectTime() < time_freq()/2 && NetBan()) - NetBan()->BanAddr(ClientAddr(i), 60, "Stressing network"); - else - Drop(i, m_aSlots[i].m_Connection.ErrorString()); + Drop(i, m_aSlots[i].m_Connection.ErrorString()); } } return 0; } +SECURITY_TOKEN CNetServer::GetToken(const NETADDR &Addr) +{ + md5_state_t md5; + md5_byte_t digest[16]; + SECURITY_TOKEN SecurityToken; + md5_init(&md5); + + md5_append(&md5, (unsigned char*)m_SecurityTokenSeed, sizeof(m_SecurityTokenSeed)); + md5_append(&md5, (unsigned char*)&Addr, sizeof(Addr)); + + md5_finish(&md5, digest); + SecurityToken = ToSecurityToken(digest); + + if (SecurityToken == NET_SECURITY_TOKEN_UNKNOWN || + SecurityToken == NET_SECURITY_TOKEN_UNSUPPORTED) + SecurityToken = 1; + + return SecurityToken; +} + +void CNetServer::SendControl(NETADDR &Addr, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken) +{ + CNetBase::SendControlMsg(m_Socket, &Addr, 0, ControlMsg, pExtra, ExtraSize, SecurityToken); +} + +int CNetServer::NumClientsWithAddr(NETADDR Addr) +{ + NETADDR ThisAddr = Addr, OtherAddr; + + int FoundAddr = 0; + ThisAddr.port = 0; + + for(int i = 0; i < MaxClients(); ++i) + { + if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE || + m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR) + continue; + + OtherAddr = *m_aSlots[i].m_Connection.PeerAddress(); + OtherAddr.port = 0; + if(!net_addr_comp(&ThisAddr, &OtherAddr)) + FoundAddr++; + } + + return FoundAddr; +} + +bool CNetServer::Connlimit(NETADDR Addr) +{ + int64 Now = time_get(); + int Oldest = 0; + + for(int i = 0; i < NET_CONNLIMIT_IPS; ++i) + { + if(!net_addr_comp(&m_aSpamConns[i].m_Addr, &Addr)) + { + if(m_aSpamConns[i].m_Time > Now - time_freq() * g_Config.m_SvConnlimitTime) + { + if(m_aSpamConns[i].m_Conns >= g_Config.m_SvConnlimit) + return true; + } + else + { + m_aSpamConns[i].m_Time = Now; + m_aSpamConns[i].m_Conns = 0; + } + m_aSpamConns[i].m_Conns++; + return false; + } + + if(m_aSpamConns[i].m_Time < m_aSpamConns[Oldest].m_Time) + Oldest = i; + } + + m_aSpamConns[Oldest].m_Addr = Addr; + m_aSpamConns[Oldest].m_Time = Now; + m_aSpamConns[Oldest].m_Conns = 1; + return false; +} + +int CNetServer::TryAcceptClient(NETADDR &Addr, SECURITY_TOKEN SecurityToken, bool VanillaAuth) +{ + if (Connlimit(Addr)) + { + const char Msg[] = "Too many connections in a short time"; + CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, Msg, sizeof(Msg), SecurityToken); + return -1; // failed to add client + } + + // check for sv_max_clients_per_ip + if (NumClientsWithAddr(Addr) + 1 > m_MaxClientsPerIP) + { + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "Only %d players with the same IP are allowed", m_MaxClientsPerIP); + CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, str_length(aBuf) + 1, SecurityToken); + return -1; // failed to add client + } + + int Slot = -1; + for(int i = 0; i < MaxClients(); i++) + { + if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) + { + Slot = i; + break; + } + } + + if (Slot == -1) + { + const char FullMsg[] = "This server is full"; + CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, FullMsg, sizeof(FullMsg), SecurityToken); + + return -1; // failed to add client + } + + // init connection slot + m_aSlots[Slot].m_Connection.DirectInit(Addr, SecurityToken); + + if (VanillaAuth) + { + // client sequence is unknown if the auth was done + // connection-less + m_aSlots[Slot].m_Connection.SetUnknownSeq(); + // correct sequence + m_aSlots[Slot].m_Connection.SetSequence(6); + } + + if (g_Config.m_Debug) + { + char aAddrStr[NETADDR_MAXSTRSIZE]; + net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr), true); + dbg_msg("security", "client accepted %s", aAddrStr); + } + + + if (VanillaAuth) + m_pfnNewClientNoAuth(Slot, m_UserPtr); + else + m_pfnNewClient(Slot, m_UserPtr); + + return Slot; // done +} + +void CNetServer::SendMsgs(NETADDR &Addr, const CMsgPacker *Msgs[], int num) +{ + CNetPacketConstruct m_Construct; + mem_zero(&m_Construct, sizeof(m_Construct)); + unsigned char *pChunkData = &m_Construct.m_aChunkData[m_Construct.m_DataSize]; + + for (int i = 0; i < num; i++) + { + const CMsgPacker *pMsg = Msgs[i]; + CNetChunkHeader Header; + Header.m_Flags = NET_CHUNKFLAG_VITAL; + Header.m_Size = pMsg->Size(); + Header.m_Sequence = i+1; + pChunkData = Header.Pack(pChunkData); + mem_copy(pChunkData, pMsg->Data(), pMsg->Size()); + *((unsigned char*)pChunkData) <<= 1; + *((unsigned char*)pChunkData) |= 1; + pChunkData += pMsg->Size(); + m_Construct.m_NumChunks++; + } + + // + m_Construct.m_DataSize = (int)(pChunkData-m_Construct.m_aChunkData); + CNetBase::SendPacket(m_Socket, &Addr, &m_Construct, NET_SECURITY_TOKEN_UNSUPPORTED); +} + +// connection-less msg packet without token-support +void CNetServer::OnPreConnMsg(NETADDR &Addr, CNetPacketConstruct &Packet) +{ + bool IsCtrl = Packet.m_Flags&NET_PACKETFLAG_CONTROL; + int CtrlMsg = m_RecvUnpacker.m_Data.m_aChunkData[0]; + + // log flooding + //TODO: remove + if (g_Config.m_Debug) + { + int64 Now = time_get(); + + if (Now - m_TimeNumConAttempts > time_freq()) + // reset + m_NumConAttempts = 0; + + m_NumConAttempts++; + + if (m_NumConAttempts > 100) + { + dbg_msg("security", "flooding detected"); + + m_TimeNumConAttempts = Now; + m_NumConAttempts = 0; + } + } + + + if (IsCtrl && CtrlMsg == NET_CTRLMSG_CONNECT) + { + if (g_Config.m_SvVanillaAntiSpoof && g_Config.m_Password[0] == '\0') + { + // detect flooding + int64 Now = time_get(); + if(Now <= m_VConnFirst + time_freq()) + { + m_VConnNum++; + } + else + { + m_VConnHighLoad = m_VConnNum > g_Config.m_SvVanConnPerSecond; + m_VConnNum = 1; + m_VConnFirst = Now; + } + + bool Flooding = m_VConnNum > g_Config.m_SvVanConnPerSecond || m_VConnHighLoad; + + if (g_Config.m_Debug && Flooding) + { + dbg_msg("security", "vanilla connection flooding detected"); + } + + // simulate accept + SendControl(Addr, NET_CTRLMSG_CONNECTACCEPT, NULL, 0, NET_SECURITY_TOKEN_UNSUPPORTED); + + // Begin vanilla compatible token handshake + // The idea is to pack a security token in the gametick + // parameter of NETMSG_SNAPEMPTY. The Client then will + // return the token/gametick in NETMSG_INPUT, allowing + // us to validate the token. + // https://github.com/eeeee/ddnet/commit/b8e40a244af4e242dc568aa34854c5754c75a39a + + // Before we can send NETMSG_SNAPEMPTY, the client needs + // to load a map, otherwise it might crash. The map + // should be as small as is possible and directly available + // to the client. Therefore a dummy map is sent in the same + // packet. To reduce the traffic we'll fallback to a default + // map if there are too many connection attempts at once. + + // send mapchange + map data + con_ready + 3 x empty snap (with token) + CMsgPacker MapChangeMsg(NETMSG_MAP_CHANGE); + + if (Flooding) + { + // Fallback to dm1 + MapChangeMsg.AddString("dm1", 0); + MapChangeMsg.AddInt(0xf2159e6e); + MapChangeMsg.AddInt(5805); + } + else + { + // dummy map + MapChangeMsg.AddString("dummy", 0); + MapChangeMsg.AddInt(DummyMapCrc); + MapChangeMsg.AddInt(sizeof(g_aDummyMapData)); + } + + CMsgPacker MapDataMsg(NETMSG_MAP_DATA); + + if (Flooding) + { + // send empty map data to keep 0.6.4 support + MapDataMsg.AddInt(1); // last chunk + MapDataMsg.AddInt(0); // crc + MapDataMsg.AddInt(0); // chunk index + MapDataMsg.AddInt(0); // map size + MapDataMsg.AddRaw(NULL, 0); // map data + } + else + { + // send dummy map data + MapDataMsg.AddInt(1); // last chunk + MapDataMsg.AddInt(DummyMapCrc); // crc + MapDataMsg.AddInt(0); // chunk index + MapDataMsg.AddInt(sizeof(g_aDummyMapData)); // map size + MapDataMsg.AddRaw(g_aDummyMapData, sizeof(g_aDummyMapData)); // map data + } + + CMsgPacker ConReadyMsg(NETMSG_CON_READY); + + CMsgPacker SnapEmptyMsg(NETMSG_SNAPEMPTY); + SECURITY_TOKEN SecurityToken = GetVanillaToken(Addr); + SnapEmptyMsg.AddInt((int)SecurityToken); + SnapEmptyMsg.AddInt((int)SecurityToken + 1); + + // send all chunks/msgs in one packet + const CMsgPacker *Msgs[] = {&MapChangeMsg, &MapDataMsg, &ConReadyMsg, + &SnapEmptyMsg, &SnapEmptyMsg, &SnapEmptyMsg}; + SendMsgs(Addr, Msgs, 6); + } + else + { + // accept client directly + SendControl(Addr, NET_CTRLMSG_CONNECTACCEPT, NULL, 0, NET_SECURITY_TOKEN_UNSUPPORTED); + + TryAcceptClient(Addr, NET_SECURITY_TOKEN_UNSUPPORTED); + } + } + else if(!IsCtrl && g_Config.m_SvVanillaAntiSpoof && g_Config.m_Password[0] == '\0') + { + CNetChunkHeader h; + + unsigned char *pData = Packet.m_aChunkData; + pData = h.Unpack(pData); + CUnpacker Unpacker; + Unpacker.Reset(pData, h.m_Size); + int Msg = Unpacker.GetInt() >> 1; + + if (Msg == NETMSG_INPUT) + { + SECURITY_TOKEN SecurityToken = Unpacker.GetInt(); + if (SecurityToken == GetVanillaToken(Addr)) + { + if (g_Config.m_Debug) + dbg_msg("security", "new client (vanilla handshake)"); + // try to accept client skipping auth state + TryAcceptClient(Addr, NET_SECURITY_TOKEN_UNSUPPORTED, true); + } + else if (g_Config.m_Debug) + dbg_msg("security", "invalid token (vanilla handshake)"); + + } + else + { + if (g_Config.m_Debug) + { + dbg_msg("security", "invalid preconn msg %d", Msg); + } + } + } +} + +void CNetServer::OnTokenCtrlMsg(NETADDR &Addr, int ControlMsg, const CNetPacketConstruct &Packet) +{ + if (ClientExists(Addr)) + return; // silently ignore + + + if (ControlMsg == NET_CTRLMSG_CONNECT) + { + bool SupportsToken = Packet.m_DataSize >= + (int)(1 + sizeof(SECURITY_TOKEN_MAGIC) + sizeof(SECURITY_TOKEN)) && + !mem_comp(&Packet.m_aChunkData[1], SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC)); + + if (SupportsToken) + { + // response connection request with token + SECURITY_TOKEN Token = GetToken(Addr); + SendControl(Addr, NET_CTRLMSG_CONNECTACCEPT, SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC), Token); + } + } + else if (ControlMsg == NET_CTRLMSG_ACCEPT && Packet.m_DataSize == 1 + sizeof(SECURITY_TOKEN)) + { + SECURITY_TOKEN Token = ToSecurityToken(&Packet.m_aChunkData[1]); + if (Token == GetToken(Addr)) + { + // correct token + // try to accept client + if (g_Config.m_Debug) + dbg_msg("security", "new client (0.6.5 token)"); + TryAcceptClient(Addr, Token); + } + else + { + // invalid token + if (g_Config.m_Debug) + dbg_msg("security", "invalid token"); + } + } +} + +int CNetServer::GetClientSlot(const NETADDR &Addr) +{ + int Slot = -1; + + for(int i = 0; i < MaxClients(); i++) + { + if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE && + m_aSlots[i].m_Connection.State() != NET_CONNSTATE_ERROR && + net_addr_comp(m_aSlots[i].m_Connection.PeerAddress(), &Addr) == 0) + + { + Slot = i; + } + } + + return Slot; +} + /* TODO: chopp up this function into smaller working parts */ @@ -105,17 +549,17 @@ int CNetServer::Recv(CNetChunk *pChunk) if(Bytes <= 0) break; - if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0) + // check if we just should drop the packet + char aBuf[128]; + if(NetBan() && NetBan()->IsBanned(&Addr, aBuf, sizeof(aBuf))) { - // check if we just should drop the packet - char aBuf[128]; - if(NetBan() && NetBan()->IsBanned(&Addr, aBuf, sizeof(aBuf))) - { - // banned, reply with a message - CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, str_length(aBuf)+1); - continue; - } + // banned, reply with a message + CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, str_length(aBuf)+1, NET_SECURITY_TOKEN_UNSUPPORTED); + continue; + } + if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0) + { if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS) { pChunk->m_Flags = NETSENDFLAG_CONNLESS; @@ -127,83 +571,35 @@ int CNetServer::Recv(CNetChunk *pChunk) } else { - // TODO: check size here - if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_CONNECT) - { - bool Found = false; + // drop invalid ctrl packets + if (m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && + m_RecvUnpacker.m_Data.m_DataSize == 0) + continue; - // check if we already got this client - for(int i = 0; i < MaxClients(); i++) - { - if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE && - net_addr_comp(m_aSlots[i].m_Connection.PeerAddress(), &Addr) == 0) - { - Found = true; // silent ignore.. we got this client already - break; - } - } + // normal packet, find matching slot + int Slot = GetClientSlot(Addr); - // client that wants to connect - if(!Found) - { + if (Slot != -1) + { + // found - // only allow a specific number of players with the same ip - NETADDR ThisAddr = Addr, OtherAddr; - int FoundAddr = 1; - ThisAddr.port = 0; - for(int i = 0; i < MaxClients(); ++i) - { - if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) - continue; - - OtherAddr = *m_aSlots[i].m_Connection.PeerAddress(); - OtherAddr.port = 0; - if(!net_addr_comp(&ThisAddr, &OtherAddr)) - { - if(FoundAddr++ >= m_MaxClientsPerIP) - { - char aBuf[128]; - str_format(aBuf, sizeof(aBuf), "Only %d players with the same IP are allowed", m_MaxClientsPerIP); - CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, sizeof(aBuf)); - return 0; - } - } - } - - for(int i = 0; i < MaxClients(); i++) - { - if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) - { - Found = true; - m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr); - if(m_pfnNewClient) - m_pfnNewClient(i, m_UserPtr); - - break; - } - } - - if(!Found) - { - const char FullMsg[] = "This server is full"; - CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, FullMsg, sizeof(FullMsg)); - } + if(m_aSlots[Slot].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr)) + { + if(m_RecvUnpacker.m_Data.m_DataSize) + m_RecvUnpacker.Start(&Addr, &m_aSlots[Slot].m_Connection, Slot); } } else { - // normal packet, find matching slot - for(int i = 0; i < MaxClients(); i++) - { - if(net_addr_comp(m_aSlots[i].m_Connection.PeerAddress(), &Addr) == 0) - { - if(m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr)) - { - if(m_RecvUnpacker.m_Data.m_DataSize) - m_RecvUnpacker.Start(&Addr, &m_aSlots[i].m_Connection, i); - } - } - } + // not found, client that wants to connect + + if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && + m_RecvUnpacker.m_Data.m_DataSize > 1) + // got control msg with extra size (should support token) + OnTokenCtrlMsg(Addr, m_RecvUnpacker.m_Data.m_aChunkData[0], m_RecvUnpacker.m_Data); + else + // got connection-less ctrl or sys msg + OnPreConnMsg(Addr, m_RecvUnpacker.m_Data); } } } @@ -240,7 +636,7 @@ int CNetServer::Send(CNetChunk *pChunk) } else { - Drop(pChunk->m_ClientID, "Error sending data"); + //Drop(pChunk->m_ClientID, "Error sending data"); } } return 0; |