Skip to content

Commit

Permalink
improved map download. Closes teeworlds#712
Browse files Browse the repository at this point in the history
  • Loading branch information
oy committed Mar 4, 2012
1 parent 42c845b commit c2e5771
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 93 deletions.
24 changes: 14 additions & 10 deletions src/base/system.c
Expand Up @@ -903,6 +903,7 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
NETSOCKET sock = invalid_socket;
NETADDR tmpbindaddr = bindaddr;
int broadcast = 1;
int recvsize = 65536;

if(bindaddr.type&NETTYPE_IPV4)
{
Expand All @@ -917,13 +918,13 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
{
sock.type |= NETTYPE_IPV4;
sock.ipv4sock = socket;
}

/* set non-blocking */
net_set_non_blocking(sock);
/* set broadcast */
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));

/* set boardcast */
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));
/* set receive buffer size */
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvsize, sizeof(recvsize));
}
}

if(bindaddr.type&NETTYPE_IPV6)
Expand All @@ -939,15 +940,18 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
{
sock.type |= NETTYPE_IPV6;
sock.ipv6sock = socket;
}

/* set non-blocking */
net_set_non_blocking(sock);
/* set broadcast */
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));

/* set boardcast */
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));
/* set receive buffer size */
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvsize, sizeof(recvsize));
}
}

/* set non-blocking */
net_set_non_blocking(sock);

/* return */
return sock;
}
Expand Down
54 changes: 24 additions & 30 deletions src/engine/client/client.cpp
Expand Up @@ -1028,6 +1028,8 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
const char *pMap = Unpacker.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES);
int MapCrc = Unpacker.GetInt();
int MapSize = Unpacker.GetInt();
int MapChunkNum = Unpacker.GetInt();
int MapChunkSize = Unpacker.GetInt();
const char *pError = 0;

if(Unpacker.Error())
Expand All @@ -1037,13 +1039,14 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(!m_MapChecker.IsMapValid(pMap, MapCrc, MapSize))
pError = "invalid standard map";

for(int i = 0; pMap[i]; i++) // protect the player from nasty map names
// protect the player from nasty map names
for(int i = 0; pMap[i]; i++)
{
if(pMap[i] == '/' || pMap[i] == '\\')
pError = "strange character in map name";
}

if(MapSize < 0)
if(MapSize <= 0)
pError = "invalid map size";

if(pError)
Expand All @@ -1059,52 +1062,50 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
}
else
{
// start map download
str_format(m_aMapdownloadFilename, sizeof(m_aMapdownloadFilename), "downloadedmaps/%s_%08x.map", pMap, MapCrc);

char aBuf[256];
str_format(aBuf, sizeof(aBuf), "starting to download map to '%s'", m_aMapdownloadFilename);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", aBuf);

m_MapdownloadChunk = 0;
str_copy(m_aMapdownloadName, pMap, sizeof(m_aMapdownloadName));
if(m_MapdownloadFile)
io_close(m_MapdownloadFile);
m_MapdownloadFile = Storage()->OpenFile(m_aMapdownloadFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
m_MapdownloadChunk = 0;
m_MapdownloadChunkNum = MapChunkNum;
m_MapDownloadChunkSize = MapChunkSize;
m_MapdownloadCrc = MapCrc;
m_MapdownloadTotalsize = MapSize;
m_MapdownloadAmount = 0;

// request first chunk package of map data
CMsgPacker Msg(NETMSG_REQUEST_MAP_DATA);
Msg.AddInt(m_MapdownloadChunk);
SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH);

if(g_Config.m_Debug)
{
str_format(aBuf, sizeof(aBuf), "requested chunk %d", m_MapdownloadChunk);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", aBuf);
}
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", "requested first chunk package");
}
}
}
else if(Msg == NETMSG_MAP_DATA)
{
int Last = Unpacker.GetInt();
int MapCRC = Unpacker.GetInt();
int Chunk = Unpacker.GetInt();
int Size = Unpacker.GetInt();
const unsigned char *pData = Unpacker.GetRaw(Size);

// check fior errors
if(Unpacker.Error() || Size <= 0 || MapCRC != m_MapdownloadCrc || Chunk != m_MapdownloadChunk || !m_MapdownloadFile)
if(!m_MapdownloadFile)
return;

int Size = min(m_MapDownloadChunkSize, m_MapdownloadTotalsize-m_MapdownloadAmount);
const unsigned char *pData = Unpacker.GetRaw(Size);
if(Unpacker.Error())
return;

io_write(m_MapdownloadFile, pData, Size);

++m_MapdownloadChunk;
m_MapdownloadAmount += Size;

if(Last)
if(m_MapdownloadAmount == m_MapdownloadTotalsize)
{
const char *pError;
// map download complete
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "download complete, loading map");

if(m_MapdownloadFile)
Expand All @@ -1114,7 +1115,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
m_MapdownloadTotalsize = -1;

// load map
pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, m_MapdownloadCrc);
const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, m_MapdownloadCrc);
if(!pError)
{
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "loading done");
Expand All @@ -1123,21 +1124,14 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
else
DisconnectWithReason(pError);
}
else
else if(m_MapdownloadChunk%m_MapdownloadChunkNum == 0)
{
// request new chunk
m_MapdownloadChunk++;

// request next chunk package of map data
CMsgPacker Msg(NETMSG_REQUEST_MAP_DATA);
Msg.AddInt(m_MapdownloadChunk);
SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH);

if(g_Config.m_Debug)
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "requested chunk %d", m_MapdownloadChunk);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", aBuf);
}
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", "requested next chunk package");
}
}
else if(Msg == NETMSG_CON_READY)
Expand Down
2 changes: 2 additions & 0 deletions src/engine/client/client.h
Expand Up @@ -121,6 +121,8 @@ class CClient : public IClient, public CDemoPlayer::IListner
char m_aMapdownloadName[256];
IOHANDLE m_MapdownloadFile;
int m_MapdownloadChunk;
int m_MapdownloadChunkNum;
int m_MapDownloadChunkSize;
int m_MapdownloadCrc;
int m_MapdownloadAmount;
int m_MapdownloadTotalsize;
Expand Down
56 changes: 30 additions & 26 deletions src/engine/server/server.cpp
Expand Up @@ -288,6 +288,7 @@ void CServer::CClient::Reset()
m_LastInputTick = -1;
m_SnapRate = CClient::SNAPRATE_INIT;
m_Score = 0;
m_MapChunk = 0;
}

CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta)
Expand Down Expand Up @@ -745,6 +746,8 @@ void CServer::SendMap(int ClientID)
Msg.AddString(GetMapName(), 0);
Msg.AddInt(m_CurrentMapCrc);
Msg.AddInt(m_CurrentMapSize);
Msg.AddInt(m_MapChunksPerRequest);
Msg.AddInt(MAP_CHUNK_SIZE);
SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true);
}

Expand Down Expand Up @@ -855,36 +858,36 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
}
else if(Msg == NETMSG_REQUEST_MAP_DATA)
{
int Chunk = Unpacker.GetInt();
int ChunkSize = 1024-128;
int Offset = Chunk * ChunkSize;
int Last = 0;
if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTING)
{
int ChunkSize = MAP_CHUNK_SIZE;

// drop faulty map data requests
if(Chunk < 0 || Offset > m_CurrentMapSize)
return;
// send map chunks
for(int i = 0; i < m_MapChunksPerRequest && m_aClients[ClientID].m_MapChunk >= 0; ++i)
{
int Chunk = m_aClients[ClientID].m_MapChunk;
int Offset = Chunk * ChunkSize;

if(Offset+ChunkSize >= m_CurrentMapSize)
{
ChunkSize = m_CurrentMapSize-Offset;
if(ChunkSize < 0)
ChunkSize = 0;
Last = 1;
}
// check for last part
if(Offset+ChunkSize >= m_CurrentMapSize)
{
ChunkSize = m_CurrentMapSize-Offset;
m_aClients[ClientID].m_MapChunk = -1;
}
else
m_aClients[ClientID].m_MapChunk++;

CMsgPacker Msg(NETMSG_MAP_DATA);
Msg.AddInt(Last);
Msg.AddInt(m_CurrentMapCrc);
Msg.AddInt(Chunk);
Msg.AddInt(ChunkSize);
Msg.AddRaw(&m_pCurrentMapData[Offset], ChunkSize);
SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true);
CMsgPacker Msg(NETMSG_MAP_DATA);
Msg.AddRaw(&m_pCurrentMapData[Offset], ChunkSize);
SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true);

if(g_Config.m_Debug)
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "sending chunk %d with size %d", Chunk, ChunkSize);
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf);
if(g_Config.m_Debug)
{
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "sending chunk %d with size %d", Chunk, ChunkSize);
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf);
}
}
}
}
else if(Msg == NETMSG_READY)
Expand Down Expand Up @@ -1268,6 +1271,7 @@ int CServer::Run()
dbg_msg("server", "failed to load map. mapname='%s'", g_Config.m_SvMap);
return -1;
}
m_MapChunksPerRequest = g_Config.m_SvMapDownloadSpeed;

// start server
NETADDR BindAddr;
Expand Down
7 changes: 7 additions & 0 deletions src/engine/server/server.h
Expand Up @@ -122,6 +122,7 @@ class CServer : public IServer
int m_Authed;
int m_AuthTries;

int m_MapChunk;
const IConsole::CCommandInfo *m_pRconCmdToSend;

void Reset();
Expand Down Expand Up @@ -149,10 +150,16 @@ class CServer : public IServer
int64 m_Lastheartbeat;
//static NETADDR4 master_server;

// map
enum
{
MAP_CHUNK_SIZE=NET_MAX_PAYLOAD-NET_MAX_CHUNKHEADERSIZE-4, // msg type
};
char m_aCurrentMap[64];
unsigned m_CurrentMapCrc;
unsigned char *m_pCurrentMapData;
int m_CurrentMapSize;
int m_MapChunksPerRequest;

CDemoRecorder m_DemoRecorder;
CRegister m_Register;
Expand Down
1 change: 1 addition & 0 deletions src/engine/shared/config_variables.h
Expand Up @@ -84,6 +84,7 @@ MACRO_CONFIG_INT(SvExternalPort, sv_external_port, 0, 0, 0, CFGFLAG_SERVER, "Ext
MACRO_CONFIG_STR(SvMap, sv_map, 128, "dm1", CFGFLAG_SERVER, "Map to use on the server")
MACRO_CONFIG_INT(SvMaxClients, sv_max_clients, 8, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum number of clients that are allowed on a server")
MACRO_CONFIG_INT(SvMaxClientsPerIP, sv_max_clients_per_ip, 4, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum number of clients with the same IP that can connect to the server")
MACRO_CONFIG_INT(SvMapDownloadSpeed, sv_map_download_speed, 1, 2, 16, CFGFLAG_SERVER, "Number of map data packages a client gets on each request")
MACRO_CONFIG_INT(SvHighBandwidth, sv_high_bandwidth, 0, 0, 1, CFGFLAG_SERVER, "Use high bandwidth mode. Doubles the bandwidth required for the server. LAN use only")
MACRO_CONFIG_INT(SvRegister, sv_register, 1, 0, 1, CFGFLAG_SERVER, "Register server with master server for public listing")
MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remote console password (full access)")
Expand Down
31 changes: 18 additions & 13 deletions src/engine/shared/network.cpp
Expand Up @@ -161,7 +161,7 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct
// check the size
if(Size < NET_PACKETHEADERSIZE || Size > NET_MAX_PACKETSIZE)
{
dbg_msg("", "packet too small, %d", Size);
dbg_msg("network", "packet too small, %d", Size);
return -1;
}

Expand All @@ -177,15 +177,11 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct

// read the packet
pPacket->m_Flags = pBuffer[0]>>4;
pPacket->m_Ack = ((pBuffer[0]&0xf)<<8) | pBuffer[1];
pPacket->m_NumChunks = pBuffer[2];
pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE;

if(pPacket->m_Flags&NET_PACKETFLAG_CONNLESS)
{
if(Size < 6)
{
dbg_msg("", "connection less packet too small, %d", Size);
dbg_msg("network", "connection less packet too small, %d", Size);
return -1;
}

Expand All @@ -197,6 +193,15 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct
}
else
{
if(Size-NET_PACKETHEADERSIZE > NET_MAX_PAYLOAD)
{
dbg_msg("network", "packet too big, %d", Size);
return -1;
}

pPacket->m_Ack = ((pBuffer[0]&0xf)<<8) | pBuffer[1];
pPacket->m_NumChunks = pBuffer[2];
pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE;
if(pPacket->m_Flags&NET_PACKETFLAG_COMPRESSION)
pPacket->m_DataSize = ms_Huffman.Decompress(&pBuffer[3], pPacket->m_DataSize, pPacket->m_aChunkData, sizeof(pPacket->m_aChunkData));
else
Expand Down Expand Up @@ -244,25 +249,25 @@ void CNetBase::SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int Con

unsigned char *CNetChunkHeader::Pack(unsigned char *pData)
{
pData[0] = ((m_Flags&3)<<6)|((m_Size>>4)&0x3f);
pData[1] = (m_Size&0xf);
pData[0] = ((m_Flags&0x03)<<6) | ((m_Size>>6)&0x3F);
pData[1] = (m_Size&0x3F);
if(m_Flags&NET_CHUNKFLAG_VITAL)
{
pData[1] |= (m_Sequence>>2)&0xf0;
pData[2] = m_Sequence&0xff;
pData[1] |= (m_Sequence>>2)&0xC0;
pData[2] = m_Sequence&0xFF;
return pData + 3;
}
return pData + 2;
}

unsigned char *CNetChunkHeader::Unpack(unsigned char *pData)
{
m_Flags = (pData[0]>>6)&3;
m_Size = ((pData[0]&0x3f)<<4) | (pData[1]&0xf);
m_Flags = (pData[0]>>6)&0x03;
m_Size = ((pData[0]&0x3F)<<6) | (pData[1]&0x3F);
m_Sequence = -1;
if(m_Flags&NET_CHUNKFLAG_VITAL)
{
m_Sequence = ((pData[1]&0xf0)<<2) | pData[2];
m_Sequence = ((pData[1]&0xC0)<<2) | pData[2];
return pData + 3;
}
return pData + 2;
Expand Down

0 comments on commit c2e5771

Please sign in to comment.