mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-14 03:58:18 +00:00
1d81d56850
This means that we have a reliable and fast way to query for extended info, while also not wasting network bandwidth. The protocol is designed to be extensible, there's four bytes space for encoding more request types (currently zeroed), and there's one string in each response packet and one string for each player available (currently the empty string). The protocol itself has no problems with more than 64 players, although the current client implementation will drop the player info after the 64th player, because it uses a static array for storage. Also fixes #130, the player list is just sorted each time new player info arrives.
155 lines
3.5 KiB
C++
155 lines
3.5 KiB
C++
/* (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. */
|
|
#include <base/system.h>
|
|
#include "network.h"
|
|
|
|
bool CNetClient::Open(NETADDR BindAddr, int Flags)
|
|
{
|
|
// open socket
|
|
NETSOCKET Socket;
|
|
Socket = net_udp_create(BindAddr);
|
|
if(!Socket.type)
|
|
return false;
|
|
|
|
// clean it
|
|
mem_zero(this, sizeof(*this));
|
|
|
|
// init
|
|
m_Socket = Socket;
|
|
m_Connection.Init(m_Socket, false);
|
|
return true;
|
|
}
|
|
|
|
int CNetClient::Close()
|
|
{
|
|
// TODO: implement me
|
|
return 0;
|
|
}
|
|
|
|
|
|
int CNetClient::Disconnect(const char *pReason)
|
|
{
|
|
//dbg_msg("netclient", "disconnected. reason=\"%s\"", pReason);
|
|
m_Connection.Disconnect(pReason);
|
|
return 0;
|
|
}
|
|
|
|
int CNetClient::Update()
|
|
{
|
|
m_Connection.Update();
|
|
if(m_Connection.State() == NET_CONNSTATE_ERROR)
|
|
Disconnect(m_Connection.ErrorString());
|
|
return 0;
|
|
}
|
|
|
|
int CNetClient::Connect(NETADDR *pAddr)
|
|
{
|
|
m_Connection.Connect(pAddr);
|
|
return 0;
|
|
}
|
|
|
|
int CNetClient::ResetErrorString()
|
|
{
|
|
m_Connection.ResetErrorString();
|
|
return 0;
|
|
}
|
|
|
|
int CNetClient::Recv(CNetChunk *pChunk)
|
|
{
|
|
while(1)
|
|
{
|
|
// check for a chunk
|
|
if(m_RecvUnpacker.FetchChunk(pChunk))
|
|
return 1;
|
|
|
|
// TODO: empty the recvinfo
|
|
NETADDR Addr;
|
|
int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE);
|
|
|
|
// no more packets for now
|
|
if(Bytes <= 0)
|
|
break;
|
|
|
|
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;
|
|
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;
|
|
if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_EXTENDED)
|
|
{
|
|
pChunk->m_Flags |= NETSENDFLAG_EXTENDED;
|
|
mem_copy(pChunk->m_aExtraData, m_RecvUnpacker.m_Data.m_aExtraData, sizeof(pChunk->m_aExtraData));
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if(m_Connection.State() != NET_CONNSTATE_OFFLINE && m_Connection.State() != NET_CONNSTATE_ERROR && net_addr_comp(m_Connection.PeerAddress(), &Addr) == 0
|
|
&& m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr))
|
|
m_RecvUnpacker.Start(&Addr, &m_Connection, 0);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int CNetClient::Send(CNetChunk *pChunk)
|
|
{
|
|
if(pChunk->m_DataSize >= NET_MAX_PAYLOAD)
|
|
{
|
|
dbg_msg("netclient", "chunk payload too big. %d. dropping chunk", pChunk->m_DataSize);
|
|
return -1;
|
|
}
|
|
|
|
if(pChunk->m_Flags&NETSENDFLAG_CONNLESS)
|
|
{
|
|
// send connectionless packet
|
|
CNetBase::SendPacketConnless(m_Socket, &pChunk->m_Address, pChunk->m_pData, pChunk->m_DataSize,
|
|
pChunk->m_Flags&NETSENDFLAG_EXTENDED, pChunk->m_aExtraData);
|
|
}
|
|
else
|
|
{
|
|
int Flags = 0;
|
|
dbg_assert(pChunk->m_ClientID == 0, "errornous client id");
|
|
|
|
if(pChunk->m_Flags&NETSENDFLAG_VITAL)
|
|
Flags = NET_CHUNKFLAG_VITAL;
|
|
|
|
m_Connection.QueueChunk(Flags, pChunk->m_DataSize, pChunk->m_pData);
|
|
|
|
if(pChunk->m_Flags&NETSENDFLAG_FLUSH)
|
|
m_Connection.Flush();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int CNetClient::State()
|
|
{
|
|
if(m_Connection.State() == NET_CONNSTATE_ONLINE)
|
|
return NETSTATE_ONLINE;
|
|
if(m_Connection.State() == NET_CONNSTATE_OFFLINE)
|
|
return NETSTATE_OFFLINE;
|
|
return NETSTATE_CONNECTING;
|
|
}
|
|
|
|
int CNetClient::Flush()
|
|
{
|
|
return m_Connection.Flush();
|
|
}
|
|
|
|
int CNetClient::GotProblems()
|
|
{
|
|
if(time_get() - m_Connection.LastRecvTime() > time_freq())
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
const char *CNetClient::ErrorString()
|
|
{
|
|
return m_Connection.ErrorString();
|
|
}
|