2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2009-10-27 14:38:53 +00:00
|
|
|
#include <base/system.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "network.h"
|
2009-10-27 14:38:53 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#define MACRO_LIST_LINK_FIRST(Object, First, Prev, Next) \
|
|
|
|
{ if(First) First->Prev = Object; \
|
|
|
|
Object->Prev = (struct CBan *)0; \
|
|
|
|
Object->Next = First; \
|
|
|
|
First = Object; }
|
2009-10-27 14:38:53 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#define MACRO_LIST_LINK_AFTER(Object, After, Prev, Next) \
|
|
|
|
{ Object->Prev = After; \
|
|
|
|
Object->Next = After->Next; \
|
|
|
|
After->Next = Object; \
|
|
|
|
if(Object->Next) \
|
|
|
|
Object->Next->Prev = Object; \
|
2009-10-27 14:38:53 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#define MACRO_LIST_UNLINK(Object, First, Prev, Next) \
|
|
|
|
{ if(Object->Next) Object->Next->Prev = Object->Prev; \
|
|
|
|
if(Object->Prev) Object->Prev->Next = Object->Next; \
|
|
|
|
else First = Object->Next; \
|
|
|
|
Object->Next = 0; Object->Prev = 0; }
|
2009-10-27 14:38:53 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#define MACRO_LIST_FIND(Start, Next, Expression) \
|
|
|
|
{ while(Start && !(Expression)) Start = Start->Next; }
|
2009-10-27 14:38:53 +00:00
|
|
|
|
2010-06-03 12:48:32 +00:00
|
|
|
bool CNetServer::Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int Flags)
|
2009-10-27 14:38:53 +00:00
|
|
|
{
|
|
|
|
// zero out the whole structure
|
|
|
|
mem_zero(this, sizeof(*this));
|
|
|
|
|
|
|
|
// open socket
|
|
|
|
m_Socket = net_udp_create(BindAddr);
|
|
|
|
if(m_Socket == NETSOCKET_INVALID)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// clamp clients
|
|
|
|
m_MaxClients = MaxClients;
|
|
|
|
if(m_MaxClients > NET_MAX_CLIENTS)
|
|
|
|
m_MaxClients = NET_MAX_CLIENTS;
|
|
|
|
if(m_MaxClients < 1)
|
|
|
|
m_MaxClients = 1;
|
2010-06-03 12:48:32 +00:00
|
|
|
|
|
|
|
m_MaxClientsPerIP = MaxClientsPerIP;
|
2009-10-27 14:38:53 +00:00
|
|
|
|
|
|
|
for(int i = 0; i < NET_MAX_CLIENTS; i++)
|
|
|
|
m_aSlots[i].m_Connection.Init(m_Socket);
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// setup all pointers for bans
|
2009-10-27 14:38:53 +00:00
|
|
|
for(int i = 1; i < NET_SERVER_MAXBANS-1; i++)
|
|
|
|
{
|
|
|
|
m_BanPool[i].m_pNext = &m_BanPool[i+1];
|
|
|
|
m_BanPool[i].m_pPrev = &m_BanPool[i-1];
|
|
|
|
}
|
|
|
|
|
|
|
|
m_BanPool[0].m_pNext = &m_BanPool[1];
|
|
|
|
m_BanPool[NET_SERVER_MAXBANS-1].m_pPrev = &m_BanPool[NET_SERVER_MAXBANS-2];
|
|
|
|
m_BanPool_FirstFree = &m_BanPool[0];
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetServer::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser)
|
|
|
|
{
|
|
|
|
m_pfnNewClient = pfnNewClient;
|
|
|
|
m_pfnDelClient = pfnDelClient;
|
|
|
|
m_UserPtr = pUser;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetServer::Close()
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
// TODO: implement me
|
2009-10-27 14:38:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetServer::Drop(int ClientID, const char *pReason)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
// TODO: insert lots of checks here
|
2009-10-27 14:38:53 +00:00
|
|
|
NETADDR Addr = ClientAddr(ClientID);
|
|
|
|
|
2010-08-17 22:06:00 +00:00
|
|
|
/*dbg_msg("net_server", "client dropped. cid=%d ip=%d.%d.%d.%d reason=\"%s\"",
|
2009-10-27 14:38:53 +00:00
|
|
|
ClientID,
|
|
|
|
Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3],
|
|
|
|
pReason
|
2010-08-17 22:06:00 +00:00
|
|
|
);*/
|
|
|
|
if(m_pfnDelClient)
|
|
|
|
m_pfnDelClient(ClientID, pReason, m_UserPtr);
|
2009-10-27 14:38:53 +00:00
|
|
|
|
|
|
|
m_aSlots[ClientID].m_Connection.Disconnect(pReason);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetServer::BanGet(int Index, CBanInfo *pInfo)
|
|
|
|
{
|
|
|
|
CBan *pBan;
|
|
|
|
for(pBan = m_BanPool_FirstUsed; pBan && Index; pBan = pBan->m_pNext, Index--)
|
|
|
|
{}
|
|
|
|
|
|
|
|
if(!pBan)
|
|
|
|
return 0;
|
|
|
|
*pInfo = pBan->m_Info;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetServer::BanNum()
|
|
|
|
{
|
|
|
|
int Count = 0;
|
|
|
|
CBan *pBan;
|
|
|
|
for(pBan = m_BanPool_FirstUsed; pBan; pBan = pBan->m_pNext)
|
|
|
|
Count++;
|
|
|
|
return Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CNetServer::BanRemoveByObject(CBan *pBan)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int IpHash = (pBan->m_Info.m_Addr.ip[0]+pBan->m_Info.m_Addr.ip[1]+pBan->m_Info.m_Addr.ip[2]+pBan->m_Info.m_Addr.ip[3])&0xff;
|
2009-10-27 14:38:53 +00:00
|
|
|
dbg_msg("netserver", "removing ban on %d.%d.%d.%d",
|
|
|
|
pBan->m_Info.m_Addr.ip[0], pBan->m_Info.m_Addr.ip[1], pBan->m_Info.m_Addr.ip[2], pBan->m_Info.m_Addr.ip[3]);
|
|
|
|
MACRO_LIST_UNLINK(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
|
2010-05-29 07:25:38 +00:00
|
|
|
MACRO_LIST_UNLINK(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext);
|
2009-10-27 14:38:53 +00:00
|
|
|
MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext);
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetServer::BanRemove(NETADDR Addr)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3])&0xff;
|
|
|
|
CBan *pBan = m_aBans[IpHash];
|
2009-10-27 14:38:53 +00:00
|
|
|
|
|
|
|
MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0);
|
|
|
|
|
|
|
|
if(pBan)
|
|
|
|
{
|
|
|
|
BanRemoveByObject(pBan);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-10-09 18:19:58 +00:00
|
|
|
int CNetServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason)
|
2009-10-27 14:38:53 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3])&0xff;
|
2009-10-27 14:38:53 +00:00
|
|
|
int Stamp = -1;
|
|
|
|
CBan *pBan;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// remove the port
|
2009-10-27 14:38:53 +00:00
|
|
|
Addr.port = 0;
|
|
|
|
|
|
|
|
if(Seconds)
|
|
|
|
Stamp = time_timestamp() + Seconds;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// search to see if it already exists
|
|
|
|
pBan = m_aBans[IpHash];
|
2009-10-27 14:38:53 +00:00
|
|
|
MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0);
|
|
|
|
if(pBan)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
// adjust the ban
|
2009-10-27 14:38:53 +00:00
|
|
|
pBan->m_Info.m_Expires = Stamp;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!m_BanPool_FirstFree)
|
|
|
|
return -1;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// fetch and clear the new ban
|
2009-10-27 14:38:53 +00:00
|
|
|
pBan = m_BanPool_FirstFree;
|
|
|
|
MACRO_LIST_UNLINK(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext);
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// setup the ban info
|
2009-10-27 14:38:53 +00:00
|
|
|
pBan->m_Info.m_Expires = Stamp;
|
|
|
|
pBan->m_Info.m_Addr = Addr;
|
2011-02-13 11:36:55 +00:00
|
|
|
str_copy(pBan->m_Info.m_Reason, pReason, sizeof(pBan->m_Info.m_Reason));
|
2009-10-27 14:38:53 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// add it to the ban hash
|
|
|
|
MACRO_LIST_LINK_FIRST(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext);
|
2009-10-27 14:38:53 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// insert it into the used list
|
2009-10-27 14:38:53 +00:00
|
|
|
{
|
|
|
|
if(m_BanPool_FirstUsed)
|
|
|
|
{
|
|
|
|
CBan *pInsertAfter = m_BanPool_FirstUsed;
|
|
|
|
MACRO_LIST_FIND(pInsertAfter, m_pNext, Stamp < pInsertAfter->m_Info.m_Expires);
|
|
|
|
|
|
|
|
if(pInsertAfter)
|
|
|
|
pInsertAfter = pInsertAfter->m_pPrev;
|
|
|
|
else
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
// add to last
|
2009-10-27 14:38:53 +00:00
|
|
|
pInsertAfter = m_BanPool_FirstUsed;
|
|
|
|
while(pInsertAfter->m_pNext)
|
|
|
|
pInsertAfter = pInsertAfter->m_pNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pInsertAfter)
|
|
|
|
{
|
|
|
|
MACRO_LIST_LINK_AFTER(pBan, pInsertAfter, m_pPrev, m_pNext);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// drop banned clients
|
2009-10-27 14:38:53 +00:00
|
|
|
{
|
|
|
|
char Buf[128];
|
|
|
|
NETADDR BanAddr;
|
|
|
|
|
2011-02-13 11:36:55 +00:00
|
|
|
int Mins = (Seconds + 59) / 60;
|
|
|
|
if(Mins)
|
|
|
|
{
|
|
|
|
if(Mins == 1)
|
|
|
|
str_format(Buf, sizeof(Buf), "You have been banned for 1 minute (%s)", pReason);
|
|
|
|
else
|
|
|
|
str_format(Buf, sizeof(Buf), "You have been banned for %d minutes (%s)", Mins, pReason);
|
|
|
|
}
|
2009-10-27 14:38:53 +00:00
|
|
|
else
|
2010-10-09 18:19:58 +00:00
|
|
|
str_format(Buf, sizeof(Buf), "You have been banned for life (%s)", pReason);
|
2009-10-27 14:38:53 +00:00
|
|
|
|
|
|
|
for(int i = 0; i < MaxClients(); i++)
|
|
|
|
{
|
|
|
|
BanAddr = m_aSlots[i].m_Connection.PeerAddress();
|
|
|
|
BanAddr.port = 0;
|
|
|
|
|
|
|
|
if(net_addr_comp(&Addr, &BanAddr) == 0)
|
|
|
|
Drop(i, Buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetServer::Update()
|
|
|
|
{
|
|
|
|
int Now = time_timestamp();
|
|
|
|
for(int i = 0; i < MaxClients(); i++)
|
|
|
|
{
|
|
|
|
m_aSlots[i].m_Connection.Update();
|
|
|
|
if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR)
|
|
|
|
Drop(i, m_aSlots[i].m_Connection.ErrorString());
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// remove expired bans
|
2009-10-27 14:38:53 +00:00
|
|
|
while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires < Now)
|
|
|
|
{
|
|
|
|
CBan *pBan = m_BanPool_FirstUsed;
|
|
|
|
BanRemoveByObject(pBan);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
TODO: chopp up this function into smaller working parts
|
|
|
|
*/
|
|
|
|
int CNetServer::Recv(CNetChunk *pChunk)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
unsigned Now = time_timestamp();
|
2009-10-27 14:38:53 +00:00
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
NETADDR Addr;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// check for a chunk
|
2009-10-27 14:38:53 +00:00
|
|
|
if(m_RecvUnpacker.FetchChunk(pChunk))
|
|
|
|
return 1;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// TODO: empty the recvinfo
|
2009-10-27 14:38:53 +00:00
|
|
|
int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE);
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// no more packets for now
|
2009-10-27 14:38:53 +00:00
|
|
|
if(Bytes <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0)
|
|
|
|
{
|
|
|
|
CBan *pBan = 0;
|
|
|
|
NETADDR BanAddr = Addr;
|
2010-05-29 07:25:38 +00:00
|
|
|
int IpHash = (BanAddr.ip[0]+BanAddr.ip[1]+BanAddr.ip[2]+BanAddr.ip[3])&0xff;
|
2009-10-27 14:38:53 +00:00
|
|
|
int Found = 0;
|
|
|
|
BanAddr.port = 0;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// search a ban
|
|
|
|
for(pBan = m_aBans[IpHash]; pBan; pBan = pBan->m_pHashNext)
|
2009-10-27 14:38:53 +00:00
|
|
|
{
|
|
|
|
if(net_addr_comp(&pBan->m_Info.m_Addr, &BanAddr) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// check if we just should drop the packet
|
2009-10-27 14:38:53 +00:00
|
|
|
if(pBan)
|
|
|
|
{
|
|
|
|
// banned, reply with a message
|
|
|
|
char BanStr[128];
|
|
|
|
if(pBan->m_Info.m_Expires)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int Mins = ((pBan->m_Info.m_Expires - Now)+59)/60;
|
2009-10-27 14:38:53 +00:00
|
|
|
if(Mins == 1)
|
2011-02-13 11:36:55 +00:00
|
|
|
str_format(BanStr, sizeof(BanStr), "Banned for 1 minute (%s)", pBan->m_Info.m_Reason);
|
2009-10-27 14:38:53 +00:00
|
|
|
else
|
2011-02-13 11:36:55 +00:00
|
|
|
str_format(BanStr, sizeof(BanStr), "Banned for %d minutes (%s)", Mins, pBan->m_Info.m_Reason);
|
2009-10-27 14:38:53 +00:00
|
|
|
}
|
|
|
|
else
|
2011-02-13 11:36:55 +00:00
|
|
|
str_format(BanStr, sizeof(BanStr), "Banned for life (%s)", pBan->m_Info.m_Reason);
|
2009-10-27 14:38:53 +00:00
|
|
|
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, BanStr, str_length(BanStr)+1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS)
|
|
|
|
{
|
|
|
|
pChunk->m_Flags = NETSENDFLAG_CONNLESS;
|
|
|
|
pChunk->m_ClientID = -1;
|
|
|
|
pChunk->m_Address = Addr;
|
|
|
|
pChunk->m_DataSize = m_RecvUnpacker.m_Data.m_DataSize;
|
|
|
|
pChunk->m_pData = m_RecvUnpacker.m_Data.m_aChunkData;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
// TODO: check size here
|
2009-10-27 14:38:53 +00:00
|
|
|
if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_CONNECT)
|
|
|
|
{
|
|
|
|
Found = 0;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// check if we already got this client
|
2009-10-27 14:38:53 +00:00
|
|
|
for(int i = 0; i < MaxClients(); i++)
|
|
|
|
{
|
|
|
|
NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
|
|
|
|
if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE &&
|
|
|
|
net_addr_comp(&PeerAddr, &Addr) == 0)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
Found = 1; // silent ignore.. we got this client already
|
2009-10-27 14:38:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// client that wants to connect
|
2009-10-27 14:38:53 +00:00
|
|
|
if(!Found)
|
|
|
|
{
|
2010-06-03 12:48:32 +00:00
|
|
|
// 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];
|
2010-10-09 18:19:58 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "Only %d players with the same IP are allowed", m_MaxClientsPerIP);
|
2010-06-03 12:48:32 +00:00
|
|
|
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, sizeof(aBuf));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-27 14:38:53 +00:00
|
|
|
for(int i = 0; i < MaxClients(); i++)
|
|
|
|
{
|
|
|
|
if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
|
|
|
|
{
|
|
|
|
Found = 1;
|
|
|
|
m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr);
|
|
|
|
if(m_pfnNewClient)
|
|
|
|
m_pfnNewClient(i, m_UserPtr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!Found)
|
|
|
|
{
|
2010-10-09 18:19:58 +00:00
|
|
|
const char FullMsg[] = "This server is full";
|
2009-10-27 14:38:53 +00:00
|
|
|
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, FullMsg, sizeof(FullMsg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
// normal packet, find matching slot
|
2009-10-27 14:38:53 +00:00
|
|
|
for(int i = 0; i < MaxClients(); i++)
|
|
|
|
{
|
|
|
|
NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
|
|
|
|
if(net_addr_comp(&PeerAddr, &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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetServer::Send(CNetChunk *pChunk)
|
|
|
|
{
|
|
|
|
if(pChunk->m_DataSize >= NET_MAX_PAYLOAD)
|
|
|
|
{
|
|
|
|
dbg_msg("netserver", "packet payload too big. %d. dropping packet", pChunk->m_DataSize);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pChunk->m_Flags&NETSENDFLAG_CONNLESS)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
// send connectionless packet
|
2009-10-27 14:38:53 +00:00
|
|
|
CNetBase::SendPacketConnless(m_Socket, &pChunk->m_Address, pChunk->m_pData, pChunk->m_DataSize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int Flags = 0;
|
|
|
|
dbg_assert(pChunk->m_ClientID >= 0, "errornous client id");
|
|
|
|
dbg_assert(pChunk->m_ClientID < MaxClients(), "errornous client id");
|
|
|
|
|
|
|
|
if(pChunk->m_Flags&NETSENDFLAG_VITAL)
|
|
|
|
Flags = NET_CHUNKFLAG_VITAL;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_aSlots[pChunk->m_ClientID].m_Connection.QueueChunk(Flags, pChunk->m_DataSize, pChunk->m_pData) == 0)
|
|
|
|
{
|
|
|
|
if(pChunk->m_Flags&NETSENDFLAG_FLUSH)
|
|
|
|
m_aSlots[pChunk->m_ClientID].m_Connection.Flush();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-10-09 18:19:58 +00:00
|
|
|
Drop(pChunk->m_ClientID, "Error sending data");
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
2009-10-27 14:38:53 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-03 12:48:32 +00:00
|
|
|
void CNetServer::SetMaxClientsPerIP(int Max)
|
|
|
|
{
|
|
|
|
// clamp
|
|
|
|
if(Max < 1)
|
|
|
|
Max = 1;
|
|
|
|
else if(Max > NET_MAX_CLIENTS)
|
|
|
|
Max = NET_MAX_CLIENTS;
|
|
|
|
|
|
|
|
m_MaxClientsPerIP = Max;
|
|
|
|
}
|