diff --git a/docs/net_protocol.txt b/docs/net_protocol.txt
index 1dbcb536..d2e9da9d 100644
--- a/docs/net_protocol.txt
+++ b/docs/net_protocol.txt
@@ -45,6 +45,9 @@ Additional values for major version = 1:
[Future versions will include the name of the game, to support
multiple games per server.]
+Player Flags:
+ 0x01 set: Player is human
+
Server Reply: Join Game ACK
@@ -83,7 +86,7 @@ Server Reply: Join Game Error
Reason:
0x01 - Version not supported
0x02 - Server full
- 0x03 - Game has already started
+ 0x03 - Game is already running
0x04 - Invalid Password
0xFF - Other cause
@@ -95,7 +98,7 @@ Server Notification: Player Joined
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 4 | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Player ID | Player Number |
+ | Player ID | Player Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Player Flags | Name Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -105,10 +108,6 @@ Server Notification: Player Joined
/ | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-Player Flags:
- 0x01 set: Player is human
-
-
Server Notification: Player Left
diff --git a/src/gui/qt/mainwindow.ui b/src/gui/qt/mainwindow.ui
index d1d79ad0..9d3e1567 100644
--- a/src/gui/qt/mainwindow.ui
+++ b/src/gui/qt/mainwindow.ui
@@ -4223,17 +4223,11 @@
Create Network Game ...
-
- false
-
Join Network Game ...
-
- false
-
diff --git a/src/net/clientcontext.h b/src/net/clientcontext.h
index 829ae217..bfe1eaa4 100644
--- a/src/net/clientcontext.h
+++ b/src/net/clientcontext.h
@@ -55,6 +55,10 @@ public:
{return &m_clientSockaddr;}
sockaddr_storage *GetClientSockaddr()
{return &m_clientSockaddr;}
+ const std::string &GetPlayerName() const
+ {return m_playerName;}
+ void SetPlayerName(const std::string &playerName)
+ {m_playerName = playerName;}
int GetClientSockaddrSize() const
{return m_addrFamily == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in);}
@@ -66,6 +70,7 @@ private:
unsigned m_serverPort;
std::string m_password;
sockaddr_storage m_clientSockaddr;
+ std::string m_playerName; // TODO: use player interface.
};
#endif
diff --git a/src/net/clientthread.h b/src/net/clientthread.h
index 4f72e7a5..4cd8b13f 100644
--- a/src/net/clientthread.h
+++ b/src/net/clientthread.h
@@ -41,7 +41,12 @@ public:
// Set the parameters. Does not do any error checking.
// Error checking will be done during connect
// (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();
diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp
index fd02e372..435d699b 100644
--- a/src/net/common/clientstate.cpp
+++ b/src/net/common/clientstate.cpp
@@ -320,8 +320,17 @@ ClientStateStartSession::~ClientStateStartSession()
int
ClientStateStartSession::Process(ClientThread &client)
{
- boost::shared_ptr packet(new NetPacketInit(10));
- client.GetSender().Send(packet, client.GetContext().GetSocket());
+ ClientContext &context = client.GetContext();
+
+ NetPacketJoinGame::Data initData;
+ initData.password = context.GetPassword();
+ initData.playerName = context.GetPlayerName();
+ initData.ptype = PLAYER_TYPE_HUMAN; // TODO
+
+ boost::shared_ptr packet(new NetPacketJoinGame);
+ ((NetPacketJoinGame *)packet.get())->SetData(initData);
+
+ client.GetSender().Send(packet, context.GetSocket());
client.SetState(ClientStateWaitSession::Instance());
@@ -355,7 +364,7 @@ ClientStateWaitSession::Process(ClientThread &client)
boost::shared_ptr tmpPacket = client.GetReceiver().Recv(context.GetSocket());
- if (tmpPacket.get() && tmpPacket->ToNetPacketInitAck())
+ if (tmpPacket.get() && tmpPacket->ToNetPacketJoinGameAck())
{
client.SetState(ClientStateWaitGame::Instance());
retVal = MSG_SOCK_SESSION_DONE;
diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp
index 35e4176c..84e699a2 100644
--- a/src/net/common/clientthread.cpp
+++ b/src/net/common/clientthread.cpp
@@ -64,7 +64,8 @@ ClientThread::~ClientThread()
}
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())
return; // TODO: throw exception
@@ -75,6 +76,7 @@ ClientThread::Init(const string &serverAddress, unsigned serverPort, bool ipv6,
context.SetServerAddr(serverAddress);
context.SetServerPort(serverPort);
context.SetPassword(pwd);
+ context.SetPlayerName(playerName);
}
ClientCallback &
diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp
index 748f398d..04da19e1 100644
--- a/src/net/common/netpacket.cpp
+++ b/src/net/common/netpacket.cpp
@@ -21,18 +21,229 @@
#include
#include
-NetPacket::~NetPacket()
+#include
+
+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::Create(char *data, unsigned &dataSize)
+{
+ boost::shared_ptr 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(new NetPacketJoinGame);
+ break;
+ case NET_TYPE_JOIN_GAME_ACK:
+ tmpPacket = boost::shared_ptr(new NetPacketJoinGameAck);
+ break;
+ case NET_TYPE_GAME_START:
+ tmpPacket = boost::shared_ptr(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::ToNetPacketInit() const
+NetPacket::NetPacket(u_int16_t type, u_int16_t initialLen)
+: 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;
}
-const NetPacketInitAck *
-NetPacket::ToNetPacketInitAck() const
+const NetPacketJoinGameAck *
+NetPacket::ToNetPacketJoinGameAck() const
+{
+ return NULL;
+}
+
+const NetPacketJoinGameError *
+NetPacket::ToNetPacketJoinGameError() const
{
return NULL;
}
@@ -43,38 +254,59 @@ NetPacket::ToNetPacketGameStart() const
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
-NetPacketInit::Clone() const
+NetPacketJoinGame::Clone() const
{
- boost::shared_ptr newPacket(new NetPacketInit);
+ boost::shared_ptr newPacket(new NetPacketJoinGame);
try
{
- newPacket->SetData(GetData());
+ newPacket->SetRawData(GetRawData());
} catch (const NetException &)
{
// Need to return the new packet anyway.
@@ -82,63 +314,92 @@ NetPacketInit::Clone() const
return newPacket;
}
-const NetPacketHeader *
-NetPacketInit::GetData() const
+void
+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
-NetPacketInit::SetData(const NetPacketHeader *p)
+NetPacketJoinGame::GetData(NetPacketJoinGame::Data &outData) const
{
- u_int16_t tmpLen = ntohs(p->length);
- if (tmpLen != sizeof(m_data)
- || ntohs(p->type) != NET_TYPE_INIT)
- {
- throw NetException(ERR_SOCK_INTERNAL, 0);
- }
+ // We assume that the data is valid. Validity has already been checked.
+ NetPacketJoinGameData *tmpData = (NetPacketJoinGameData *)GetRawData();
+ assert(tmpData);
- 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 *
-NetPacketInit::ToNetPacketInit() const
+const NetPacketJoinGame *
+NetPacketJoinGame::ToNetPacketJoinGame() const
{
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()
-{
- Init();
-}
-
-NetPacketInitAck::NetPacketInitAck(u_int32_t value)
-{
- Init();
- m_data.test = htonl(value);
-}
-
-NetPacketInitAck::~NetPacketInitAck()
+NetPacketJoinGameAck::NetPacketJoinGameAck()
+: NetPacket(NET_TYPE_JOIN_GAME_ACK, sizeof(NetPacketJoinGameAckData))
{
}
-void
-NetPacketInitAck::Init()
+NetPacketJoinGameAck::~NetPacketJoinGameAck()
{
- 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
-NetPacketInitAck::Clone() const
+NetPacketJoinGameAck::Clone() const
{
- boost::shared_ptr newPacket(new NetPacketInitAck);
+ boost::shared_ptr newPacket(new NetPacketJoinGameAck);
try
{
- newPacket->SetData(GetData());
+ newPacket->SetRawData(GetRawData());
} catch (const NetException &)
{
// Need to return the new packet anyway.
@@ -146,63 +407,176 @@ NetPacketInitAck::Clone() const
return newPacket;
}
-const NetPacketHeader *
-NetPacketInitAck::GetData() const
+void
+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
-NetPacketInitAck::SetData(const NetPacketHeader *p)
+NetPacketJoinGameAck::GetData(NetPacketJoinGameAck::Data &outData) const
{
- u_int16_t tmpLen = ntohs(p->length);
- if (tmpLen != sizeof(m_data)
- || ntohs(p->type) != NET_TYPE_INIT_ACK)
- {
- throw NetException(ERR_SOCK_INTERNAL, 0);
- }
+ NetPacketJoinGameAckData *tmpData = (NetPacketJoinGameAckData *)GetRawData();
+ assert(tmpData);
- 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 *
-NetPacketInitAck::ToNetPacketInitAck() const
+const NetPacketJoinGameAck *
+NetPacketJoinGameAck::ToNetPacketJoinGameAck() const
{
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
+NetPacketJoinGameError::Clone() const
+{
+ boost::shared_ptr 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()
+: NetPacket(NET_TYPE_GAME_START, sizeof(NetPacketGameStartData))
{
- Init();
-}
-
-NetPacketGameStart::NetPacketGameStart(u_int32_t value)
-{
- Init();
- m_data.test = htonl(value);
}
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
NetPacketGameStart::Clone() const
{
boost::shared_ptr newPacket(new NetPacketGameStart);
try
{
- newPacket->SetData(GetData());
+ newPacket->SetRawData(GetRawData());
} catch (const NetException &)
{
// Need to return the new packet anyway.
@@ -210,23 +584,24 @@ NetPacketGameStart::Clone() const
return newPacket;
}
-const NetPacketHeader *
-NetPacketGameStart::GetData() const
+void
+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
-NetPacketGameStart::SetData(const NetPacketHeader *p)
+NetPacketGameStart::GetData(NetPacketGameStart::Data &outData) const
{
- u_int16_t tmpLen = ntohs(p->length);
- if (tmpLen != sizeof(m_data)
- || ntohs(p->type) != NET_TYPE_GAME_START)
- {
- throw NetException(ERR_SOCK_INTERNAL, 0);
- }
+ NetPacketGameStartData *tmpData = (NetPacketGameStartData *)GetRawData();
+ assert(tmpData);
- memcpy(&m_data, p, tmpLen);
+ outData.yourCards[0] = ntohs(tmpData->yourCards[0]);
+ outData.yourCards[1] = ntohs(tmpData->yourCards[1]);
}
const NetPacketGameStart *
@@ -235,3 +610,23 @@ NetPacketGameStart::ToNetPacketGameStart() const
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);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
diff --git a/src/net/common/receiverhelper.cpp b/src/net/common/receiverhelper.cpp
index d9fd0d91..f321d8cf 100644
--- a/src/net/common/receiverhelper.cpp
+++ b/src/net/common/receiverhelper.cpp
@@ -98,50 +98,18 @@ ReceiverHelper::InternalGetPacket()
// This is necessary, because we use TCP.
// Packets may be received in multiple chunks or
// several packets may be received at once.
- if (m_tmpInBufSize >= sizeof(NetPacketHeader))
+ if (m_tmpInBufSize >= MIN_PACKET_SIZE)
{
- NetPacketHeader *tmpHeader = (NetPacketHeader *)m_tmpInBuf;
- u_int16_t tmpLen = ntohs(tmpHeader->length);
-
- if (tmpLen < sizeof(NetPacketHeader)
- || tmpLen > MAX_PACKET_SIZE)
+ try
{
- // 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;
}
- else if (m_tmpInBufSize >= tmpLen)
- {
- tmpPacket = InternalCreateNetPacket(tmpHeader);
- m_tmpInBufSize -= tmpLen;
- }
- }
- return tmpPacket;
-}
-
-boost::shared_ptr
-ReceiverHelper::InternalCreateNetPacket(const NetPacketHeader *p)
-{
- boost::shared_ptr tmpPacket;
-
- try
- {
- switch(ntohs(p->type))
- {
- case NET_TYPE_INIT:
- tmpPacket = boost::shared_ptr(new NetPacketInit);
- break;
- case NET_TYPE_INIT_ACK:
- tmpPacket = boost::shared_ptr(new NetPacketInitAck);
- break;
- case NET_TYPE_GAME_START:
- tmpPacket = boost::shared_ptr(new NetPacketGameStart);
- break;
- }
- if (tmpPacket.get())
- tmpPacket->SetData(p);
- } catch (const NetException &)
- {
- tmpPacket.reset();
}
return tmpPacket;
}
diff --git a/src/net/common/senderthread.cpp b/src/net/common/senderthread.cpp
index aa1ddd61..326245ab 100644
--- a/src/net/common/senderthread.cpp
+++ b/src/net/common/senderthread.cpp
@@ -71,11 +71,11 @@ SenderThread::Main()
if (IS_VALID_SOCKET(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)
{
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)
{
- m_tmpOutBufSize = m_tmpOutBufSize - (unsigned)bytesSent;
+ m_tmpOutBufSize -= (unsigned)bytesSent;
memmove(m_tmpOutBuf, m_tmpOutBuf + bytesSent, m_tmpOutBufSize);
}
else
diff --git a/src/net/common/serverrecvstate.cpp b/src/net/common/serverrecvstate.cpp
index c13d712e..7091da6c 100644
--- a/src/net/common/serverrecvstate.cpp
+++ b/src/net/common/serverrecvstate.cpp
@@ -72,10 +72,13 @@ ServerRecvStateInit::Process(ServerRecvThread &server)
{
if (session->GetState() == SessionData::Init)
{
- // Only accept init packets.
- if (packet->ToNetPacketInit())
+ // Only accept join game packets.
+ const NetPacketJoinGame *tmpPacket = packet->ToNetPacketJoinGame();
+ if (tmpPacket)
{
- boost::shared_ptr answer(new NetPacketInitAck);
+ // TODO: check password
+ // TODO: display name
+ boost::shared_ptr answer(new NetPacketJoinGameAck);
server.GetSender().Send(answer, recvSock);
session->SetState(SessionData::Established);
}
diff --git a/src/net/netpacket.h b/src/net/netpacket.h
index 638e5267..85156c66 100644
--- a/src/net/netpacket.h
+++ b/src/net/netpacket.h
@@ -25,128 +25,166 @@
#include
#include
-#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
-#define NET_TYPE_INIT_ACK 1
-#define NET_TYPE_GAME_START 2
-
-#ifdef _MSC_VER
- #pragma pack(push, 2)
-#else
- #pragma align 2
-#endif
-
-struct NetPacketHeader
+// TODO: move this somewhere else
+enum PlayerType
{
- u_int16_t type;
- u_int16_t length;
+ PLAYER_TYPE_COMPUTER,
+ PLAYER_TYPE_HUMAN
};
-struct NetPacketInitData
+enum JoinGameErrorReason
{
- NetPacketHeader head;
- u_int32_t test;
+ JOIN_UNSUPPORTED_VERSION,
+ JOIN_SERVER_FULL,
+ JOIN_GAME_RUNNING,
+ JOIN_INVALID_PASSWORD,
+ JOIN_UNKNOWN
};
-struct NetPacketInitAckData
-{
- NetPacketHeader head;
- u_int32_t test;
-};
+struct NetPacketHeader;
-struct NetPacketGameStartData
-{
- NetPacketHeader head;
- u_int32_t test;
-};
-
-#ifdef _MSC_VER
- #pragma pack(pop)
-#else
- #pragma align 0
-#endif
-
-class NetPacketInit;
-class NetPacketInitAck;
+class NetPacketJoinGame;
+class NetPacketJoinGameAck;
+class NetPacketJoinGameError;
class NetPacketGameStart;
class NetPacket
{
public:
+ static boost::shared_ptr Create(char *data, unsigned &dataSize);
+
+ NetPacket(u_int16_t type, u_int16_t initialLen);
virtual ~NetPacket();
virtual boost::shared_ptr Clone() const = 0;
- virtual void SetData(const NetPacketHeader *p) = 0;
- virtual const NetPacketHeader *GetData() const = 0;
+ const NetPacketHeader *GetRawData() const;
+ NetPacketHeader *GetRawData();
+ void SetRawData(const NetPacketHeader *p);
- virtual const NetPacketInit *ToNetPacketInit() const;
- virtual const NetPacketInitAck *ToNetPacketInitAck() const;
+ u_int16_t GetType() 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;
+
+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:
- NetPacketInit();
- NetPacketInit(u_int32_t value);
- virtual ~NetPacketInit();
+ struct Data
+ {
+ PlayerType ptype;
+ std::string playerName;
+ std::string password;
+ };
+
+ NetPacketJoinGame();
+ virtual ~NetPacketJoinGame();
virtual boost::shared_ptr Clone() const;
- virtual const NetPacketHeader *GetData() const;
- virtual void SetData(const NetPacketHeader *p);
+ void SetData(const Data &inData);
+ void GetData(Data &outData) const;
- virtual const NetPacketInit *ToNetPacketInit() const;
+ virtual const NetPacketJoinGame *ToNetPacketJoinGame() const;
protected:
- void Init();
-private:
- NetPacketInitData m_data;
+ virtual void Check(const NetPacketHeader* data) const;
};
-class NetPacketInitAck : public NetPacket
+class NetPacketJoinGameAck : public NetPacket
{
public:
- NetPacketInitAck();
- NetPacketInitAck(u_int32_t value);
- virtual ~NetPacketInitAck();
+ struct Data
+ {
+ 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 Clone() const;
- virtual const NetPacketHeader *GetData() const;
- virtual void SetData(const NetPacketHeader *p);
+ void SetData(const Data &inData);
+ void GetData(Data &outData) const;
- virtual const NetPacketInitAck *ToNetPacketInitAck() const;
+ virtual const NetPacketJoinGameAck *ToNetPacketJoinGameAck() const;
protected:
- void Init();
-private:
- NetPacketInitAckData m_data;
+ virtual void Check(const NetPacketHeader* data) const;
+};
+
+class NetPacketJoinGameError : public NetPacket
+{
+public:
+ struct Data
+ {
+ JoinGameErrorReason reason;
+ };
+
+ NetPacketJoinGameError();
+ virtual ~NetPacketJoinGameError();
+
+ virtual boost::shared_ptr 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
{
public:
+ struct Data
+ {
+ u_int16_t yourCards[2];
+ };
+
NetPacketGameStart();
- NetPacketGameStart(u_int32_t value);
virtual ~NetPacketGameStart();
virtual boost::shared_ptr Clone() const;
- virtual const NetPacketHeader *GetData() const;
- virtual void SetData(const NetPacketHeader *p);
+ void SetData(const Data &inData);
+ void GetData(Data &outData) const;
virtual const NetPacketGameStart *ToNetPacketGameStart() const;
protected:
- void Init();
-private:
- NetPacketGameStartData m_data;
+ virtual void Check(const NetPacketHeader* data) const;
};
#endif
diff --git a/src/net/receiverhelper.h b/src/net/receiverhelper.h
index 82090012..cddeb813 100644
--- a/src/net/receiverhelper.h
+++ b/src/net/receiverhelper.h
@@ -45,7 +45,6 @@ public:
protected:
boost::shared_ptr InternalGetPacket();
- boost::shared_ptr InternalCreateNetPacket(const NetPacketHeader *p);
private:
diff --git a/src/net/socket_msg.h b/src/net/socket_msg.h
index abcc1cf1..f4bf7967 100644
--- a/src/net/socket_msg.h
+++ b/src/net/socket_msg.h
@@ -36,6 +36,9 @@
#define ERR_SOCK_SEND_FAILED 14
#define ERR_SOCK_CONN_RESET 15
#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.
#define MSG_SOCK_INTERNAL_PENDING 0
diff --git a/src/session.cpp b/src/session.cpp
index 34678357..099cb23c 100755
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -64,7 +64,12 @@ void Session::startNetworkClient(const string &serverAddress, unsigned serverPor
if (myNetClient || !myGui)
return; // TODO: throw exception
myNetClient = new ClientThread(*myGui);
- myNetClient->Init(serverAddress, serverPort, ipv6, pwd);
+ myNetClient->Init(
+ serverAddress,
+ serverPort,
+ ipv6,
+ pwd,
+ myConfig->readConfigString("MyName"));
myNetClient->Run();
}
@@ -77,7 +82,8 @@ void Session::startNetworkClientForLocalServer()
"localhost",
myConfig->readConfigInt("ServerPort"),
myConfig->readConfigInt("ServerUseIpv6") == 1,
- myConfig->readConfigString("ServerPassword"));
+ myConfig->readConfigString("ServerPassword"),
+ myConfig->readConfigString("MyName"));
myNetClient->Run();
}