Replace CInitMessage by more specific classes.

This commit is contained in:
joris 2013-04-01 12:54:48 +02:00
parent 829e03df97
commit 9e6958e19b
5 changed files with 676 additions and 272 deletions

View file

@ -51,8 +51,9 @@
class CNetworkHost class CNetworkHost
{ {
public: public:
const unsigned char *Serialize() const; CNetworkHost() { Clear(); }
void Deserialize(const unsigned char *p); size_t Serialize(unsigned char *) const;
size_t Deserialize(const unsigned char *p);
void Clear(); void Clear();
static size_t Size() { return 4 + 2 + 2 + NetPlayerNameSize; } static size_t Size() { return 4 + 2 + 2 + NetPlayerNameSize; }
@ -64,15 +65,15 @@ public:
char PlyName[NetPlayerNameSize]; /// Name of player char PlyName[NetPlayerNameSize]; /// Name of player
}; };
/** /**
** Multiplayer game setup menu state ** Multiplayer game setup menu state
*/ */
class CServerSetup class CServerSetup
{ {
public: public:
const unsigned char *Serialize() const; CServerSetup() { Clear(); }
void Deserialize(const unsigned char *p); size_t Serialize(unsigned char *p) const;
size_t Deserialize(const unsigned char *p);
static size_t Size() { return 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 * PlayerMax + 1 * PlayerMax + 1 * PlayerMax; } static size_t Size() { return 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 * PlayerMax + 1 * PlayerMax + 1 * PlayerMax; }
void Clear() { void Clear() {
ResourcesOption = 0; ResourcesOption = 0;
@ -111,7 +112,7 @@ enum _ic_message_subtype_ {
ICMEngineMismatch, /// Stratagus engine version doesn't match ICMEngineMismatch, /// Stratagus engine version doesn't match
ICMProtocolMismatch, /// Network protocol version doesn't match ICMProtocolMismatch, /// Network protocol version doesn't match
ICMEngineConfMismatch, /// Engine configuration isn't identical ICMEngineConfMismatch, /// UNUSED:Engine configuration isn't identical
ICMMapUidMismatch, /// MAP UID doesn't match ICMMapUidMismatch, /// MAP UID doesn't match
ICMGameFull, /// No player slots available ICMGameFull, /// No player slots available
@ -132,36 +133,145 @@ enum _ic_message_subtype_ {
ICMIAH /// Client answers I am here ICMIAH /// Client answers I am here
}; };
/** class CInitMessage_Header
** Network init message.
**
** @todo Transfering the same data in each message is waste of bandwidth.
** I mean the versions and the UID ...
*/
class CInitMessage
{ {
public: public:
CInitMessage(); CInitMessage_Header() {}
CInitMessage(uint8_t type, uint8_t subtype); CInitMessage_Header(unsigned char type, unsigned char subtype) :
type(type),
subtype(subtype)
{}
unsigned char GetType() const { return type; }
unsigned char GetSubType() const { return subtype; }
size_t Serialize(unsigned char *p) const;
size_t Deserialize(const unsigned char *p);
static size_t Size() { return 2; }
private:
unsigned char type;
unsigned char subtype;
};
class CInitMessage_Hello
{
public:
CInitMessage_Hello() {}
explicit CInitMessage_Hello(const char *name);
const CInitMessage_Header &GetHeader() const { return header; }
const unsigned char *Serialize() const; const unsigned char *Serialize() const;
void Deserialize(const unsigned char *p); void Deserialize(const unsigned char *p);
static size_t Size() { return 1 + 1 + 1 + 1 + 4 + 4 + 4 + 4 + 4 + 4 + std::max<size_t>(256u, std::max(CNetworkHost::Size() * PlayerMax, CServerSetup::Size())); } static size_t Size() { return CInitMessage_Header::Size() + NetPlayerNameSize + 2 * 4; }
private:
uint8_t Type; /// Init message type CInitMessage_Header header;
uint8_t SubType; /// Init message subtype public:
uint8_t HostsCount; /// Number of hosts char PlyName[NetPlayerNameSize]; /// Name of player
uint8_t padding; /// padding for alignment
int32_t Stratagus; /// Stratagus engine version int32_t Stratagus; /// Stratagus engine version
int32_t Version; /// Network protocol version int32_t Version; /// Network protocol version
uint32_t MapUID; /// UID of map to play. FIXME: add MAP name, path, etc };
class CInitMessage_Config
{
public:
CInitMessage_Config();
const CInitMessage_Header &GetHeader() const { return header; }
const unsigned char *Serialize() const;
void Deserialize(const unsigned char *p);
static size_t Size() { return CInitMessage_Header::Size() + 4 + PlayerMax * CNetworkHost::Size(); }
private:
CInitMessage_Header header;
public:
int32_t HostsCount; /// Number of hosts
CNetworkHost Hosts[PlayerMax]; /// Participant information
};
class CInitMessage_EngineMismatch
{
public:
CInitMessage_EngineMismatch();
const CInitMessage_Header &GetHeader() const { return header; }
const unsigned char *Serialize() const;
void Deserialize(const unsigned char *p);
static size_t Size() { return CInitMessage_Header::Size() + 4; }
private:
CInitMessage_Header header;
public:
int32_t Stratagus; /// Stratagus engine version
};
class CInitMessage_ProtocolMismatch
{
public:
CInitMessage_ProtocolMismatch();
const CInitMessage_Header &GetHeader() const { return header; }
const unsigned char *Serialize() const;
void Deserialize(const unsigned char *p);
static size_t Size() { return CInitMessage_Header::Size() + 4; }
private:
CInitMessage_Header header;
public:
int32_t Version; /// Network protocol version
};
class CInitMessage_Welcome
{
public:
CInitMessage_Welcome();
const CInitMessage_Header &GetHeader() const { return header; }
const unsigned char *Serialize() const;
void Deserialize(const unsigned char *p);
static size_t Size() { return CInitMessage_Header::Size() + PlayerMax * CNetworkHost::Size() + 2 * 4; }
private:
CInitMessage_Header header;
public:
CNetworkHost hosts[PlayerMax]; /// Participant information
int32_t Lag; /// Lag time int32_t Lag; /// Lag time
int32_t Updates; /// Update frequency int32_t Updates; /// Update frequency
};
union { class CInitMessage_Map
CNetworkHost Hosts[PlayerMax]; /// Participant information {
char MapPath[256]; public:
CServerSetup State; /// Server Setup State information CInitMessage_Map() {}
} u; CInitMessage_Map(const char *path, uint32_t mapUID);
const CInitMessage_Header &GetHeader() const { return header; }
const unsigned char *Serialize() const;
void Deserialize(const unsigned char *p);
static size_t Size() { return CInitMessage_Header::Size() + 256 + 4; }
private:
CInitMessage_Header header;
public:
char MapPath[256];
uint32_t MapUID; /// UID of map to play.
};
class CInitMessage_State
{
public:
CInitMessage_State() {}
CInitMessage_State(int type, const CServerSetup &data);
const CInitMessage_Header &GetHeader() const { return header; }
const unsigned char *Serialize() const;
void Deserialize(const unsigned char *p);
static size_t Size() { return CInitMessage_Header::Size() + CServerSetup::Size(); }
private:
CInitMessage_Header header;
public:
CServerSetup State; /// Server Setup State information
};
class CInitMessage_Resync
{
public:
CInitMessage_Resync();
const CInitMessage_Header &GetHeader() const { return header; }
const unsigned char *Serialize() const;
void Deserialize(const unsigned char *p);
static size_t Size() { return CInitMessage_Header::Size() + CNetworkHost::Size() * PlayerMax; }
private:
CInitMessage_Header header;
public:
CNetworkHost hosts[PlayerMax]; /// Participant information
}; };
/** /**

View file

@ -31,7 +31,6 @@
//@{ //@{
#include <stdint.h>
#include "net_message.h" #include "net_message.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------

View file

@ -84,6 +84,14 @@ int serialize8(unsigned char *buf, int8_t data)
} }
return sizeof(data); return sizeof(data);
} }
template <int N>
int serialize(unsigned char *buf, const char (&data)[N])
{
if (buf) {
memcpy(buf, data, N);
}
return N;
}
int deserialize32(const unsigned char *buf, uint32_t *data) int deserialize32(const unsigned char *buf, uint32_t *data)
{ {
@ -115,30 +123,38 @@ int deserialize8(const unsigned char *buf, int8_t *data)
*data = *buf; *data = *buf;
return sizeof(*data); return sizeof(*data);
} }
template <int N>
int deserialize(const unsigned char *buf, char (&data)[N])
{
memcpy(data, buf, N);
return N;
}
// //
// CNetworkHost // CNetworkHost
// //
const unsigned char *CNetworkHost::Serialize() const size_t CNetworkHost::Serialize(unsigned char *buf) const
{ {
unsigned char *buf = new unsigned char[CNetworkHost::Size()];
unsigned char *p = buf; unsigned char *p = buf;
p += serialize32(p, this->Host); p += serialize32(p, this->Host);
p += serialize16(p, this->Port); p += serialize16(p, this->Port);
p += serialize16(p, this->PlyNr); p += serialize16(p, this->PlyNr);
memcpy(p, this->PlyName, sizeof(this->PlyName)); p += serialize(p, this->PlyName);
return buf; return p - buf;
} }
void CNetworkHost::Deserialize(const unsigned char *p) size_t CNetworkHost::Deserialize(const unsigned char *p)
{ {
const unsigned char *buf = p;
p += deserialize32(p, &Host); p += deserialize32(p, &Host);
p += deserialize16(p, &Port); p += deserialize16(p, &Port);
p += deserialize16(p, &PlyNr); p += deserialize16(p, &PlyNr);
memcpy(this->PlyName, p, sizeof(this->PlyName)); p += deserialize(p, this->PlyName);
return p - buf;
} }
void CNetworkHost::Clear() void CNetworkHost::Clear()
@ -158,9 +174,8 @@ void CNetworkHost::SetName(const char *name)
// CServerSetup // CServerSetup
// //
const unsigned char *CServerSetup::Serialize() const size_t CServerSetup::Serialize(unsigned char *buf) const
{ {
unsigned char *buf = new unsigned char[CServerSetup::Size()];
unsigned char *p = buf; unsigned char *p = buf;
p += serialize8(p, this->ResourcesOption); p += serialize8(p, this->ResourcesOption);
@ -180,11 +195,12 @@ const unsigned char *CServerSetup::Serialize() const
for (int i = 0; i < PlayerMax; ++i) { for (int i = 0; i < PlayerMax; ++i) {
p += serialize8(p, this->Race[i]); p += serialize8(p, this->Race[i]);
} }
return buf; return p - buf;
} }
void CServerSetup::Deserialize(const unsigned char *p) size_t CServerSetup::Deserialize(const unsigned char *p)
{ {
const unsigned char *buf = p;
p += deserialize8(p, &this->ResourcesOption); p += deserialize8(p, &this->ResourcesOption);
p += deserialize8(p, &this->UnitsOption); p += deserialize8(p, &this->UnitsOption);
p += deserialize8(p, &this->FogOfWar); p += deserialize8(p, &this->FogOfWar);
@ -202,101 +218,260 @@ void CServerSetup::Deserialize(const unsigned char *p)
for (int i = 0; i < PlayerMax; ++i) { for (int i = 0; i < PlayerMax; ++i) {
p += deserialize8(p, &this->Race[i]); p += deserialize8(p, &this->Race[i]);
} }
return p - buf;
} }
// //
// CInitMessage // CInitMessage_Header
// //
CInitMessage::CInitMessage() size_t CInitMessage_Header::Serialize(unsigned char *p) const
{ {
memset(this, 0, sizeof(CInitMessage)); unsigned char *buf = p;
p += serialize8(p, type);
p += serialize8(p, subtype);
return p - buf;
} }
CInitMessage::CInitMessage(uint8_t type, uint8_t subtype) size_t CInitMessage_Header::Deserialize(const unsigned char *p)
{ {
this->Type = type; const unsigned char *buf = p;
this->SubType = subtype; p += deserialize8(p, &type);
p += deserialize8(p, &subtype);
return p - buf;
}
//
// CInitMessage_Hello
//
CInitMessage_Hello::CInitMessage_Hello(const char *name) :
header(MessageInit_FromClient, ICMHello)
{
strncpy_s(this->PlyName, sizeof(this->PlyName), name, _TRUNCATE);
this->Stratagus = StratagusVersion; this->Stratagus = StratagusVersion;
this->Version = NetworkProtocolVersion; this->Version = NetworkProtocolVersion;
this->Lag = NetworkLag;
this->Updates = NetworkUpdates;
} }
const unsigned char *CInitMessage::Serialize() const const unsigned char *CInitMessage_Hello::Serialize() const
{ {
unsigned char *buf = new unsigned char[CInitMessage::Size()]; unsigned char *buf = new unsigned char[Size()];
unsigned char *p = buf; unsigned char *p = buf;
p += serialize8(p, this->Type); p += header.Serialize(p);
p += serialize8(p, this->SubType); p += serialize(p, this->PlyName);
p += serialize8(p, this->HostsCount);
p += serialize8(p, this->padding);
p += serialize32(p, this->Stratagus); p += serialize32(p, this->Stratagus);
p += serialize32(p, this->Version); p += serialize32(p, this->Version);
p += serialize32(p, this->MapUID); return buf;
p += serialize32(p, this->Lag); }
p += serialize32(p, this->Updates);
switch (this->SubType) { void CInitMessage_Hello::Deserialize(const unsigned char *p)
case ICMHello: {
case ICMConfig: p += header.Deserialize(p);
case ICMWelcome: p += deserialize(p, this->PlyName);
case ICMResync: p += deserialize32(p, &this->Stratagus);
case ICMGo: p += deserialize32(p, &this->Version);
for (int i = 0; i < PlayerMax; ++i) { }
const unsigned char *x = this->u.Hosts[i].Serialize();
memcpy(p, x, CNetworkHost::Size()); //
p += CNetworkHost::Size(); // CInitMessage_Config
delete[] x; //
}
break; CInitMessage_Config::CInitMessage_Config() :
case ICMMap: header(MessageInit_FromServer, ICMConfig)
memcpy(p, this->u.MapPath, sizeof(this->u.MapPath)); {
p += sizeof(this->u.MapPath); }
break;
case ICMState: { const unsigned char *CInitMessage_Config::Serialize() const
const unsigned char *x = this->u.State.Serialize(); {
memcpy(p, x, CServerSetup::Size()); unsigned char *buf = new unsigned char[Size()];
p += CServerSetup::Size(); unsigned char *p = buf;
delete[] x;
break; p += header.Serialize(p);
} p += serialize32(p, this->HostsCount);
for (int i = 0; i != PlayerMax; ++i) {
p += this->Hosts[i].Serialize(p);
} }
return buf; return buf;
} }
void CInitMessage::Deserialize(const unsigned char *p) void CInitMessage_Config::Deserialize(const unsigned char *p)
{ {
p += deserialize8(p, &this->Type); p += header.Deserialize(p);
p += deserialize8(p, &this->SubType); p += deserialize32(p, &this->HostsCount);
p += deserialize8(p, &this->HostsCount); for (int i = 0; i != PlayerMax; ++i) {
p += deserialize8(p, &this->padding); p += this->Hosts[i].Deserialize(p);
}
}
//
// CInitMessage_EngineMismatch
//
CInitMessage_EngineMismatch::CInitMessage_EngineMismatch() :
header(MessageInit_FromServer, ICMEngineMismatch)
{
this->Stratagus = StratagusVersion;
}
const unsigned char *CInitMessage_EngineMismatch::Serialize() const
{
unsigned char *buf = new unsigned char[Size()];
unsigned char *p = buf;
p += header.Serialize(p);
p += serialize32(p, this->Stratagus);
return buf;
}
void CInitMessage_EngineMismatch::Deserialize(const unsigned char *p)
{
p += header.Deserialize(p);
p += deserialize32(p, &this->Stratagus); p += deserialize32(p, &this->Stratagus);
}
//
// CInitMessage_ProtocolMismatch
//
CInitMessage_ProtocolMismatch::CInitMessage_ProtocolMismatch() :
header(MessageInit_FromServer, ICMProtocolMismatch)
{
this->Version = NetworkProtocolVersion;
}
const unsigned char *CInitMessage_ProtocolMismatch::Serialize() const
{
unsigned char *buf = new unsigned char[Size()];
unsigned char *p = buf;
p += header.Serialize(p);
p += serialize32(p, this->Version);
return buf;
}
void CInitMessage_ProtocolMismatch::Deserialize(const unsigned char *p)
{
p += header.Deserialize(p);
p += deserialize32(p, &this->Version); p += deserialize32(p, &this->Version);
p += deserialize32(p, &this->MapUID); }
//
// CInitMessage_Welcome
//
CInitMessage_Welcome::CInitMessage_Welcome() :
header(MessageInit_FromServer, ICMWelcome)
{
this->Lag = NetworkLag;
this->Updates = NetworkUpdates;
}
const unsigned char *CInitMessage_Welcome::Serialize() const
{
unsigned char *buf = new unsigned char[Size()];
unsigned char *p = buf;
p += header.Serialize(p);
for (int i = 0; i < PlayerMax; ++i) {
p += this->hosts[i].Serialize(p);
}
p += serialize32(p, this->Lag);
p += serialize32(p, this->Updates);
return buf;
}
void CInitMessage_Welcome::Deserialize(const unsigned char *p)
{
p += header.Deserialize(p);
for (int i = 0; i < PlayerMax; ++i) {
p += this->hosts[i].Deserialize(p);
}
p += deserialize32(p, &this->Lag); p += deserialize32(p, &this->Lag);
p += deserialize32(p, &this->Updates); p += deserialize32(p, &this->Updates);
}
switch (this->SubType) { //
case ICMHello: // CInitMessage_Map
case ICMConfig: //
case ICMWelcome:
case ICMResync: CInitMessage_Map::CInitMessage_Map(const char *path, uint32_t mapUID) :
case ICMGo: header(MessageInit_FromServer, ICMMap),
for (int i = 0; i < PlayerMax; ++i) { MapUID(mapUID)
this->u.Hosts[i].Deserialize(p); {
p += CNetworkHost::Size(); strncpy_s(MapPath, sizeof(MapPath), path, _TRUNCATE);
} }
break;
case ICMMap: const unsigned char *CInitMessage_Map::Serialize() const
memcpy(this->u.MapPath, p, sizeof(this->u.MapPath)); {
p += sizeof(this->u.MapPath); unsigned char *buf = new unsigned char[Size()];
break; unsigned char *p = buf;
case ICMState:
this->u.State.Deserialize(p); p += header.Serialize(p);
p += CServerSetup::Size(); p += serialize(p, MapPath);
break; p += serialize32(p, this->MapUID);
return buf;
}
void CInitMessage_Map::Deserialize(const unsigned char *p)
{
p += header.Deserialize(p);
p += deserialize(p, this->MapPath);
p += deserialize32(p, &this->MapUID);
}
//
// CInitMessage_State
//
CInitMessage_State::CInitMessage_State(int type, const CServerSetup &data) :
header(type, ICMState),
State(data)
{
}
const unsigned char *CInitMessage_State::Serialize() const
{
unsigned char *buf = new unsigned char[Size()];
unsigned char *p = buf;
p += header.Serialize(p);
p += this->State.Serialize(p);
return buf;
}
void CInitMessage_State::Deserialize(const unsigned char *p)
{
p += header.Deserialize(p);
p += this->State.Deserialize(p);
}
//
// CInitMessage_Resync
//
CInitMessage_Resync::CInitMessage_Resync() :
header(MessageInit_FromServer, ICMResync)
{
}
const unsigned char *CInitMessage_Resync::Serialize() const
{
unsigned char *buf = new unsigned char[Size()];
unsigned char *p = buf;
p += header.Serialize(p);
for (int i = 0; i < PlayerMax; ++i) {
p += this->hosts[i].Serialize(p);
}
return buf;
}
void CInitMessage_Resync::Deserialize(const unsigned char *p)
{
p += header.Deserialize(p);
for (int i = 0; i < PlayerMax; ++i) {
p += this->hosts[i].Deserialize(p);
} }
} }

View file

@ -104,11 +104,11 @@ public:
void MarkClientsAsResync(); void MarkClientsAsResync();
void KickClient(int c); void KickClient(int c);
private: private:
int Parse_Hello(int h, const CInitMessage &msg, unsigned long host, int port); int Parse_Hello(int h, const CInitMessage_Hello &msg, unsigned long host, int port);
void Parse_Resync(const int h); void Parse_Resync(const int h);
void Parse_Waiting(const int h); void Parse_Waiting(const int h);
void Parse_Map(const int h); void Parse_Map(const int h);
void Parse_State(const int h, const CInitMessage &msg); void Parse_State(const int h, const CInitMessage_State &msg);
void Parse_GoodBye(const int h); void Parse_GoodBye(const int h);
void Parse_SeeYou(const int h); void Parse_SeeYou(const int h);
@ -162,11 +162,12 @@ private:
void Send_Hello(unsigned long tick); void Send_Hello(unsigned long tick);
void Send_GoodBye(unsigned long tick); void Send_GoodBye(unsigned long tick);
void NetworkSendRateLimitedClientMessage(const CInitMessage &msg, unsigned long tick, unsigned long msecs); template <typename T>
void SendRateLimited(const T &msg, unsigned long tick, unsigned long msecs);
void NetClientCheckLocalState(); void NetClientCheckLocalState();
void SetConfig(const CInitMessage &msg, unsigned long host, int port); void SetConfig(const CInitMessage_Config &msg, unsigned long host, int port);
void SetState(const CInitMessage &msg); void SetState(const CInitMessage_State &msg);
void Parse_GameFull(); void Parse_GameFull();
void Parse_ProtocolMismatch(const unsigned char *buf); void Parse_ProtocolMismatch(const unsigned char *buf);
@ -198,14 +199,20 @@ static CClient Client;
** @param host Host to send to (network byte order). ** @param host Host to send to (network byte order).
** @param port Port of host to send to (network byte order). ** @param port Port of host to send to (network byte order).
** @param msg The message to send ** @param msg The message to send
**
** @todo FIXME: we don't need to put the header into all messages.
** (header = msg->Stratagus ... )
*/ */
static void NetworkSendICMessage(unsigned long host, int port, const CInitMessage &msg) template <typename T>
static void NetworkSendICMessage(unsigned long host, int port, const T &msg)
{ {
const unsigned char *buf = msg.Serialize(); const unsigned char *buf = msg.Serialize();
NetSendUDP(NetworkFildes, host, port, buf, CInitMessage::Size()); NetSendUDP(NetworkFildes, host, port, buf, msg.Size());
delete[] buf;
}
void NetworkSendICMessage(unsigned long host, int port, const CInitMessage_Header &msg)
{
unsigned char *buf = new unsigned char [msg.Size()];
msg.Serialize(buf);
NetSendUDP(NetworkFildes, host, port, buf, msg.Size());
delete[] buf; delete[] buf;
} }
@ -258,13 +265,23 @@ static const char *icmsgsubtypenames[] = {
}; };
#endif #endif
static void NetworkSendICMessage_Log(unsigned long ip, int port, const CInitMessage &msg) template <typename T>
static void NetworkSendICMessage_Log(unsigned long ip, int port, const T &msg)
{ {
NetworkSendICMessage(ip, port, msg); NetworkSendICMessage(ip, port, msg);
DebugPrint("Sending to %d.%d.%d.%d:%d -> %s\n" DebugPrint("Sending to %d.%d.%d.%d:%d -> %s\n"
_C_ NIPQUAD(ntohl(ip)) _C_ ntohs(port) _C_ NIPQUAD(ntohl(ip)) _C_ ntohs(port)
_C_ icmsgsubtypenames[msg.SubType]); _C_ icmsgsubtypenames[msg.GetHeader().GetSubType()]);
}
static void NetworkSendICMessage_Log(unsigned long ip, int port, const CInitMessage_Header &msg)
{
NetworkSendICMessage(ip, port, msg);
DebugPrint("Sending to %d.%d.%d.%d:%d -> %s\n"
_C_ NIPQUAD(ntohl(ip)) _C_ ntohs(port)
_C_ icmsgsubtypenames[msg.GetSubType()]);
} }
/** /**
@ -274,23 +291,46 @@ static void NetworkSendICMessage_Log(unsigned long ip, int port, const CInitMess
** @param tick current tick ** @param tick current tick
** @param msecs microseconds to delay ** @param msecs microseconds to delay
*/ */
void CClient::NetworkSendRateLimitedClientMessage(const CInitMessage &msg, unsigned long tick, unsigned long msecs) template <typename T>
void CClient::SendRateLimited(const T &msg, unsigned long tick, unsigned long msecs)
{ {
const unsigned long now = tick; const unsigned long now = tick;
if (now - networkState.LastFrame < msecs) { if (now - networkState.LastFrame < msecs) {
return; return;
} }
networkState.LastFrame = now; networkState.LastFrame = now;
if (msg.SubType == lastMsgTypeSent) { const unsigned char subtype = msg.GetHeader().GetSubType();
if (subtype == lastMsgTypeSent) {
++networkState.MsgCnt; ++networkState.MsgCnt;
} else { } else {
networkState.MsgCnt = 0; networkState.MsgCnt = 0;
lastMsgTypeSent = msg.SubType; lastMsgTypeSent = subtype;
} }
NetworkSendICMessage(serverIP, serverPort, msg); NetworkSendICMessage(serverIP, serverPort, msg);
DebugPrint("[%s] Sending (%s:#%d)\n" _C_ DebugPrint("[%s] Sending (%s:#%d)\n" _C_
ncconstatenames[networkState.State] _C_ ncconstatenames[networkState.State] _C_
icmsgsubtypenames[msg.SubType] _C_ networkState.MsgCnt); icmsgsubtypenames[subtype] _C_ networkState.MsgCnt);
}
template<>
void CClient::SendRateLimited<CInitMessage_Header>(const CInitMessage_Header &msg, unsigned long tick, unsigned long msecs)
{
const unsigned long now = tick;
if (now - networkState.LastFrame < msecs) {
return;
}
networkState.LastFrame = now;
const unsigned char subtype = msg.GetSubType();
if (subtype == lastMsgTypeSent) {
++networkState.MsgCnt;
} else {
networkState.MsgCnt = 0;
lastMsgTypeSent = subtype;
}
NetworkSendICMessage(serverIP, serverPort, msg);
DebugPrint("[%s] Sending (%s:#%d)\n" _C_
ncconstatenames[networkState.State] _C_
icmsgsubtypenames[subtype] _C_ networkState.MsgCnt);
} }
bool CClient::SetupServerAddress(const std::string &serveraddr, int port) bool CClient::SetupServerAddress(const std::string &serveraddr, int port)
@ -339,7 +379,7 @@ void CClient::NetClientCheckLocalState()
bool CClient::Update_disconnected() bool CClient::Update_disconnected()
{ {
Assert(networkState.State == ccs_disconnected); Assert(networkState.State == ccs_disconnected);
const CInitMessage message(MessageInit_FromClient, ICMSeeYou); const CInitMessage_Header message(MessageInit_FromClient, ICMSeeYou);
// Spew out 5 and trust in God that they arrive // Spew out 5 and trust in God that they arrive
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
@ -489,69 +529,65 @@ bool CClient::Update_started(unsigned long tick)
void CClient::Send_Go(unsigned long tick) void CClient::Send_Go(unsigned long tick)
{ {
const CInitMessage message(MessageInit_FromClient, ICMGo); const CInitMessage_Header message(MessageInit_FromClient, ICMGo);
NetworkSendRateLimitedClientMessage(message, tick, 250); SendRateLimited(message, tick, 250);
} }
void CClient::Send_Config(unsigned long tick) void CClient::Send_Config(unsigned long tick)
{ {
const CInitMessage message(MessageInit_FromClient, ICMConfig); const CInitMessage_Header message(MessageInit_FromClient, ICMConfig);
NetworkSendRateLimitedClientMessage(message, tick, 250); SendRateLimited(message, tick, 250);
} }
void CClient::Send_MapUidMismatch(unsigned long tick) void CClient::Send_MapUidMismatch(unsigned long tick)
{ {
CInitMessage message(MessageInit_FromClient, ICMMapUidMismatch); const CInitMessage_Header message(MessageInit_FromClient, ICMMapUidMismatch); // MAP Uid doesn't match
message.MapUID = Map.Info.MapUID; // MAP Uid doesn't match SendRateLimited(message, tick, 650);
NetworkSendRateLimitedClientMessage(message, tick, 650);
} }
void CClient::Send_Map(unsigned long tick) void CClient::Send_Map(unsigned long tick)
{ {
CInitMessage message(MessageInit_FromClient, ICMMap); CInitMessage_Header message(MessageInit_FromClient, ICMMap);
message.MapUID = Map.Info.MapUID; SendRateLimited(message, tick, 650);
NetworkSendRateLimitedClientMessage(message, tick, 650);
} }
void CClient::Send_Resync(unsigned long tick) void CClient::Send_Resync(unsigned long tick)
{ {
const CInitMessage message(MessageInit_FromClient, ICMResync); const CInitMessage_Header message(MessageInit_FromClient, ICMResync);
NetworkSendRateLimitedClientMessage(message, tick, 450); SendRateLimited(message, tick, 450);
} }
void CClient::Send_State(unsigned long tick) void CClient::Send_State(unsigned long tick)
{ {
CInitMessage message(MessageInit_FromClient, ICMState); const CInitMessage_State message(MessageInit_FromClient, LocalSetupState);
message.u.State = LocalSetupState; SendRateLimited(message, tick, 450);
message.MapUID = Map.Info.MapUID;
NetworkSendRateLimitedClientMessage(message, tick, 450);
} }
void CClient::Send_Waiting(unsigned long tick, unsigned long msec) void CClient::Send_Waiting(unsigned long tick, unsigned long msec)
{ {
const CInitMessage message(MessageInit_FromClient, ICMWaiting); const CInitMessage_Header message(MessageInit_FromClient, ICMWaiting);
NetworkSendRateLimitedClientMessage(message, tick, msec);
SendRateLimited(message, tick, msec);
} }
void CClient::Send_Hello(unsigned long tick) void CClient::Send_Hello(unsigned long tick)
{ {
CInitMessage message(MessageInit_FromClient, ICMHello); const CInitMessage_Hello message(Parameters::Instance.LocalPlayerName.c_str());
message.u.Hosts[0].SetName(Parameters::Instance.LocalPlayerName.c_str()); SendRateLimited(message, tick, 500);
NetworkSendRateLimitedClientMessage(message, tick, 500);
} }
void CClient::Send_GoodBye(unsigned long tick) void CClient::Send_GoodBye(unsigned long tick)
{ {
const CInitMessage message(MessageInit_FromClient, ICMGoodBye); const CInitMessage_Header message(MessageInit_FromClient, ICMGoodBye);
NetworkSendRateLimitedClientMessage(message, tick, 100); SendRateLimited(message, tick, 100);
} }
/* /*
@ -576,42 +612,42 @@ bool CClient::Update(unsigned long tick)
return true; return true;
} }
void CClient::SetState(const CInitMessage &msg) void CClient::SetState(const CInitMessage_State &msg)
{ {
ServerSetupState = msg.u.State; ServerSetupState = msg.State;
} }
void CClient::SetConfig(const CInitMessage &msg, unsigned long host, int port) void CClient::SetConfig(const CInitMessage_Config &msg, unsigned long host, int port)
{ {
HostsCount = 0; HostsCount = 0;
for (int i = 0; i < msg.HostsCount - 1; ++i) { for (int i = 0; i < msg.HostsCount - 1; ++i) {
if (msg.u.Hosts[i].Host || msg.u.Hosts[i].Port) { if (msg.Hosts[i].Host || msg.Hosts[i].Port) {
Hosts[HostsCount] = msg.u.Hosts[i]; Hosts[HostsCount] = msg.Hosts[i];
HostsCount++; HostsCount++;
DebugPrint("Client %d = %d.%d.%d.%d:%d [%.*s]\n" _C_ DebugPrint("Client %d = %d.%d.%d.%d:%d [%.*s]\n" _C_
msg.u.Hosts[i].PlyNr _C_ NIPQUAD(ntohl(msg.u.Hosts[i].Host)) _C_ msg.Hosts[i].PlyNr _C_ NIPQUAD(ntohl(msg.Hosts[i].Host)) _C_
ntohs(msg.u.Hosts[i].Port) _C_ ntohs(msg.Hosts[i].Port) _C_
static_cast<int>(sizeof(msg.u.Hosts[i].PlyName)) _C_ static_cast<int>(sizeof(msg.Hosts[i].PlyName)) _C_
msg.u.Hosts[i].PlyName); msg.Hosts[i].PlyName);
} else { // Own client } else { // Own client
NetLocalPlayerNumber = msg.u.Hosts[i].PlyNr; NetLocalPlayerNumber = msg.Hosts[i].PlyNr;
DebugPrint("SELF %d [%.*s]\n" _C_ msg.u.Hosts[i].PlyNr _C_ DebugPrint("SELF %d [%.*s]\n" _C_ msg.Hosts[i].PlyNr _C_
static_cast<int>(sizeof(msg.u.Hosts[i].PlyName)) _C_ static_cast<int>(sizeof(msg.Hosts[i].PlyName)) _C_
msg.u.Hosts[i].PlyName); msg.Hosts[i].PlyName);
} }
} }
// server is last: // server is last:
Hosts[HostsCount].Host = host; Hosts[HostsCount].Host = host;
Hosts[HostsCount].Port = port; Hosts[HostsCount].Port = port;
Hosts[HostsCount].PlyNr = msg.u.Hosts[msg.HostsCount - 1].PlyNr; Hosts[HostsCount].PlyNr = msg.Hosts[msg.HostsCount - 1].PlyNr;
Hosts[HostsCount].SetName(msg.u.Hosts[msg.HostsCount - 1].PlyName); Hosts[HostsCount].SetName(msg.Hosts[msg.HostsCount - 1].PlyName);
++HostsCount; ++HostsCount;
NetPlayers = HostsCount + 1; NetPlayers = HostsCount + 1;
DebugPrint("Server %d = %d.%d.%d.%d:%d [%.*s]\n" _C_ DebugPrint("Server %d = %d.%d.%d.%d:%d [%.*s]\n" _C_
msg.u.Hosts[msg.HostsCount - 1].PlyNr _C_ NIPQUAD(ntohl(host)) _C_ msg.Hosts[msg.HostsCount - 1].PlyNr _C_ NIPQUAD(ntohl(host)) _C_
ntohs(port) _C_ ntohs(port) _C_
static_cast<int>(sizeof(msg.u.Hosts[msg.HostsCount - 1].PlyName)) _C_ static_cast<int>(sizeof(msg.Hosts[msg.HostsCount - 1].PlyName)) _C_
msg.u.Hosts[msg.HostsCount - 1].PlyName); msg.Hosts[msg.HostsCount - 1].PlyName);
// put ourselves to the end, like on the server.. // put ourselves to the end, like on the server..
Hosts[HostsCount].Host = 0; Hosts[HostsCount].Host = 0;
@ -622,14 +658,15 @@ void CClient::SetConfig(const CInitMessage &msg, unsigned long host, int port)
bool CClient::Parse(const unsigned char *buf, unsigned long host, int port) bool CClient::Parse(const unsigned char *buf, unsigned long host, int port)
{ {
const unsigned char msgtype = buf[0]; CInitMessage_Header header;
header.Deserialize(buf);
if (msgtype != MessageInit_FromServer) { if (header.GetType() != MessageInit_FromServer) {
return true; return true;
} }
// Assert(host == this->serverIP); // Assert(host == this->serverIP);
// Assert(port == this->serverPort); // Assert(port == this->serverPort);
const unsigned char msgsubtype = buf[1]; const unsigned char msgsubtype = header.GetSubType();
DebugPrint("Received %s in state %s\n" _C_ icmsgsubtypenames[msgsubtype] DebugPrint("Received %s in state %s\n" _C_ icmsgsubtypenames[msgsubtype]
_C_ ncconstatenames[networkState.State]); _C_ ncconstatenames[networkState.State]);
@ -733,15 +770,15 @@ void CClient::Parse_Map(const unsigned char *buf)
if (networkState.State != ccs_connected) { if (networkState.State != ccs_connected) {
return; return;
} }
CInitMessage msg; CInitMessage_Map msg;
msg.Deserialize(buf); msg.Deserialize(buf);
if (!IsSafeMapName(msg.u.MapPath)) { if (!IsSafeMapName(msg.MapPath)) {
fprintf(stderr, "Unsecure map name!\n"); fprintf(stderr, "Unsecure map name!\n");
networkState.State = ccs_badmap; networkState.State = ccs_badmap;
return; return;
} }
NetworkMapName = std::string(msg.u.MapPath, sizeof(msg.u.MapPath)); NetworkMapName = std::string(msg.MapPath, sizeof(msg.MapPath));
std::string mappath = StratagusLibPath + "/" + NetworkMapName; std::string mappath = StratagusLibPath + "/" + NetworkMapName;
LoadStratagusMapInfo(mappath); LoadStratagusMapInfo(mappath);
if (msg.MapUID != Map.Info.MapUID) { if (msg.MapUID != Map.Info.MapUID) {
@ -759,13 +796,13 @@ void CClient::Parse_Welcome(const unsigned char *buf)
if (networkState.State != ccs_connecting) { if (networkState.State != ccs_connecting) {
return; return;
} }
CInitMessage msg; CInitMessage_Welcome msg;
msg.Deserialize(buf); msg.Deserialize(buf);
networkState.State = ccs_connected; networkState.State = ccs_connected;
networkState.MsgCnt = 0; networkState.MsgCnt = 0;
NetLocalHostsSlot = msg.u.Hosts[0].PlyNr; NetLocalHostsSlot = msg.hosts[0].PlyNr;
Hosts[0].SetName(msg.u.Hosts[0].PlyName); // Name of server player Hosts[0].SetName(msg.hosts[0].PlyName); // Name of server player
NetworkLag = msg.Lag; NetworkLag = msg.Lag;
NetworkUpdates = msg.Updates; NetworkUpdates = msg.Updates;
@ -773,7 +810,7 @@ void CClient::Parse_Welcome(const unsigned char *buf)
Hosts[0].Port = serverPort; Hosts[0].Port = serverPort;
for (int i = 1; i < PlayerMax; ++i) { for (int i = 1; i < PlayerMax; ++i) {
if (i != NetLocalHostsSlot) { if (i != NetLocalHostsSlot) {
Hosts[i] = msg.u.Hosts[i]; Hosts[i] = msg.hosts[i];
} else { } else {
Hosts[i].PlyNr = i; Hosts[i].PlyNr = i;
Hosts[i].SetName(Parameters::Instance.LocalPlayerName.c_str()); Hosts[i].SetName(Parameters::Instance.LocalPlayerName.c_str());
@ -783,7 +820,7 @@ void CClient::Parse_Welcome(const unsigned char *buf)
void CClient::Parse_State(const unsigned char *buf) void CClient::Parse_State(const unsigned char *buf)
{ {
CInitMessage msg; CInitMessage_State msg;
msg.Deserialize(buf); msg.Deserialize(buf);
if (networkState.State == ccs_mapinfo) { if (networkState.State == ccs_mapinfo) {
@ -809,7 +846,7 @@ void CClient::Parse_Config(const unsigned char *buf, unsigned long ip, int port)
if (networkState.State != ccs_synced) { if (networkState.State != ccs_synced) {
return; return;
} }
CInitMessage msg; CInitMessage_Config msg;
msg.Deserialize(buf); msg.Deserialize(buf);
SetConfig(msg, ip, port); SetConfig(msg, ip, port);
@ -822,14 +859,14 @@ void CClient::Parse_Resync(const unsigned char *buf)
if (networkState.State != ccs_async) { if (networkState.State != ccs_async) {
return; return;
} }
CInitMessage msg; CInitMessage_Resync msg;
msg.Deserialize(buf); msg.Deserialize(buf);
for (int i = 1; i < PlayerMax - 1; ++i) { for (int i = 1; i < PlayerMax - 1; ++i) {
if (i != NetLocalHostsSlot) { if (i != NetLocalHostsSlot) {
Hosts[i] = msg.u.Hosts[i]; Hosts[i] = msg.hosts[i];
} else { } else {
Hosts[i].PlyNr = msg.u.Hosts[i].PlyNr; Hosts[i].PlyNr = msg.hosts[i].PlyNr;
Hosts[i].SetName(Parameters::Instance.LocalPlayerName.c_str()); Hosts[i].SetName(Parameters::Instance.LocalPlayerName.c_str());
} }
} }
@ -852,7 +889,7 @@ void CClient::Parse_ProtocolMismatch(const unsigned char *buf)
if (networkState.State != ccs_connecting) { if (networkState.State != ccs_connecting) {
return; return;
} }
CInitMessage msg; CInitMessage_ProtocolMismatch msg;
msg.Deserialize(buf); msg.Deserialize(buf);
fprintf(stderr, "Incompatible network protocol version " fprintf(stderr, "Incompatible network protocol version "
@ -868,7 +905,7 @@ void CClient::Parse_EngineMismatch(const unsigned char *buf)
if (networkState.State != ccs_connecting) { if (networkState.State != ccs_connecting) {
return; return;
} }
CInitMessage msg; CInitMessage_EngineMismatch msg;
msg.Deserialize(buf); msg.Deserialize(buf);
fprintf(stderr, "Incompatible Stratagus version %d <-> %d\n" fprintf(stderr, "Incompatible Stratagus version %d <-> %d\n"
@ -885,7 +922,7 @@ void CClient::Parse_EngineMismatch(const unsigned char *buf)
*/ */
void CClient::Parse_AreYouThere() void CClient::Parse_AreYouThere()
{ {
const CInitMessage message(MessageInit_FromClient, ICMIAH); // IAmHere const CInitMessage_Header message(MessageInit_FromClient, ICMIAH); // IAmHere
NetworkSendICMessage(serverIP, serverPort, message); NetworkSendICMessage(serverIP, serverPort, message);
} }
@ -930,31 +967,27 @@ void CServer::Init()
void CServer::Send_AreYouThere(const CNetworkHost &host) void CServer::Send_AreYouThere(const CNetworkHost &host)
{ {
const CInitMessage message(MessageInit_FromServer, ICMAYT); // AreYouThere const CInitMessage_Header message(MessageInit_FromServer, ICMAYT); // AreYouThere
NetworkSendICMessage(host.Host, host.Port, message); NetworkSendICMessage(host.Host, host.Port, message);
} }
void CServer::Send_GameFull(unsigned long host, int port) void CServer::Send_GameFull(unsigned long host, int port)
{ {
const CInitMessage message(MessageInit_FromServer, ICMGameFull); const CInitMessage_Header message(MessageInit_FromServer, ICMGameFull);
NetworkSendICMessage_Log(host, port, message); NetworkSendICMessage_Log(host, port, message);
} }
void CServer::Send_Welcome(const CNetworkHost &host, int index) void CServer::Send_Welcome(const CNetworkHost &host, int index)
{ {
CInitMessage message(MessageInit_FromServer, ICMWelcome); CInitMessage_Welcome message;
message.u.Hosts[0].PlyNr = index; // Host array slot number message.hosts[0].PlyNr = index; // Host array slot number
message.u.Hosts[0].SetName(Parameters::Instance.LocalPlayerName.c_str()); // Name of server player message.hosts[0].SetName(Parameters::Instance.LocalPlayerName.c_str()); // Name of server player
for (int i = 1; i < PlayerMax - 1; ++i) { // Info about other clients for (int i = 1; i < PlayerMax - 1; ++i) { // Info about other clients
if (i != index) { if (i != index && Hosts[i].PlyNr) {
if (Hosts[i].PlyNr) { message.hosts[i] = Hosts[i];
message.u.Hosts[i] = Hosts[i];
} else {
message.u.Hosts[i].Clear();
}
} }
} }
NetworkSendICMessage_Log(host.Host, host.Port, message); NetworkSendICMessage_Log(host.Host, host.Port, message);
@ -962,15 +995,11 @@ void CServer::Send_Welcome(const CNetworkHost &host, int index)
void CServer::Send_Resync(const CNetworkHost &host, int hostIndex) void CServer::Send_Resync(const CNetworkHost &host, int hostIndex)
{ {
CInitMessage message(MessageInit_FromServer, ICMResync); CInitMessage_Resync message;
for (int i = 1; i < PlayerMax - 1; ++i) { // Info about other clients for (int i = 1; i < PlayerMax - 1; ++i) { // Info about other clients
if (i != hostIndex) { if (i != hostIndex && Hosts[i].PlyNr) {
if (Hosts[i].PlyNr) { message.hosts[i] = Hosts[i];
message.u.Hosts[i] = Hosts[i];
} else {
message.u.Hosts[i].Clear();
}
} }
} }
NetworkSendICMessage_Log(host.Host, host.Port, message); NetworkSendICMessage_Log(host.Host, host.Port, message);
@ -978,25 +1007,21 @@ void CServer::Send_Resync(const CNetworkHost &host, int hostIndex)
void CServer::Send_Map(const CNetworkHost& host) void CServer::Send_Map(const CNetworkHost& host)
{ {
CInitMessage message(MessageInit_FromServer, ICMMap); const CInitMessage_Map message(NetworkMapName.c_str(), Map.Info.MapUID);
strncpy_s(message.u.MapPath, sizeof(message.u.MapPath), NetworkMapName.c_str(), NetworkMapName.size());
message.MapUID = Map.Info.MapUID;
NetworkSendICMessage_Log(host.Host, host.Port, message); NetworkSendICMessage_Log(host.Host, host.Port, message);
} }
void CServer::Send_State(const CNetworkHost& host) void CServer::Send_State(const CNetworkHost& host)
{ {
CInitMessage message(MessageInit_FromServer, ICMState); const CInitMessage_State message(MessageInit_FromServer, ServerSetupState);
message.u.State = ServerSetupState;
message.MapUID = Map.Info.MapUID;
NetworkSendICMessage_Log(host.Host, host.Port, message); NetworkSendICMessage_Log(host.Host, host.Port, message);
} }
void CServer::Send_GoodBye(const CNetworkHost& host) void CServer::Send_GoodBye(const CNetworkHost& host)
{ {
const CInitMessage message(MessageInit_FromServer, ICMGoodBye); const CInitMessage_Header message(MessageInit_FromServer, ICMGoodBye);
NetworkSendICMessage_Log(host.Host, host.Port, message); NetworkSendICMessage_Log(host.Host, host.Port, message);
} }
@ -1037,7 +1062,7 @@ void CServer::MarkClientsAsResync()
** **
** @return host index ** @return host index
*/ */
int CServer::Parse_Hello(int h, const CInitMessage &msg, unsigned long host, int port) int CServer::Parse_Hello(int h, const CInitMessage_Hello &msg, unsigned long host, int port)
{ {
if (h == -1) { // it is a new client if (h == -1) { // it is a new client
for (int i = 1; i < PlayerMax - 1; ++i) { for (int i = 1; i < PlayerMax - 1; ++i) {
@ -1053,7 +1078,7 @@ int CServer::Parse_Hello(int h, const CInitMessage &msg, unsigned long host, int
Hosts[h].Host = host; Hosts[h].Host = host;
Hosts[h].Port = port; Hosts[h].Port = port;
Hosts[h].PlyNr = h; Hosts[h].PlyNr = h;
Hosts[h].SetName(msg.u.Hosts[0].PlyName); Hosts[h].SetName(msg.PlyName);
DebugPrint("New client %d.%d.%d.%d:%d [%s]\n" _C_ DebugPrint("New client %d.%d.%d.%d:%d [%s]\n" _C_
NIPQUAD(ntohl(host)) _C_ ntohs(port) _C_ Hosts[h].PlyName); NIPQUAD(ntohl(host)) _C_ ntohs(port) _C_ Hosts[h].PlyName);
networkStates[h].State = ccs_connecting; networkStates[h].State = ccs_connecting;
@ -1181,7 +1206,7 @@ void CServer::Parse_Map(const int h)
networkStates[h].MsgCnt = 0; networkStates[h].MsgCnt = 0;
/* Fall through */ /* Fall through */
case ccs_mapinfo: { case ccs_mapinfo: {
// this code path happens until client acknoledges the state info // this code path happens until client acknowledges the state info
// by falling back to ICMWaiting with prev. State synced // by falling back to ICMWaiting with prev. State synced
Send_State(Hosts[h]); Send_State(Hosts[h]);
@ -1203,7 +1228,7 @@ void CServer::Parse_Map(const int h)
** @param h slot number of host msg originates from ** @param h slot number of host msg originates from
** @param msg message received ** @param msg message received
*/ */
void CServer::Parse_State(const int h, const CInitMessage &msg) void CServer::Parse_State(const int h, const CInitMessage_State &msg)
{ {
switch (networkStates[h].State) { switch (networkStates[h].State) {
case ccs_mapinfo: case ccs_mapinfo:
@ -1214,8 +1239,8 @@ void CServer::Parse_State(const int h, const CInitMessage &msg)
// networkStates[h].State = ccs_async; // networkStates[h].State = ccs_async;
networkStates[h].MsgCnt = 0; networkStates[h].MsgCnt = 0;
// Use information supplied by the client: // Use information supplied by the client:
ServerSetupState.Ready[h] = msg.u.State.Ready[h]; ServerSetupState.Ready[h] = msg.State.Ready[h];
ServerSetupState.Race[h] = msg.u.State.Race[h]; ServerSetupState.Race[h] = msg.State.Race[h];
// Add additional info usage here! // Add additional info usage here!
// Resync other clients (and us..) // Resync other clients (and us..)
@ -1297,16 +1322,16 @@ void CServer::Parse_SeeYou(const int h)
** **
** @return 0 if the versions match, -1 otherwise ** @return 0 if the versions match, -1 otherwise
*/ */
static int CheckVersions(const CInitMessage &msg, unsigned long host, int port) static int CheckVersions(const CInitMessage_Hello &msg, unsigned long host, int port)
{ {
if (msg.Stratagus != StratagusVersion) { if (msg.Stratagus != StratagusVersion) {
fprintf(stderr, "Incompatible Stratagus version " fprintf(stderr, "Incompatible Stratagus version "
"%d <-> %d\n" "%d <-> %d\n"
"from %d.%d.%d.%d:%d\n", "from %d.%d.%d.%d:%d\n",
msg.Stratagus, StratagusVersion, StratagusVersion, msg.Stratagus,
NIPQUAD(ntohl(host)), ntohs(port)); NIPQUAD(ntohl(host)), ntohs(port));
const CInitMessage message(MessageInit_FromServer, ICMEngineMismatch); const CInitMessage_EngineMismatch message;
NetworkSendICMessage_Log(host, port, message); NetworkSendICMessage_Log(host, port, message);
return -1; return -1;
} }
@ -1316,11 +1341,11 @@ static int CheckVersions(const CInitMessage &msg, unsigned long host, int port)
NetworkProtocolFormatString " <-> " NetworkProtocolFormatString " <-> "
NetworkProtocolFormatString "\n" NetworkProtocolFormatString "\n"
"from %d.%d.%d.%d:%d\n", "from %d.%d.%d.%d:%d\n",
NetworkProtocolFormatArgs(msg.Version),
NetworkProtocolFormatArgs(NetworkProtocolVersion), NetworkProtocolFormatArgs(NetworkProtocolVersion),
NetworkProtocolFormatArgs(msg.Version),
NIPQUAD(ntohl(host)), ntohs(port)); NIPQUAD(ntohl(host)), ntohs(port));
const CInitMessage message(MessageInit_FromServer, ICMProtocolMismatch); const CInitMessage_ProtocolMismatch message;
NetworkSendICMessage_Log(host, port, message); NetworkSendICMessage_Log(host, port, message);
return -1; return -1;
} }
@ -1334,7 +1359,7 @@ void CServer::Parse(unsigned long frameCounter, const unsigned char *buf, unsign
if (index == -1) { if (index == -1) {
if (msgsubtype == ICMHello) { if (msgsubtype == ICMHello) {
CInitMessage msg; CInitMessage_Hello msg;
msg.Deserialize(buf); msg.Deserialize(buf);
if (CheckVersions(msg, host, port)) { if (CheckVersions(msg, host, port)) {
@ -1349,7 +1374,7 @@ void CServer::Parse(unsigned long frameCounter, const unsigned char *buf, unsign
networkStates[index].LastFrame = frameCounter; networkStates[index].LastFrame = frameCounter;
switch (msgsubtype) { switch (msgsubtype) {
case ICMHello: { // a new client has arrived case ICMHello: { // a new client has arrived
CInitMessage msg; CInitMessage_Hello msg;
msg.Deserialize(buf); msg.Deserialize(buf);
Parse_Hello(index, msg, host, port); Parse_Hello(index, msg, host, port);
@ -1360,19 +1385,15 @@ void CServer::Parse(unsigned long frameCounter, const unsigned char *buf, unsign
case ICMMap: Parse_Map(index); break; case ICMMap: Parse_Map(index); break;
case ICMState: { case ICMState: {
CInitMessage msg; CInitMessage_State msg;
msg.Deserialize(buf); msg.Deserialize(buf);
Parse_State(index, msg); Parse_State(index, msg);
break; break;
} }
case ICMMapUidMismatch: case ICMMapUidMismatch: // Parse_MapUidMismatch(index, buf); break;
case ICMGoodBye: case ICMGoodBye: Parse_GoodBye(index); break;
Parse_GoodBye(index);
break;
case ICMSeeYou: Parse_SeeYou(index); break; case ICMSeeYou: Parse_SeeYou(index); break;
case ICMIAH: break; case ICMIAH: break;
default: default:
@ -1399,7 +1420,9 @@ int NetworkParseSetupEvent(const unsigned char *buf, int size, unsigned long hos
{ {
Assert(NetConnectRunning != 0); Assert(NetConnectRunning != 0);
const char msgtype = buf[0]; CInitMessage_Header header;
header.Deserialize(buf);
const unsigned char msgtype = header.GetType();
if ((msgtype == MessageInit_FromClient && NetConnectRunning != 1) if ((msgtype == MessageInit_FromClient && NetConnectRunning != 1)
|| (msgtype == MessageInit_FromServer && NetConnectRunning != 2)) { || (msgtype == MessageInit_FromServer && NetConnectRunning != 2)) {
if (NetConnectRunning == 2 && Client.GetNetworkState() == ccs_started) { if (NetConnectRunning == 2 && Client.GetNetworkState() == ccs_started) {
@ -1410,7 +1433,7 @@ int NetworkParseSetupEvent(const unsigned char *buf, int size, unsigned long hos
} }
return 0; return 0;
} }
const char msgsubtype = buf[1]; const unsigned char msgsubtype = header.GetSubType();
DebugPrint("Received %s (%d) from %d.%d.%d.%d:%d\n" _C_ DebugPrint("Received %s (%d) from %d.%d.%d.%d:%d\n" _C_
icmsgsubtypenames[int(msgsubtype)] _C_ msgsubtype _C_ icmsgsubtypenames[int(msgsubtype)] _C_ msgsubtype _C_
@ -1476,6 +1499,7 @@ void NetworkInitClientConnect()
ServerSetupState.Clear(); ServerSetupState.Clear();
LocalSetupState.Clear(); LocalSetupState.Clear();
} }
/** /**
** Server user has finally hit the start game button ** Server user has finally hit the start game button
*/ */
@ -1625,19 +1649,15 @@ void NetworkServerStartGame()
std::swap(Hosts[0], Hosts[HostsCount]); std::swap(Hosts[0], Hosts[HostsCount]);
// Prepare the final config message: // Prepare the final config message:
CInitMessage message(MessageInit_FromServer, ICMConfig); CInitMessage_Config message;
message.HostsCount = NetPlayers; message.HostsCount = NetPlayers;
message.MapUID = Map.Info.MapUID;
for (int i = 0; i < NetPlayers; ++i) { for (int i = 0; i < NetPlayers; ++i) {
message.u.Hosts[i] = Hosts[i]; message.Hosts[i] = Hosts[i];
message.u.Hosts[i].PlyNr = Hosts[i].PlyNr; message.Hosts[i].PlyNr = Hosts[i].PlyNr;
} }
// Prepare the final state message: // Prepare the final state message:
CInitMessage statemsg(MessageInit_FromServer, ICMState); const CInitMessage_State statemsg(MessageInit_FromServer, ServerSetupState);
statemsg.HostsCount = NetPlayers;
statemsg.u.State = ServerSetupState;
statemsg.MapUID = Map.Info.MapUID;
DebugPrint("Ready, sending InitConfig to %d host(s)\n" _C_ HostsCount); DebugPrint("Ready, sending InitConfig to %d host(s)\n" _C_ HostsCount);
// Send all clients host:ports to all clients. // Send all clients host:ports to all clients.
@ -1647,15 +1667,15 @@ breakout:
// Send to all clients. // Send to all clients.
for (int i = 0; i < HostsCount; ++i) { for (int i = 0; i < HostsCount; ++i) {
if (num[Hosts[i].PlyNr] == 1) { // not acknowledged yet if (num[Hosts[i].PlyNr] == 1) { // not acknowledged yet
unsigned long host = message.u.Hosts[i].Host; unsigned long host = message.Hosts[i].Host;
int port = message.u.Hosts[i].Port; int port = message.Hosts[i].Port;
message.u.Hosts[i].Host = message.u.Hosts[i].Port = 0; message.Hosts[i].Host = message.Hosts[i].Port = 0;
NetworkSendICMessage_Log(host, port, message); NetworkSendICMessage_Log(host, port, message);
message.u.Hosts[i].Host = host; message.Hosts[i].Host = host;
message.u.Hosts[i].Port = port; message.Hosts[i].Port = port;
} else if (num[Hosts[i].PlyNr] == 2) { } else if (num[Hosts[i].PlyNr] == 2) {
unsigned long host = message.u.Hosts[i].Host; unsigned long host = message.Hosts[i].Host;
int port = message.u.Hosts[i].Port; int port = message.Hosts[i].Port;
NetworkSendICMessage_Log(host, port, statemsg); NetworkSendICMessage_Log(host, port, statemsg);
} }
} }
@ -1671,16 +1691,13 @@ breakout:
len _C_ NIPQUAD(ntohl(host)) _C_ ntohs(port)); len _C_ NIPQUAD(ntohl(host)) _C_ ntohs(port));
continue; continue;
} }
CInitMessage_Header header;
header.Deserialize(buf);
const unsigned char type = header.GetType();
const unsigned char subtype = header.GetSubType();
if (len != (int)CInitMessage::Size()) { if (type == MessageInit_FromClient) {
DebugPrint("Unexpected message size\n"); switch (subtype) {
continue;
}
CInitMessage msg;
msg.Deserialize(buf);
if (msg.Type == MessageInit_FromClient) {
switch (msg.SubType) {
case ICMConfig: { case ICMConfig: {
DebugPrint("Got ack for InitConfig from %d.%d.%d.%d:%d\n" DebugPrint("Got ack for InitConfig from %d.%d.%d.%d:%d\n"
_C_ NIPQUAD(ntohl(host)) _C_ ntohs(port)); _C_ NIPQUAD(ntohl(host)) _C_ ntohs(port));
@ -1709,23 +1726,22 @@ breakout:
break; break;
} }
default: default:
DebugPrint("Server: Config ACK: Unhandled subtype %d\n" _C_ msg.SubType); DebugPrint("Server: Config ACK: Unhandled subtype %d\n" _C_ subtype);
break; break;
} }
} else { } else {
DebugPrint("Unexpected Message Type %d while waiting for Config ACK\n" _C_ msg.Type); DebugPrint("Unexpected Message Type %d while waiting for Config ACK\n" _C_ type);
} }
} }
} }
DebugPrint("DONE: All configs acked - Now starting..\n"); DebugPrint("DONE: All configs acked - Now starting..\n");
// Give clients a quick-start kick.. // Give clients a quick-start kick..
message.SubType = ICMGo; const CInitMessage_Header message_go(MessageInit_FromServer, ICMGo);
for (int i = 0; i < HostsCount; ++i) { for (int i = 0; i < HostsCount; ++i) {
const unsigned long host = message.u.Hosts[i].Host; const unsigned long host = Hosts[i].Host;
const int port = message.u.Hosts[i].Port; const int port = Hosts[i].Port;
NetworkSendICMessage_Log(host, port, message); NetworkSendICMessage_Log(host, port, message_go);
} }
} }

View file

@ -37,7 +37,7 @@ void FillCustomValue(CNetworkHost *obj)
{ {
obj->Host = 0x12345678; obj->Host = 0x12345678;
obj->Port = 0x9ABC; obj->Port = 0x9ABC;
for (int i = 0; i != sizeof(CNetworkHost::PlyName); ++i) { for (int i = 0; i != sizeof(obj->PlyName); ++i) {
obj->PlyName[i] = i + 1; obj->PlyName[i] = i + 1;
} }
obj->PlyNr = 0xDEF0; obj->PlyNr = 0xDEF0;
@ -64,20 +64,64 @@ void FillCustomValue(CServerSetup *obj)
} }
} }
void FillCustomValue(CInitMessage *obj) void FillCustomValue(CInitMessage_Header *obj)
{ {
obj->Type = 0x22; *obj = CInitMessage_Header(0x12, 0x34);
obj->SubType = ICMHello; }
obj->HostsCount = 0x04;
obj->padding = 0x33; void FillCustomValue(CInitMessage_Hello *obj)
{
for (int i = 0; i != sizeof(obj->PlyName); ++i) {
obj->PlyName[i] = i + 1;
}
obj->Stratagus = 0x12345678; obj->Stratagus = 0x12345678;
obj->Version = 0x90ABCDEF; obj->Version = 0x90ABCDEF;
obj->MapUID = 0x09BADCFE; }
obj->Lag = 0x13245768;
obj->Updates = 0x9A0BCEDF; void FillCustomValue(CInitMessage_Config *obj)
// it is the biggest data size. {
obj->HostsCount = PlayerMax;
for (int i = 0; i != PlayerMax; ++i) { for (int i = 0; i != PlayerMax; ++i) {
FillCustomValue(&obj->u.Hosts[i]); FillCustomValue(&obj->Hosts[i]);
}
}
void FillCustomValue(CInitMessage_EngineMismatch *obj)
{
obj->Stratagus = 0x01020304;
}
void FillCustomValue(CInitMessage_ProtocolMismatch *obj)
{
obj->Version = 0x01020304;
}
void FillCustomValue(CInitMessage_Welcome *obj)
{
obj->Lag = 0x01020304;
obj->Updates = 0x05060708;
for (int i = 0; i != PlayerMax; ++i) {
FillCustomValue(&obj->hosts[i]);
}
}
void FillCustomValue(CInitMessage_Map *obj)
{
obj->MapUID = 0x01234567;
for (int i = 0; i != sizeof(obj->MapPath); ++i) {
obj->MapPath[i] = 1 + i;
}
}
void FillCustomValue(CInitMessage_State *obj)
{
FillCustomValue(&obj->State);
}
void FillCustomValue(CInitMessage_Resync *obj)
{
for (int i = 0; i != PlayerMax; ++i) {
FillCustomValue(&obj->hosts[i]);
} }
} }
@ -86,16 +130,36 @@ bool CheckSerialization()
{ {
T obj1; T obj1;
FillCustomValue(&obj1);
unsigned char *buffer = new unsigned char [obj1.Size()];
unsigned char *end = buffer + obj1.Serialize(buffer);
bool res = size_t(end - buffer) == obj1.Size();
T obj2;
obj2.Deserialize(buffer);
delete [] buffer;
res &= memcmp(&obj1, &obj2, sizeof(T)) == 0; // may fail with padding
return res;
}
template <typename T>
bool CheckSerialization_return()
{
T obj1;
memset(&obj1, 0, sizeof(T));
FillCustomValue(&obj1); FillCustomValue(&obj1);
const unsigned char *buffer = obj1.Serialize(); const unsigned char *buffer = obj1.Serialize();
T obj2; T obj2;
memset(&obj2, 0, sizeof(T));
obj2.Deserialize(buffer); obj2.Deserialize(buffer);
bool res = memcmp(&obj1, &obj2, sizeof(T)) == 0; bool res = memcmp(&obj1, &obj2, sizeof(T)) == 0; // may fail with padding
delete [] buffer; delete [] buffer;
return res; return res;
} }
TEST(CNetworkHost) TEST(CNetworkHost)
{ {
CHECK(CheckSerialization<CNetworkHost>()); CHECK(CheckSerialization<CNetworkHost>());
@ -106,7 +170,47 @@ TEST(CServerSetup)
CHECK(CheckSerialization<CServerSetup>()); CHECK(CheckSerialization<CServerSetup>());
} }
TEST(CInitMessage) TEST(CInitMessage_Header)
{ {
CHECK(CheckSerialization<CInitMessage>()); CHECK(CheckSerialization<CInitMessage_Header>());
}
TEST(CInitMessage_Hello)
{
CHECK(CheckSerialization_return<CInitMessage_Hello>());
}
TEST(CInitMessage_Config)
{
CHECK(CheckSerialization_return<CInitMessage_Config>());
}
TEST(CInitMessage_EngineMismatch)
{
CHECK(CheckSerialization_return<CInitMessage_EngineMismatch>());
}
TEST(CInitMessage_ProtocolMismatch)
{
CHECK(CheckSerialization_return<CInitMessage_ProtocolMismatch>());
}
TEST(CInitMessage_Welcome)
{
CHECK(CheckSerialization_return<CInitMessage_Welcome>());
}
TEST(CInitMessage_Map)
{
CHECK(CheckSerialization_return<CInitMessage_Map>());
}
TEST(CInitMessage_State)
{
CHECK(CheckSerialization_return<CInitMessage_State>());
}
TEST(CInitMessage_Resync)
{
CHECK(CheckSerialization_return<CInitMessage_Resync>());
} }