Redone network packet abstraction. Prepared for easy access to packet data.

This commit is contained in:
lotodore
2007-04-08 16:18:20 +00:00
parent 6f458ec012
commit 2f5c8d7da1
14 changed files with 656 additions and 230 deletions
+5 -6
View File
@@ -45,6 +45,9 @@ Additional values for major version = 1:
[Future versions will include the name of the game, to support [Future versions will include the name of the game, to support
multiple games per server.] multiple games per server.]
Player Flags:
0x01 set: Player is human
Server Reply: Join Game ACK Server Reply: Join Game ACK
@@ -83,7 +86,7 @@ Server Reply: Join Game Error
Reason: Reason:
0x01 - Version not supported 0x01 - Version not supported
0x02 - Server full 0x02 - Server full
0x03 - Game has already started 0x03 - Game is already running
0x04 - Invalid Password 0x04 - Invalid Password
0xFF - Other cause 0xFF - Other cause
@@ -95,7 +98,7 @@ Server Notification: Player Joined
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 4 | Message Length | | Message Type = 4 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player ID | Player Number | | Player ID | Player Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player Flags | Name Length | | Player Flags | Name Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -105,10 +108,6 @@ Server Notification: Player Joined
/ | padding | / | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Player Flags:
0x01 set: Player is human
Server Notification: Player Left Server Notification: Player Left
-6
View File
@@ -4223,17 +4223,11 @@
<property name="text" > <property name="text" >
<string>Create Network Game ...</string> <string>Create Network Game ...</string>
</property> </property>
<property name="visible" >
<bool>false</bool>
</property>
</action> </action>
<action name="actionJoin_network_Game" > <action name="actionJoin_network_Game" >
<property name="text" > <property name="text" >
<string>Join Network Game ...</string> <string>Join Network Game ...</string>
</property> </property>
<property name="visible" >
<bool>false</bool>
</property>
</action> </action>
<action name="actionFullScreen" > <action name="actionFullScreen" >
<property name="text" > <property name="text" >
+5
View File
@@ -55,6 +55,10 @@ public:
{return &m_clientSockaddr;} {return &m_clientSockaddr;}
sockaddr_storage *GetClientSockaddr() sockaddr_storage *GetClientSockaddr()
{return &m_clientSockaddr;} {return &m_clientSockaddr;}
const std::string &GetPlayerName() const
{return m_playerName;}
void SetPlayerName(const std::string &playerName)
{m_playerName = playerName;}
int GetClientSockaddrSize() const int GetClientSockaddrSize() const
{return m_addrFamily == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in);} {return m_addrFamily == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in);}
@@ -66,6 +70,7 @@ private:
unsigned m_serverPort; unsigned m_serverPort;
std::string m_password; std::string m_password;
sockaddr_storage m_clientSockaddr; sockaddr_storage m_clientSockaddr;
std::string m_playerName; // TODO: use player interface.
}; };
#endif #endif
+6 -1
View File
@@ -41,7 +41,12 @@ public:
// Set the parameters. Does not do any error checking. // Set the parameters. Does not do any error checking.
// Error checking will be done during connect // Error checking will be done during connect
// (i.e. after starting the thread). // (i.e. after starting the thread).
void Init(const std::string &serverAddress, unsigned serverPort, bool ipv6, const std::string &pwd); void Init(
const std::string &serverAddress,
unsigned serverPort,
bool ipv6,
const std::string &pwd,
const std::string &playerName);
ClientCallback &GetCallback(); ClientCallback &GetCallback();
+12 -3
View File
@@ -320,8 +320,17 @@ ClientStateStartSession::~ClientStateStartSession()
int int
ClientStateStartSession::Process(ClientThread &client) ClientStateStartSession::Process(ClientThread &client)
{ {
boost::shared_ptr<NetPacket> packet(new NetPacketInit(10)); ClientContext &context = client.GetContext();
client.GetSender().Send(packet, client.GetContext().GetSocket());
NetPacketJoinGame::Data initData;
initData.password = context.GetPassword();
initData.playerName = context.GetPlayerName();
initData.ptype = PLAYER_TYPE_HUMAN; // TODO
boost::shared_ptr<NetPacket> packet(new NetPacketJoinGame);
((NetPacketJoinGame *)packet.get())->SetData(initData);
client.GetSender().Send(packet, context.GetSocket());
client.SetState(ClientStateWaitSession::Instance()); client.SetState(ClientStateWaitSession::Instance());
@@ -355,7 +364,7 @@ ClientStateWaitSession::Process(ClientThread &client)
boost::shared_ptr<NetPacket> tmpPacket = client.GetReceiver().Recv(context.GetSocket()); boost::shared_ptr<NetPacket> tmpPacket = client.GetReceiver().Recv(context.GetSocket());
if (tmpPacket.get() && tmpPacket->ToNetPacketInitAck()) if (tmpPacket.get() && tmpPacket->ToNetPacketJoinGameAck())
{ {
client.SetState(ClientStateWaitGame::Instance()); client.SetState(ClientStateWaitGame::Instance());
retVal = MSG_SOCK_SESSION_DONE; retVal = MSG_SOCK_SESSION_DONE;
+3 -1
View File
@@ -64,7 +64,8 @@ ClientThread::~ClientThread()
} }
void void
ClientThread::Init(const string &serverAddress, unsigned serverPort, bool ipv6, const string &pwd) ClientThread::Init(
const string &serverAddress, unsigned serverPort, bool ipv6, const string &pwd, const string &playerName)
{ {
if (IsRunning()) if (IsRunning())
return; // TODO: throw exception return; // TODO: throw exception
@@ -75,6 +76,7 @@ ClientThread::Init(const string &serverAddress, unsigned serverPort, bool ipv6,
context.SetServerAddr(serverAddress); context.SetServerAddr(serverAddress);
context.SetServerPort(serverPort); context.SetServerPort(serverPort);
context.SetPassword(pwd); context.SetPassword(pwd);
context.SetPlayerName(playerName);
} }
ClientCallback & ClientCallback &
+493 -98
View File
@@ -21,18 +21,229 @@
#include <net/netexception.h> #include <net/netexception.h>
#include <net/socket_msg.h> #include <net/socket_msg.h>
NetPacket::~NetPacket() #include <string>
using namespace std;
#define ADD_PADDING(x) ((((x) + 3) >> 2) << 2)
#define NET_TYPE_JOIN_GAME 1
#define NET_TYPE_JOIN_GAME_ACK 2
#define NET_TYPE_JOIN_GAME_ERROR 3
#define NET_TYPE_PLAYER_JOINED 4
#define NET_TYPE_PLAYER_LEFT 5
#define NET_TYPE_GAME_START 6
#define NET_PLAYER_FLAG_HUMAN 0x01
#define NET_JOIN_ERR_UNSUPPORTED_VERSION 0x01
#define NET_JOIN_ERR_SERVER_FULL 0x02
#define NET_JOIN_ERR_GAME_RUNNING 0x03
#define NET_JOIN_ERR_INVALID_PASSWORD 0x04
#define NET_JOIN_ERR_OTHER 0xFF
#define NET_VERSION_MAJOR 1
#define NET_VERSION_MINOR 0
#ifdef _MSC_VER
#pragma pack(push, 2)
#else
#pragma align 2
#endif
struct NetPacketHeader
{ {
u_int16_t type;
u_int16_t length;
};
struct NetPacketJoinGameData
{
NetPacketHeader head;
u_int16_t requestedVersionMajor;
u_int16_t requestedVersionMinor;
u_int16_t passwordLength;
u_int16_t playerFlags;
u_int16_t playerNameLength;
u_int16_t reserved;
char password[1];
};
struct NetPacketJoinGameAckData
{
NetPacketHeader head;
u_int32_t sessionId;
u_int16_t playerId;
u_int16_t playerNumber;
u_int16_t numberOfPlayers;
u_int16_t smallBlind;
u_int16_t handsBeforeRaise;
u_int16_t gameSpeed;
u_int32_t startCash;
};
struct NetPacketJoinGameErrorData
{
NetPacketHeader head;
u_int16_t errorReason;
u_int16_t reserved;
};
struct NetPacketPlayerJoinedData
{
NetPacketHeader head;
u_int16_t playerId;
u_int16_t playerNumber;
u_int16_t playerFlags;
u_int16_t playerNameLength;
char playerName[1];
};
struct NetPacketPlayerLeftData
{
NetPacketHeader head;
u_int16_t playerId;
u_int16_t reserved;
};
struct NetPacketGameStartData
{
NetPacketHeader head;
u_int16_t yourCards[2];
};
#ifdef _MSC_VER
#pragma pack(pop)
#else
#pragma align 0
#endif
boost::shared_ptr<NetPacket>
NetPacket::Create(char *data, unsigned &dataSize)
{
boost::shared_ptr<NetPacket> tmpPacket;
NetPacketHeader *tmpHeader = (NetPacketHeader *)data;
u_int16_t tmpLen = ntohs(tmpHeader->length);
// Check size restrictions.
if (tmpLen < sizeof(NetPacketHeader)
|| tmpLen > MAX_PACKET_SIZE)
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
else if (dataSize >= tmpLen)
{
// OK - we have a complete packet. Construct a corresponding object.
try
{
switch(ntohs(tmpHeader->type))
{
case NET_TYPE_JOIN_GAME:
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketJoinGame);
break;
case NET_TYPE_JOIN_GAME_ACK:
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketJoinGameAck);
break;
case NET_TYPE_GAME_START:
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketGameStart);
break;
}
if (tmpPacket.get())
tmpPacket->SetRawData(tmpHeader);
} catch (const NetException &)
{
tmpPacket.reset();
}
if (tmpLen < dataSize)
{
dataSize -= tmpLen;
memmove(data, data + tmpLen, dataSize);
}
else
dataSize = 0;
}
return tmpPacket;
} }
const NetPacketInit * NetPacket::NetPacket(u_int16_t type, u_int16_t initialLen)
NetPacket::ToNetPacketInit() const : m_data(NULL)
{
assert(initialLen >= sizeof(NetPacketHeader));
m_data = (NetPacketHeader *)malloc(initialLen);
assert(m_data);
memset(m_data, 0, initialLen);
m_data->type = htons(type);
m_data->length = htons(initialLen);
}
NetPacket::~NetPacket()
{
if (m_data)
free(m_data);
}
const NetPacketHeader *
NetPacket::GetRawData() const
{
assert(m_data);
return m_data;
}
NetPacketHeader *
NetPacket::GetRawData()
{
assert(m_data);
return m_data;
}
void
NetPacket::SetRawData(const NetPacketHeader *p)
{
if (!p)
return;
assert(m_data);
u_int16_t tmpLen = ntohs(p->length);
if (ntohs(p->type) != GetType())
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
// Check whether the data is valid.
Check(p);
// Resize makes sure m_data is large enough.
Resize(tmpLen);
memcpy(m_data, p, tmpLen);
}
u_int16_t
NetPacket::GetType() const
{
return ntohs(GetRawData()->type);
}
u_int16_t
NetPacket::GetLen() const
{
return ntohs(GetRawData()->length);
}
const NetPacketJoinGame *
NetPacket::ToNetPacketJoinGame() const
{ {
return NULL; return NULL;
} }
const NetPacketInitAck * const NetPacketJoinGameAck *
NetPacket::ToNetPacketInitAck() const NetPacket::ToNetPacketJoinGameAck() const
{
return NULL;
}
const NetPacketJoinGameError *
NetPacket::ToNetPacketJoinGameError() const
{ {
return NULL; return NULL;
} }
@@ -43,38 +254,59 @@ NetPacket::ToNetPacketGameStart() const
return NULL; return NULL;
} }
void
NetPacket::Resize(u_int16_t newLen)
{
assert(m_data);
u_int16_t oldLen = GetLen();
if (newLen != oldLen)
{
if (newLen < sizeof(NetPacketHeader))
throw NetException(ERR_SOCK_INTERNAL, 0);
else
{
NetPacketHeader *newData = (NetPacketHeader *)malloc(newLen);
if (!newData)
throw NetException(ERR_SOCK_INTERNAL, 0);
else
{
// Copy as much data as possible.
memcpy(newData, m_data, newLen > oldLen ? oldLen : newLen);
// Initialize new data to 0.
if (newLen > oldLen)
memset(((unsigned char *)newData) + oldLen, 0, newLen - oldLen);
// Set new len.
newData->length = htons(newLen);
// Switch over to new data.
free(m_data);
m_data = newData;
}
}
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
NetPacketInit::NetPacketInit() NetPacketJoinGame::NetPacketJoinGame()
: NetPacket(NET_TYPE_JOIN_GAME, sizeof(NetPacketJoinGameData))
{ {
Init(); NetPacketJoinGameData *tmpData = (NetPacketJoinGameData *)GetRawData();
assert(tmpData);
tmpData->requestedVersionMajor = htons(NET_VERSION_MAJOR);
tmpData->requestedVersionMinor = htons(NET_VERSION_MINOR);
} }
NetPacketInit::NetPacketInit(u_int32_t value) NetPacketJoinGame::~NetPacketJoinGame()
{ {
Init();
m_data.test = htonl(value);
}
NetPacketInit::~NetPacketInit()
{
}
void
NetPacketInit::Init()
{
m_data.head.type = htons(NET_TYPE_INIT);
m_data.head.length = htons(sizeof(m_data));
m_data.test = htonl(0);
} }
boost::shared_ptr<NetPacket> boost::shared_ptr<NetPacket>
NetPacketInit::Clone() const NetPacketJoinGame::Clone() const
{ {
boost::shared_ptr<NetPacket> newPacket(new NetPacketInit); boost::shared_ptr<NetPacket> newPacket(new NetPacketJoinGame);
try try
{ {
newPacket->SetData(GetData()); newPacket->SetRawData(GetRawData());
} catch (const NetException &) } catch (const NetException &)
{ {
// Need to return the new packet anyway. // Need to return the new packet anyway.
@@ -82,63 +314,92 @@ NetPacketInit::Clone() const
return newPacket; return newPacket;
} }
const NetPacketHeader * void
NetPacketInit::GetData() const NetPacketJoinGame::SetData(const NetPacketJoinGame::Data &inData)
{ {
return (const NetPacketHeader *)&m_data; u_int16_t playerNameLen = (u_int16_t)inData.playerName.length();
u_int16_t passwordLen = (u_int16_t)inData.password.length();
if (!playerNameLen || playerNameLen > MAX_NAME_SIZE)
throw NetException(ERR_SOCK_INVALID_NAME_STR, 0);
if (passwordLen > MAX_PASSWORD_SIZE)
throw NetException(ERR_SOCK_INVALID_PWD_STR, 0);
// Resize the packet so that the data fits in.
Resize((u_int16_t)
(sizeof(NetPacketJoinGameData) + ADD_PADDING(playerNameLen) + ADD_PADDING(passwordLen)));
NetPacketJoinGameData *tmpData = (NetPacketJoinGameData *)GetRawData();
assert(tmpData);
// Set the data.
tmpData->passwordLength = htons(passwordLen);
tmpData->playerFlags = htons((inData.ptype == PLAYER_TYPE_HUMAN) ? NET_PLAYER_FLAG_HUMAN : 0);
tmpData->playerNameLength = htons(playerNameLen);
memcpy(tmpData->password, inData.password.c_str(), passwordLen);
memcpy(tmpData->password + ADD_PADDING(passwordLen), inData.playerName.c_str(), playerNameLen);
} }
void void
NetPacketInit::SetData(const NetPacketHeader *p) NetPacketJoinGame::GetData(NetPacketJoinGame::Data &outData) const
{ {
u_int16_t tmpLen = ntohs(p->length); // We assume that the data is valid. Validity has already been checked.
if (tmpLen != sizeof(m_data) NetPacketJoinGameData *tmpData = (NetPacketJoinGameData *)GetRawData();
|| ntohs(p->type) != NET_TYPE_INIT) assert(tmpData);
{
throw NetException(ERR_SOCK_INTERNAL, 0);
}
memcpy(&m_data, p, tmpLen); outData.ptype = (ntohs(tmpData->playerFlags) & NET_PLAYER_FLAG_HUMAN) ? PLAYER_TYPE_HUMAN : PLAYER_TYPE_COMPUTER;
u_int16_t passwordLen = ntohs(tmpData->passwordLength);
outData.password = string(tmpData->password, passwordLen);
outData.playerName = string(tmpData->password + ADD_PADDING(passwordLen), ntohs(tmpData->playerNameLength));
} }
const NetPacketInit * const NetPacketJoinGame *
NetPacketInit::ToNetPacketInit() const NetPacketJoinGame::ToNetPacketJoinGame() const
{ {
return this; return this;
} }
void
NetPacketJoinGame::Check(const NetPacketHeader* data) const
{
assert(data);
u_int16_t dataLen = ntohs(data->length);
if (dataLen < sizeof(NetPacketJoinGameData)
|| dataLen > sizeof(NetPacketJoinGameData) + MAX_NAME_SIZE + MAX_PASSWORD_SIZE)
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
NetPacketJoinGameData *tmpData = (NetPacketJoinGameData *)data;
if (dataLen !=
sizeof(NetPacketJoinGameData)
+ ADD_PADDING(ntohs(tmpData->passwordLength))
+ ADD_PADDING(ntohs(tmpData->playerNameLength)))
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
NetPacketInitAck::NetPacketInitAck() NetPacketJoinGameAck::NetPacketJoinGameAck()
{ : NetPacket(NET_TYPE_JOIN_GAME_ACK, sizeof(NetPacketJoinGameAckData))
Init();
}
NetPacketInitAck::NetPacketInitAck(u_int32_t value)
{
Init();
m_data.test = htonl(value);
}
NetPacketInitAck::~NetPacketInitAck()
{ {
} }
void NetPacketJoinGameAck::~NetPacketJoinGameAck()
NetPacketInitAck::Init()
{ {
m_data.head.type = htons(NET_TYPE_INIT_ACK);
m_data.head.length = htons(sizeof(m_data));
m_data.test = htonl(0);
} }
boost::shared_ptr<NetPacket> boost::shared_ptr<NetPacket>
NetPacketInitAck::Clone() const NetPacketJoinGameAck::Clone() const
{ {
boost::shared_ptr<NetPacket> newPacket(new NetPacketInitAck); boost::shared_ptr<NetPacket> newPacket(new NetPacketJoinGameAck);
try try
{ {
newPacket->SetData(GetData()); newPacket->SetRawData(GetRawData());
} catch (const NetException &) } catch (const NetException &)
{ {
// Need to return the new packet anyway. // Need to return the new packet anyway.
@@ -146,63 +407,176 @@ NetPacketInitAck::Clone() const
return newPacket; return newPacket;
} }
const NetPacketHeader * void
NetPacketInitAck::GetData() const NetPacketJoinGameAck::SetData(const NetPacketJoinGameAck::Data &inData)
{ {
return (const NetPacketHeader *)&m_data; NetPacketJoinGameAckData *tmpData = (NetPacketJoinGameAckData *)GetRawData();
assert(tmpData);
tmpData->sessionId = htonl(inData.sessionId);
tmpData->playerId = htons(inData.playerId);
tmpData->playerNumber = htons(inData.playerNumber);
tmpData->numberOfPlayers = htons(inData.numberOfPlayers);
tmpData->smallBlind = htons(inData.smallBlind);
tmpData->handsBeforeRaise = htons(inData.handsBeforeRaise);
tmpData->gameSpeed = htons(inData.gameSpeed);
tmpData->startCash = htonl(inData.startCash);
} }
void void
NetPacketInitAck::SetData(const NetPacketHeader *p) NetPacketJoinGameAck::GetData(NetPacketJoinGameAck::Data &outData) const
{ {
u_int16_t tmpLen = ntohs(p->length); NetPacketJoinGameAckData *tmpData = (NetPacketJoinGameAckData *)GetRawData();
if (tmpLen != sizeof(m_data) assert(tmpData);
|| ntohs(p->type) != NET_TYPE_INIT_ACK)
{
throw NetException(ERR_SOCK_INTERNAL, 0);
}
memcpy(&m_data, p, tmpLen); outData.sessionId = ntohl(tmpData->sessionId);
outData.playerId = ntohs(tmpData->playerId);
outData.playerNumber = ntohs(tmpData->playerNumber);
outData.numberOfPlayers = ntohs(tmpData->numberOfPlayers);
outData.smallBlind = ntohs(tmpData->smallBlind);
outData.handsBeforeRaise = ntohs(tmpData->handsBeforeRaise);
outData.gameSpeed = ntohs(tmpData->gameSpeed);
outData.startCash = ntohl(tmpData->startCash);
} }
const NetPacketInitAck * const NetPacketJoinGameAck *
NetPacketInitAck::ToNetPacketInitAck() const NetPacketJoinGameAck::ToNetPacketJoinGameAck() const
{ {
return this; return this;
} }
void
NetPacketJoinGameAck::Check(const NetPacketHeader* data) const
{
assert(data);
u_int16_t dataLen = ntohs(data->length);
if (dataLen < sizeof(NetPacketJoinGameAckData))
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
// TODO: maybe some semantic checks
}
//-----------------------------------------------------------------------------
NetPacketJoinGameError::NetPacketJoinGameError()
: NetPacket(NET_TYPE_JOIN_GAME_ERROR, sizeof(NetPacketJoinGameErrorData))
{
}
NetPacketJoinGameError::~NetPacketJoinGameError()
{
}
boost::shared_ptr<NetPacket>
NetPacketJoinGameError::Clone() const
{
boost::shared_ptr<NetPacket> newPacket(new NetPacketJoinGameError);
try
{
newPacket->SetRawData(GetRawData());
} catch (const NetException &)
{
// Need to return the new packet anyway.
}
return newPacket;
}
void
NetPacketJoinGameError::SetData(const NetPacketJoinGameError::Data &inData)
{
NetPacketJoinGameErrorData *tmpData = (NetPacketJoinGameErrorData *)GetRawData();
assert(tmpData);
switch (inData.reason)
{
case JOIN_UNSUPPORTED_VERSION :
tmpData->errorReason = htons(NET_JOIN_ERR_UNSUPPORTED_VERSION);
break;
case JOIN_SERVER_FULL :
tmpData->errorReason = htons(NET_JOIN_ERR_SERVER_FULL);
break;
case JOIN_GAME_RUNNING :
tmpData->errorReason = htons(NET_JOIN_ERR_GAME_RUNNING);
break;
case JOIN_INVALID_PASSWORD :
tmpData->errorReason = htons(NET_JOIN_ERR_INVALID_PASSWORD);
break;
default :
tmpData->errorReason = htons(NET_JOIN_ERR_OTHER);
break;
}
}
void
NetPacketJoinGameError::GetData(NetPacketJoinGameError::Data &outData) const
{
NetPacketJoinGameErrorData *tmpData = (NetPacketJoinGameErrorData *)GetRawData();
assert(tmpData);
switch (ntohs(tmpData->errorReason))
{
case NET_JOIN_ERR_UNSUPPORTED_VERSION :
outData.reason = JOIN_UNSUPPORTED_VERSION;
break;
case NET_JOIN_ERR_SERVER_FULL :
outData.reason = JOIN_SERVER_FULL;
break;
case NET_JOIN_ERR_GAME_RUNNING :
outData.reason = JOIN_GAME_RUNNING;
break;
case NET_JOIN_ERR_INVALID_PASSWORD :
outData.reason = JOIN_INVALID_PASSWORD;
break;
default :
outData.reason = JOIN_UNKNOWN;
break;
}
}
const NetPacketJoinGameError *
NetPacketJoinGameError::ToNetPacketJoinGameError() const
{
return this;
}
void
NetPacketJoinGameError::Check(const NetPacketHeader* data) const
{
assert(data);
u_int16_t dataLen = ntohs(data->length);
if (dataLen < sizeof(NetPacketJoinGameErrorData))
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
NetPacketGameStartData *tmpData = (NetPacketGameStartData *)GetRawData();
if (tmpData->yourCards[0] > 51 || tmpData->yourCards[1] > 51)
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
NetPacketGameStart::NetPacketGameStart() NetPacketGameStart::NetPacketGameStart()
: NetPacket(NET_TYPE_GAME_START, sizeof(NetPacketGameStartData))
{ {
Init();
}
NetPacketGameStart::NetPacketGameStart(u_int32_t value)
{
Init();
m_data.test = htonl(value);
} }
NetPacketGameStart::~NetPacketGameStart() NetPacketGameStart::~NetPacketGameStart()
{ {
} }
void
NetPacketGameStart::Init()
{
m_data.head.type = htons(NET_TYPE_GAME_START);
m_data.head.length = htons(sizeof(m_data));
m_data.test = htonl(0);
}
boost::shared_ptr<NetPacket> boost::shared_ptr<NetPacket>
NetPacketGameStart::Clone() const NetPacketGameStart::Clone() const
{ {
boost::shared_ptr<NetPacket> newPacket(new NetPacketGameStart); boost::shared_ptr<NetPacket> newPacket(new NetPacketGameStart);
try try
{ {
newPacket->SetData(GetData()); newPacket->SetRawData(GetRawData());
} catch (const NetException &) } catch (const NetException &)
{ {
// Need to return the new packet anyway. // Need to return the new packet anyway.
@@ -210,23 +584,24 @@ NetPacketGameStart::Clone() const
return newPacket; return newPacket;
} }
const NetPacketHeader * void
NetPacketGameStart::GetData() const NetPacketGameStart::SetData(const NetPacketGameStart::Data &inData)
{ {
return (NetPacketHeader *)&m_data; NetPacketGameStartData *tmpData = (NetPacketGameStartData *)GetRawData();
assert(tmpData);
tmpData->yourCards[0] = htons(inData.yourCards[0]);
tmpData->yourCards[1] = htons(inData.yourCards[1]);
} }
void void
NetPacketGameStart::SetData(const NetPacketHeader *p) NetPacketGameStart::GetData(NetPacketGameStart::Data &outData) const
{ {
u_int16_t tmpLen = ntohs(p->length); NetPacketGameStartData *tmpData = (NetPacketGameStartData *)GetRawData();
if (tmpLen != sizeof(m_data) assert(tmpData);
|| ntohs(p->type) != NET_TYPE_GAME_START)
{
throw NetException(ERR_SOCK_INTERNAL, 0);
}
memcpy(&m_data, p, tmpLen); outData.yourCards[0] = ntohs(tmpData->yourCards[0]);
outData.yourCards[1] = ntohs(tmpData->yourCards[1]);
} }
const NetPacketGameStart * const NetPacketGameStart *
@@ -235,3 +610,23 @@ NetPacketGameStart::ToNetPacketGameStart() const
return this; return this;
} }
void
NetPacketGameStart::Check(const NetPacketHeader* data) const
{
assert(data);
u_int16_t dataLen = ntohs(data->length);
if (dataLen < sizeof(NetPacketGameStartData))
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
NetPacketGameStartData *tmpData = (NetPacketGameStartData *)GetRawData();
if (tmpData->yourCards[0] > 51 || tmpData->yourCards[1] > 51)
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
}
//-----------------------------------------------------------------------------
+8 -40
View File
@@ -98,50 +98,18 @@ ReceiverHelper::InternalGetPacket()
// This is necessary, because we use TCP. // This is necessary, because we use TCP.
// Packets may be received in multiple chunks or // Packets may be received in multiple chunks or
// several packets may be received at once. // several packets may be received at once.
if (m_tmpInBufSize >= sizeof(NetPacketHeader)) if (m_tmpInBufSize >= MIN_PACKET_SIZE)
{ {
NetPacketHeader *tmpHeader = (NetPacketHeader *)m_tmpInBuf; try
u_int16_t tmpLen = ntohs(tmpHeader->length);
if (tmpLen < sizeof(NetPacketHeader)
|| tmpLen > MAX_PACKET_SIZE)
{ {
// Invalid packet - reset input buffer. // This call will also handle the memmove stuff, i.e.
// buffering for partial packets.
tmpPacket = NetPacket::Create(m_tmpInBuf, m_tmpInBufSize);
} catch (const NetException &)
{
// Reset buffer on error.
m_tmpInBufSize = 0; m_tmpInBufSize = 0;
} }
else if (m_tmpInBufSize >= tmpLen)
{
tmpPacket = InternalCreateNetPacket(tmpHeader);
m_tmpInBufSize -= tmpLen;
}
}
return tmpPacket;
}
boost::shared_ptr<NetPacket>
ReceiverHelper::InternalCreateNetPacket(const NetPacketHeader *p)
{
boost::shared_ptr<NetPacket> tmpPacket;
try
{
switch(ntohs(p->type))
{
case NET_TYPE_INIT:
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketInit);
break;
case NET_TYPE_INIT_ACK:
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketInitAck);
break;
case NET_TYPE_GAME_START:
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketGameStart);
break;
}
if (tmpPacket.get())
tmpPacket->SetData(p);
} catch (const NetException &)
{
tmpPacket.reset();
} }
return tmpPacket; return tmpPacket;
} }
+3 -3
View File
@@ -71,11 +71,11 @@ SenderThread::Main()
if (IS_VALID_SOCKET(tmpData.second)) if (IS_VALID_SOCKET(tmpData.second))
m_curSocket = tmpData.second; m_curSocket = tmpData.second;
u_int16_t tmpLen = ntohs(tmpData.first->GetData()->length); u_int16_t tmpLen = tmpData.first->GetLen();
if (tmpLen <= MAX_PACKET_SIZE) if (tmpLen <= MAX_PACKET_SIZE)
{ {
m_tmpOutBufSize = tmpLen; m_tmpOutBufSize = tmpLen;
memcpy(m_tmpOutBuf, tmpData.first->GetData(), m_tmpOutBufSize); memcpy(m_tmpOutBuf, tmpData.first->GetRawData(), tmpLen);
} }
} }
} }
@@ -109,7 +109,7 @@ SenderThread::Main()
} }
else if ((unsigned)bytesSent < m_tmpOutBufSize) else if ((unsigned)bytesSent < m_tmpOutBufSize)
{ {
m_tmpOutBufSize = m_tmpOutBufSize - (unsigned)bytesSent; m_tmpOutBufSize -= (unsigned)bytesSent;
memmove(m_tmpOutBuf, m_tmpOutBuf + bytesSent, m_tmpOutBufSize); memmove(m_tmpOutBuf, m_tmpOutBuf + bytesSent, m_tmpOutBufSize);
} }
else else
+6 -3
View File
@@ -72,10 +72,13 @@ ServerRecvStateInit::Process(ServerRecvThread &server)
{ {
if (session->GetState() == SessionData::Init) if (session->GetState() == SessionData::Init)
{ {
// Only accept init packets. // Only accept join game packets.
if (packet->ToNetPacketInit()) const NetPacketJoinGame *tmpPacket = packet->ToNetPacketJoinGame();
if (tmpPacket)
{ {
boost::shared_ptr<NetPacket> answer(new NetPacketInitAck); // TODO: check password
// TODO: display name
boost::shared_ptr<NetPacket> answer(new NetPacketJoinGameAck);
server.GetSender().Send(answer, recvSock); server.GetSender().Send(answer, recvSock);
session->SetState(SessionData::Established); session->SetState(SessionData::Established);
} }
+104 -66
View File
@@ -25,128 +25,166 @@
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <net/socket_helper.h> #include <net/socket_helper.h>
#define MAX_PACKET_SIZE 256 #define MIN_PACKET_SIZE 4
#define MAX_PACKET_SIZE 256
#define MAX_NAME_SIZE 64
#define MAX_PASSWORD_SIZE 64
#define NET_TYPE_INIT 0 // TODO: move this somewhere else
#define NET_TYPE_INIT_ACK 1 enum PlayerType
#define NET_TYPE_GAME_START 2
#ifdef _MSC_VER
#pragma pack(push, 2)
#else
#pragma align 2
#endif
struct NetPacketHeader
{ {
u_int16_t type; PLAYER_TYPE_COMPUTER,
u_int16_t length; PLAYER_TYPE_HUMAN
}; };
struct NetPacketInitData enum JoinGameErrorReason
{ {
NetPacketHeader head; JOIN_UNSUPPORTED_VERSION,
u_int32_t test; JOIN_SERVER_FULL,
JOIN_GAME_RUNNING,
JOIN_INVALID_PASSWORD,
JOIN_UNKNOWN
}; };
struct NetPacketInitAckData struct NetPacketHeader;
{
NetPacketHeader head;
u_int32_t test;
};
struct NetPacketGameStartData class NetPacketJoinGame;
{ class NetPacketJoinGameAck;
NetPacketHeader head; class NetPacketJoinGameError;
u_int32_t test;
};
#ifdef _MSC_VER
#pragma pack(pop)
#else
#pragma align 0
#endif
class NetPacketInit;
class NetPacketInitAck;
class NetPacketGameStart; class NetPacketGameStart;
class NetPacket class NetPacket
{ {
public: public:
static boost::shared_ptr<NetPacket> Create(char *data, unsigned &dataSize);
NetPacket(u_int16_t type, u_int16_t initialLen);
virtual ~NetPacket(); virtual ~NetPacket();
virtual boost::shared_ptr<NetPacket> Clone() const = 0; virtual boost::shared_ptr<NetPacket> Clone() const = 0;
virtual void SetData(const NetPacketHeader *p) = 0; const NetPacketHeader *GetRawData() const;
virtual const NetPacketHeader *GetData() const = 0; NetPacketHeader *GetRawData();
void SetRawData(const NetPacketHeader *p);
virtual const NetPacketInit *ToNetPacketInit() const; u_int16_t GetType() const;
virtual const NetPacketInitAck *ToNetPacketInitAck() const; u_int16_t GetLen() const;
virtual const NetPacketJoinGame *ToNetPacketJoinGame() const;
virtual const NetPacketJoinGameAck *ToNetPacketJoinGameAck() const;
virtual const NetPacketJoinGameError *ToNetPacketJoinGameError() const;
virtual const NetPacketGameStart *ToNetPacketGameStart() const; virtual const NetPacketGameStart *ToNetPacketGameStart() const;
protected:
virtual void Check(const NetPacketHeader* data) const = 0;
void Resize(u_int16_t newLen);
private:
NetPacketHeader *m_data;
}; };
class NetPacketInit : public NetPacket class NetPacketJoinGame : public NetPacket
{ {
public: public:
NetPacketInit(); struct Data
NetPacketInit(u_int32_t value); {
virtual ~NetPacketInit(); PlayerType ptype;
std::string playerName;
std::string password;
};
NetPacketJoinGame();
virtual ~NetPacketJoinGame();
virtual boost::shared_ptr<NetPacket> Clone() const; virtual boost::shared_ptr<NetPacket> Clone() const;
virtual const NetPacketHeader *GetData() const; void SetData(const Data &inData);
virtual void SetData(const NetPacketHeader *p); void GetData(Data &outData) const;
virtual const NetPacketInit *ToNetPacketInit() const; virtual const NetPacketJoinGame *ToNetPacketJoinGame() const;
protected: protected:
void Init();
private: virtual void Check(const NetPacketHeader* data) const;
NetPacketInitData m_data;
}; };
class NetPacketInitAck : public NetPacket class NetPacketJoinGameAck : public NetPacket
{ {
public: public:
NetPacketInitAck(); struct Data
NetPacketInitAck(u_int32_t value); {
virtual ~NetPacketInitAck(); u_int32_t sessionId;
u_int16_t playerId;
u_int16_t playerNumber;
u_int16_t numberOfPlayers;
u_int16_t smallBlind;
u_int16_t handsBeforeRaise;
u_int16_t gameSpeed;
u_int32_t startCash;
};
NetPacketJoinGameAck();
virtual ~NetPacketJoinGameAck();
virtual boost::shared_ptr<NetPacket> Clone() const; virtual boost::shared_ptr<NetPacket> Clone() const;
virtual const NetPacketHeader *GetData() const; void SetData(const Data &inData);
virtual void SetData(const NetPacketHeader *p); void GetData(Data &outData) const;
virtual const NetPacketInitAck *ToNetPacketInitAck() const; virtual const NetPacketJoinGameAck *ToNetPacketJoinGameAck() const;
protected: protected:
void Init();
private: virtual void Check(const NetPacketHeader* data) const;
NetPacketInitAckData m_data; };
class NetPacketJoinGameError : public NetPacket
{
public:
struct Data
{
JoinGameErrorReason reason;
};
NetPacketJoinGameError();
virtual ~NetPacketJoinGameError();
virtual boost::shared_ptr<NetPacket> Clone() const;
void SetData(const Data &inData);
void GetData(Data &outData) const;
virtual const NetPacketJoinGameError *ToNetPacketJoinGameError() const;
protected:
virtual void Check(const NetPacketHeader* data) const;
}; };
class NetPacketGameStart : public NetPacket class NetPacketGameStart : public NetPacket
{ {
public: public:
struct Data
{
u_int16_t yourCards[2];
};
NetPacketGameStart(); NetPacketGameStart();
NetPacketGameStart(u_int32_t value);
virtual ~NetPacketGameStart(); virtual ~NetPacketGameStart();
virtual boost::shared_ptr<NetPacket> Clone() const; virtual boost::shared_ptr<NetPacket> Clone() const;
virtual const NetPacketHeader *GetData() const; void SetData(const Data &inData);
virtual void SetData(const NetPacketHeader *p); void GetData(Data &outData) const;
virtual const NetPacketGameStart *ToNetPacketGameStart() const; virtual const NetPacketGameStart *ToNetPacketGameStart() const;
protected: protected:
void Init();
private: virtual void Check(const NetPacketHeader* data) const;
NetPacketGameStartData m_data;
}; };
#endif #endif
-1
View File
@@ -45,7 +45,6 @@ public:
protected: protected:
boost::shared_ptr<NetPacket> InternalGetPacket(); boost::shared_ptr<NetPacket> InternalGetPacket();
boost::shared_ptr<NetPacket> InternalCreateNetPacket(const NetPacketHeader *p);
private: private:
+3
View File
@@ -36,6 +36,9 @@
#define ERR_SOCK_SEND_FAILED 14 #define ERR_SOCK_SEND_FAILED 14
#define ERR_SOCK_CONN_RESET 15 #define ERR_SOCK_CONN_RESET 15
#define ERR_SOCK_CONN_EXISTS 16 #define ERR_SOCK_CONN_EXISTS 16
#define ERR_SOCK_INVALID_NAME_STR 17
#define ERR_SOCK_INVALID_PWD_STR 18
#define ERR_SOCK_INVALID_PACKET 19
// This is an internal message which is not reported. // This is an internal message which is not reported.
#define MSG_SOCK_INTERNAL_PENDING 0 #define MSG_SOCK_INTERNAL_PENDING 0
+8 -2
View File
@@ -64,7 +64,12 @@ void Session::startNetworkClient(const string &serverAddress, unsigned serverPor
if (myNetClient || !myGui) if (myNetClient || !myGui)
return; // TODO: throw exception return; // TODO: throw exception
myNetClient = new ClientThread(*myGui); myNetClient = new ClientThread(*myGui);
myNetClient->Init(serverAddress, serverPort, ipv6, pwd); myNetClient->Init(
serverAddress,
serverPort,
ipv6,
pwd,
myConfig->readConfigString("MyName"));
myNetClient->Run(); myNetClient->Run();
} }
@@ -77,7 +82,8 @@ void Session::startNetworkClientForLocalServer()
"localhost", "localhost",
myConfig->readConfigInt("ServerPort"), myConfig->readConfigInt("ServerPort"),
myConfig->readConfigInt("ServerUseIpv6") == 1, myConfig->readConfigInt("ServerUseIpv6") == 1,
myConfig->readConfigString("ServerPassword")); myConfig->readConfigString("ServerPassword"),
myConfig->readConfigString("MyName"));
myNetClient->Run(); myNetClient->Run();
} }