Initial handshake and network game start. Works with multiple clients. Not yet stable, because it is not thread-safe. GUI callbacks not complete yet (server dialog not updated).
This commit is contained in:
@@ -21,12 +21,14 @@
|
||||
#ifndef _CLIENTCALLBACK_H_
|
||||
#define _CLIENTCALLBACK_H_
|
||||
|
||||
#include <net/netcallback.h>
|
||||
|
||||
class ClientCallback : public NetCallback
|
||||
class ClientCallback
|
||||
{
|
||||
public:
|
||||
virtual ~ClientCallback();
|
||||
|
||||
virtual void SignalNetClientConnect(int actionID) = 0;
|
||||
virtual void SignalNetClientGameInfo(int actionID) = 0;
|
||||
virtual void SignalNetClientError(int errorID, int osErrorID) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+19
-1
@@ -164,7 +164,7 @@ public:
|
||||
|
||||
virtual ~ClientStateWaitSession();
|
||||
|
||||
// sleep.
|
||||
// select on socket.
|
||||
virtual int Process(ClientThread &client);
|
||||
|
||||
protected:
|
||||
@@ -173,6 +173,24 @@ protected:
|
||||
ClientStateWaitSession();
|
||||
};
|
||||
|
||||
// State: Wait for start of the game or start info.
|
||||
class ClientStateWaitGame : public ClientState
|
||||
{
|
||||
public:
|
||||
// Access the state singleton.
|
||||
static ClientStateWaitGame &Instance();
|
||||
|
||||
virtual ~ClientStateWaitGame();
|
||||
|
||||
// select on socket.
|
||||
virtual int Process(ClientThread &client);
|
||||
|
||||
protected:
|
||||
|
||||
// Protected constructor - this is a singleton.
|
||||
ClientStateWaitGame();
|
||||
};
|
||||
|
||||
// State: Final (TODO).
|
||||
class ClientStateFinal : public ClientState
|
||||
{
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
#include <core/thread.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <net/clientcallback.h>
|
||||
|
||||
class ClientContext;
|
||||
class ClientState;
|
||||
class ClientCallback;
|
||||
class SenderThread;
|
||||
class ReceiverHelper;
|
||||
class ClientSenderCallback;
|
||||
@@ -77,6 +77,7 @@ friend class ClientStateStartConnect;
|
||||
friend class ClientStateConnecting;
|
||||
friend class ClientStateStartSession;
|
||||
friend class ClientStateWaitSession;
|
||||
friend class ClientStateWaitGame;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -321,7 +321,7 @@ ClientStateStartSession::~ClientStateStartSession()
|
||||
int
|
||||
ClientStateStartSession::Process(ClientThread &client)
|
||||
{
|
||||
boost::shared_ptr<NetPacket> packet(new TestNetPacket(10));
|
||||
boost::shared_ptr<NetPacket> packet(new NetPacketInit(10));
|
||||
client.GetSender().Send(packet, client.GetContext().GetSocket());
|
||||
|
||||
client.SetState(ClientStateWaitSession::Instance());
|
||||
@@ -356,15 +356,54 @@ ClientStateWaitSession::Process(ClientThread &client)
|
||||
|
||||
boost::shared_ptr<NetPacket> tmpPacket = client.GetReceiver().Recv(context.GetSocket());
|
||||
|
||||
if (tmpPacket.get())
|
||||
if (tmpPacket.get() && tmpPacket->ToNetPacketInitAck())
|
||||
{
|
||||
client.SetState(ClientStateFinal::Instance());
|
||||
client.SetState(ClientStateWaitGame::Instance());
|
||||
retVal = MSG_SOCK_SESSION_DONE;
|
||||
}
|
||||
else
|
||||
else // TODO: handle error packet
|
||||
{
|
||||
retVal = MSG_SOCK_INTERNAL_PENDING;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ClientStateWaitGame &
|
||||
ClientStateWaitGame::Instance()
|
||||
{
|
||||
static ClientStateWaitGame state;
|
||||
return state;
|
||||
}
|
||||
|
||||
ClientStateWaitGame::ClientStateWaitGame()
|
||||
{
|
||||
}
|
||||
|
||||
ClientStateWaitGame::~ClientStateWaitGame()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
ClientStateWaitGame::Process(ClientThread &client)
|
||||
{
|
||||
int retVal;
|
||||
ClientContext &context = client.GetContext();
|
||||
|
||||
// delegate to receiver helper class
|
||||
|
||||
boost::shared_ptr<NetPacket> tmpPacket = client.GetReceiver().Recv(context.GetSocket());
|
||||
|
||||
if (tmpPacket.get() && tmpPacket->ToNetPacketGameStart())
|
||||
{
|
||||
client.SetState(ClientStateFinal::Instance());
|
||||
retVal = MSG_SOCK_GAME_START;
|
||||
}
|
||||
else // TODO: handle error packet
|
||||
{
|
||||
retVal = MSG_SOCK_INTERNAL_PENDING;
|
||||
Thread::Msleep(CLIENT_WAIT_TIMEOUT_MSEC);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <net/clientcontext.h>
|
||||
#include <net/senderthread.h>
|
||||
#include <net/receiverhelper.h>
|
||||
#include <net/clientcallback.h>
|
||||
#include <net/clientexception.h>
|
||||
#include <net/socket_msg.h>
|
||||
|
||||
@@ -43,7 +42,7 @@ public:
|
||||
// For now, we ignore the socket.
|
||||
// Just signal the error.
|
||||
// We assume that the client thread will be terminated.
|
||||
m_client.GetCallback().SignalNetError(errorID, osErrorID);
|
||||
m_client.GetCallback().SignalNetClientError(errorID, osErrorID);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -97,11 +96,16 @@ ClientThread::Main()
|
||||
{
|
||||
int msg = GetState().Process(*this);
|
||||
if (msg != MSG_SOCK_INTERNAL_PENDING)
|
||||
GetCallback().SignalNetSuccess(msg);
|
||||
{
|
||||
if (msg <= MSG_SOCK_LIMIT_CONNECT)
|
||||
GetCallback().SignalNetClientConnect(msg);
|
||||
else
|
||||
GetCallback().SignalNetClientGameInfo(msg);
|
||||
}
|
||||
}
|
||||
} catch (const NetException &e)
|
||||
{
|
||||
GetCallback().SignalNetError(e.GetErrorId(), e.GetOsErrorCode());
|
||||
GetCallback().SignalNetClientError(e.GetErrorId(), e.GetOsErrorCode());
|
||||
}
|
||||
GetSender().SignalTermination();
|
||||
GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT);
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
ConnectData::ConnectData()
|
||||
: m_sockfd(INVALID_SOCKET)
|
||||
{
|
||||
bzero(&m_sockaddr, sizeof(m_sockaddr));
|
||||
}
|
||||
|
||||
ConnectData::~ConnectData()
|
||||
@@ -31,3 +30,11 @@ ConnectData::~ConnectData()
|
||||
CLOSESOCKET(m_sockfd);
|
||||
}
|
||||
|
||||
SOCKET
|
||||
ConnectData::ReleaseSocket()
|
||||
{
|
||||
SOCKET tmpSock = m_sockfd;
|
||||
m_sockfd = INVALID_SOCKET;
|
||||
return tmpSock;
|
||||
}
|
||||
|
||||
|
||||
+147
-15
@@ -25,35 +25,61 @@ NetPacket::~NetPacket()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
TestNetPacket::TestNetPacket()
|
||||
const NetPacketInit *
|
||||
NetPacket::ToNetPacketInit() const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TestNetPacket::TestNetPacket(u_int32_t value)
|
||||
const NetPacketInitAck *
|
||||
NetPacket::ToNetPacketInitAck() const
|
||||
{
|
||||
m_data.head.type = htons(NET_TYPE_TEST);
|
||||
m_data.head.length = htons(sizeof(m_data));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const NetPacketGameStart *
|
||||
NetPacket::ToNetPacketGameStart() const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NetPacketInit::NetPacketInit()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
NetPacketInit::NetPacketInit(u_int32_t value)
|
||||
{
|
||||
Init();
|
||||
m_data.test = htonl(value);
|
||||
}
|
||||
|
||||
TestNetPacket::~TestNetPacket()
|
||||
NetPacketInit::~NetPacketInit()
|
||||
{
|
||||
}
|
||||
|
||||
NetPacketHeader *
|
||||
TestNetPacket::GetData()
|
||||
{
|
||||
return (NetPacketHeader *)&m_data;
|
||||
}
|
||||
|
||||
void
|
||||
TestNetPacket::SetData(const NetPacketHeader *p)
|
||||
NetPacketInit::Init()
|
||||
{
|
||||
m_data.head.type = htons(NET_TYPE_INIT);
|
||||
m_data.head.length = htons(sizeof(m_data));
|
||||
m_data.test = htonl(0);
|
||||
}
|
||||
|
||||
const NetPacketHeader *
|
||||
NetPacketInit::GetData() const
|
||||
{
|
||||
return (const NetPacketHeader *)&m_data;
|
||||
}
|
||||
|
||||
void
|
||||
NetPacketInit::SetData(const NetPacketHeader *p)
|
||||
{
|
||||
u_int16_t tmpLen = ntohs(p->length);
|
||||
if (tmpLen != sizeof(m_data)
|
||||
|| ntohs(p->type) != NET_TYPE_TEST)
|
||||
|| ntohs(p->type) != NET_TYPE_INIT)
|
||||
{
|
||||
throw NetException(ERR_SOCK_INTERNAL, 0);
|
||||
}
|
||||
@@ -61,3 +87,109 @@ TestNetPacket::SetData(const NetPacketHeader *p)
|
||||
memcpy(&m_data, p, tmpLen);
|
||||
}
|
||||
|
||||
const NetPacketInit *
|
||||
NetPacketInit::ToNetPacketInit() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NetPacketInitAck::NetPacketInitAck()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
NetPacketInitAck::NetPacketInitAck(u_int32_t value)
|
||||
{
|
||||
Init();
|
||||
m_data.test = htonl(value);
|
||||
}
|
||||
|
||||
NetPacketInitAck::~NetPacketInitAck()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NetPacketInitAck::Init()
|
||||
{
|
||||
m_data.head.type = htons(NET_TYPE_INIT_ACK);
|
||||
m_data.head.length = htons(sizeof(m_data));
|
||||
m_data.test = htonl(0);
|
||||
}
|
||||
|
||||
const NetPacketHeader *
|
||||
NetPacketInitAck::GetData() const
|
||||
{
|
||||
return (const NetPacketHeader *)&m_data;
|
||||
}
|
||||
|
||||
void
|
||||
NetPacketInitAck::SetData(const NetPacketHeader *p)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
memcpy(&m_data, p, tmpLen);
|
||||
}
|
||||
|
||||
const NetPacketInitAck *
|
||||
NetPacketInitAck::ToNetPacketInitAck() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NetPacketGameStart::NetPacketGameStart()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
const NetPacketHeader *
|
||||
NetPacketGameStart::GetData() const
|
||||
{
|
||||
return (NetPacketHeader *)&m_data;
|
||||
}
|
||||
|
||||
void
|
||||
NetPacketGameStart::SetData(const NetPacketHeader *p)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
memcpy(&m_data, p, tmpLen);
|
||||
}
|
||||
|
||||
const NetPacketGameStart *
|
||||
NetPacketGameStart::ToNetPacketGameStart() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define RECV_TIMEOUT_MSEC 50
|
||||
|
||||
ReceiverHelper::ReceiverHelper()
|
||||
: m_socket(INVALID_SOCKET), m_tmpInBufSize(0)
|
||||
@@ -124,18 +123,25 @@ ReceiverHelper::InternalCreateNetPacket(const NetPacketHeader *p)
|
||||
{
|
||||
boost::shared_ptr<NetPacket> tmpPacket;
|
||||
|
||||
switch(ntohs(p->type))
|
||||
try
|
||||
{
|
||||
case NET_TYPE_TEST:
|
||||
try
|
||||
{
|
||||
tmpPacket = boost::shared_ptr<NetPacket>(new TestNetPacket);
|
||||
tmpPacket->SetData(p);
|
||||
} catch (const NetException &)
|
||||
{
|
||||
tmpPacket.reset();
|
||||
}
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <net/netcallback.h>
|
||||
#include <net/servercallback.h>
|
||||
|
||||
|
||||
NetCallback::~NetCallback()
|
||||
ServerCallback::~ServerCallback()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
#include <net/serverrecvstate.h>
|
||||
#include <net/serverrecvthread.h>
|
||||
#include <net/receiverhelper.h>
|
||||
#include <net/senderthread.h>
|
||||
#include <net/netpacket.h>
|
||||
#include <net/socket_msg.h>
|
||||
|
||||
using namespace std;
|
||||
@@ -48,14 +51,78 @@ ServerRecvStateInit::~ServerRecvStateInit()
|
||||
}
|
||||
|
||||
void
|
||||
ServerRecvStateInit::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> data)
|
||||
ServerRecvStateInit::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData)
|
||||
{
|
||||
boost::shared_ptr<SessionData> sessionData(new SessionData);
|
||||
server.AddSession(connData, sessionData);
|
||||
}
|
||||
|
||||
int
|
||||
ServerRecvStateInit::Process(ServerRecvThread &server)
|
||||
{
|
||||
Thread::Msleep(SERVER_WAIT_TIMEOUT_MSEC);
|
||||
SOCKET recvSock = server.Select();
|
||||
|
||||
if (recvSock != INVALID_SOCKET)
|
||||
{
|
||||
boost::shared_ptr<NetPacket> packet = server.GetReceiver().Recv(recvSock);
|
||||
boost::shared_ptr<SessionData> session = server.GetSession(recvSock);
|
||||
|
||||
// Ignore if no session / no packet.
|
||||
if (packet.get() && session.get())
|
||||
{
|
||||
if (session->GetState() == SessionData::Init)
|
||||
{
|
||||
// Only accept init packets.
|
||||
if (packet->ToNetPacketInit())
|
||||
{
|
||||
boost::shared_ptr<NetPacket> answer(new NetPacketInitAck);
|
||||
server.GetSender().Send(answer, recvSock);
|
||||
session->SetState(SessionData::Established);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO send error message, invalid packet
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO send error message, invalid state
|
||||
}
|
||||
}
|
||||
}
|
||||
return MSG_SOCK_INIT_DONE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ServerRecvStateStartGame &
|
||||
ServerRecvStateStartGame::Instance()
|
||||
{
|
||||
static ServerRecvStateStartGame state;
|
||||
return state;
|
||||
}
|
||||
|
||||
ServerRecvStateStartGame::ServerRecvStateStartGame()
|
||||
{
|
||||
}
|
||||
|
||||
ServerRecvStateStartGame::~ServerRecvStateStartGame()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ServerRecvStateStartGame::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData)
|
||||
{
|
||||
// TODO: send error msg
|
||||
}
|
||||
|
||||
int
|
||||
ServerRecvStateStartGame::Process(ServerRecvThread &server)
|
||||
{
|
||||
boost::shared_ptr<NetPacket> answer(new NetPacketGameStart);
|
||||
|
||||
server.SendToAllClients(answer);
|
||||
|
||||
return MSG_SOCK_INIT_DONE;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,28 @@ ServerRecvThread::~ServerRecvThread()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ServerRecvThread::StartGame()
|
||||
{
|
||||
// TODO: not thread safe. use flag or something.
|
||||
SetState(SERVER_START_GAME_STATE::Instance());
|
||||
}
|
||||
|
||||
void
|
||||
ServerRecvThread::SendToAllClients(boost::shared_ptr<NetPacket> packet)
|
||||
{
|
||||
// TODO: possible race condition if used in multithreading
|
||||
SocketSessionMap::iterator i = m_sessions.begin();
|
||||
SocketSessionMap::iterator end = m_sessions.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
// TODO: desparately need clone here, this is very dangerous.
|
||||
GetSender().Send(packet, i->first);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServerRecvThread::AddConnection(boost::shared_ptr<ConnectData> data)
|
||||
{
|
||||
@@ -91,6 +113,67 @@ ServerRecvThread::Main()
|
||||
}
|
||||
GetSender().SignalTermination();
|
||||
GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT);
|
||||
|
||||
// TODO: clear connection queue
|
||||
}
|
||||
|
||||
SOCKET
|
||||
ServerRecvThread::Select()
|
||||
{
|
||||
SOCKET retSock = INVALID_SOCKET;
|
||||
|
||||
if (m_sessions.empty())
|
||||
{
|
||||
Msleep(RECV_TIMEOUT_MSEC); // just sleep if there is no session
|
||||
}
|
||||
else
|
||||
{
|
||||
// wait for data
|
||||
SOCKET maxSock = 0;
|
||||
fd_set rdset;
|
||||
FD_ZERO(&rdset);
|
||||
|
||||
{
|
||||
SocketSessionMap::iterator i = m_sessions.begin();
|
||||
SocketSessionMap::iterator end = m_sessions.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
SOCKET tmpSock = i->first;
|
||||
FD_SET(tmpSock, &rdset);
|
||||
if (tmpSock > maxSock)
|
||||
maxSock = tmpSock;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = RECV_TIMEOUT_MSEC * 1000;
|
||||
int selectResult = select(maxSock + 1, &rdset, NULL, NULL, &timeout);
|
||||
if (!IS_VALID_SELECT(selectResult))
|
||||
{
|
||||
throw ServerException(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO());
|
||||
}
|
||||
if (selectResult > 0) // one (or more) of the sockets is readable
|
||||
{
|
||||
// Check which socket is readable, return the first.
|
||||
SocketSessionMap::iterator i = m_sessions.begin();
|
||||
SocketSessionMap::iterator end = m_sessions.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
SOCKET tmpSock = i->first;
|
||||
if (FD_ISSET(tmpSock, &rdset))
|
||||
{
|
||||
retSock = tmpSock;
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retSock;
|
||||
}
|
||||
|
||||
ServerRecvState &
|
||||
@@ -106,6 +189,33 @@ ServerRecvThread::SetState(ServerRecvState &newState)
|
||||
m_curState = &newState;
|
||||
}
|
||||
|
||||
boost::shared_ptr<SessionData>
|
||||
ServerRecvThread::GetSession(SOCKET sock)
|
||||
{
|
||||
boost::shared_ptr<SessionData> tmpSession;
|
||||
|
||||
SocketSessionMap::iterator pos = m_sessions.find(sock);
|
||||
if (pos != m_sessions.end())
|
||||
{
|
||||
tmpSession = pos->second;
|
||||
}
|
||||
return tmpSession;
|
||||
}
|
||||
|
||||
void
|
||||
ServerRecvThread::AddSession(boost::shared_ptr<ConnectData> connData, boost::shared_ptr<SessionData> sessionData)
|
||||
{
|
||||
SocketSessionMap::iterator pos = m_sessions.lower_bound(connData->GetSocket());
|
||||
|
||||
// If pos points to a pair whose key is equivalent to the socket, this handle
|
||||
// already exists within the list.
|
||||
if (pos != m_sessions.end() && connData->GetSocket() == pos->first)
|
||||
{
|
||||
throw ServerException(ERR_SOCK_CONN_EXISTS, 0);
|
||||
}
|
||||
m_sessions.insert(pos, SocketSessionMap::value_type(connData->ReleaseSocket(), sessionData));
|
||||
}
|
||||
|
||||
SenderThread &
|
||||
ServerRecvThread::GetSender()
|
||||
{
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
#define NET_SERVER_LISTEN_BACKLOG 5
|
||||
|
||||
|
||||
ServerThread::ServerThread()
|
||||
ServerThread::ServerThread(ServerCallback &cb)
|
||||
: m_callback(cb)
|
||||
{
|
||||
m_context.reset(new ServerContext);
|
||||
}
|
||||
@@ -51,6 +52,22 @@ ServerThread::Init(unsigned serverPort, bool ipv6, const std::string &pwd)
|
||||
context.SetPassword(pwd);
|
||||
}
|
||||
|
||||
void
|
||||
ServerThread::StartGame()
|
||||
{
|
||||
if (!IsRunning())
|
||||
return; // TODO: throw exception
|
||||
|
||||
// TODO: possible race condition
|
||||
GetRecvThread().StartGame();
|
||||
}
|
||||
|
||||
ServerCallback &
|
||||
ServerThread::GetCallback()
|
||||
{
|
||||
return m_callback;
|
||||
}
|
||||
|
||||
void
|
||||
ServerThread::Main()
|
||||
{
|
||||
@@ -65,9 +82,9 @@ ServerThread::Main()
|
||||
// The main server thread is simple. It only accepts connections.
|
||||
AcceptLoop();
|
||||
}
|
||||
} catch (const NetException &)
|
||||
} catch (const NetException &e)
|
||||
{
|
||||
// TODO: callback.
|
||||
GetCallback().SignalNetServerError(e.GetErrorId(), e.GetOsErrorCode());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,8 +158,7 @@ ServerThread::AcceptLoop()
|
||||
if (selectResult > 0) // accept is possible
|
||||
{
|
||||
boost::shared_ptr<ConnectData> tmpData(new ConnectData);
|
||||
socklen_t addrSize = sizeof(*tmpData->GetSockaddr());
|
||||
tmpData->SetSocket(accept(context.GetSocket(), (struct sockaddr *)tmpData->GetSockaddr(), &addrSize));
|
||||
tmpData->SetSocket(accept(context.GetSocket(), NULL, NULL));
|
||||
|
||||
if (!IS_VALID_SOCKET(tmpData->GetSocket()))
|
||||
{
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Lothar May *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <net/sessiondata.h>
|
||||
|
||||
SessionData::SessionData()
|
||||
: m_id(SESSION_ID_INIT), m_state(SessionData::Init)
|
||||
{
|
||||
}
|
||||
|
||||
SessionData::~SessionData()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -33,14 +33,11 @@ public:
|
||||
{return m_sockfd;}
|
||||
void SetSocket(SOCKET sockfd)
|
||||
{m_sockfd = sockfd;}
|
||||
const sockaddr_storage *GetSockaddr() const
|
||||
{return &m_sockaddr;}
|
||||
sockaddr_storage *GetSockaddr()
|
||||
{return &m_sockaddr;}
|
||||
|
||||
SOCKET ReleaseSocket();
|
||||
|
||||
private:
|
||||
SOCKET m_sockfd;
|
||||
sockaddr_storage m_sockaddr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+73
-9
@@ -26,7 +26,9 @@
|
||||
|
||||
#define MAX_PACKET_SIZE 256
|
||||
|
||||
#define NET_TYPE_TEST 0
|
||||
#define NET_TYPE_INIT 0
|
||||
#define NET_TYPE_INIT_ACK 1
|
||||
#define NET_TYPE_GAME_START 2
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 2)
|
||||
@@ -40,7 +42,19 @@ struct NetPacketHeader
|
||||
u_int16_t length;
|
||||
};
|
||||
|
||||
struct NetPacketInit
|
||||
struct NetPacketInitData
|
||||
{
|
||||
NetPacketHeader head;
|
||||
u_int32_t test;
|
||||
};
|
||||
|
||||
struct NetPacketInitAckData
|
||||
{
|
||||
NetPacketHeader head;
|
||||
u_int32_t test;
|
||||
};
|
||||
|
||||
struct NetPacketGameStartData
|
||||
{
|
||||
NetPacketHeader head;
|
||||
u_int32_t test;
|
||||
@@ -52,6 +66,9 @@ struct NetPacketInit
|
||||
#pragma align 0
|
||||
#endif
|
||||
|
||||
class NetPacketInit;
|
||||
class NetPacketInitAck;
|
||||
class NetPacketGameStart;
|
||||
|
||||
class NetPacket
|
||||
{
|
||||
@@ -59,21 +76,68 @@ public:
|
||||
virtual ~NetPacket();
|
||||
|
||||
virtual void SetData(const NetPacketHeader *p) = 0;
|
||||
virtual NetPacketHeader *GetData() = 0;
|
||||
virtual const NetPacketHeader *GetData() const = 0;
|
||||
|
||||
virtual const NetPacketInit *ToNetPacketInit() const;
|
||||
virtual const NetPacketInitAck *ToNetPacketInitAck() const;
|
||||
virtual const NetPacketGameStart *ToNetPacketGameStart() const;
|
||||
};
|
||||
|
||||
class TestNetPacket : public NetPacket
|
||||
class NetPacketInit : public NetPacket
|
||||
{
|
||||
public:
|
||||
TestNetPacket();
|
||||
TestNetPacket(u_int32_t value);
|
||||
virtual ~TestNetPacket();
|
||||
NetPacketInit();
|
||||
NetPacketInit(u_int32_t value);
|
||||
virtual ~NetPacketInit();
|
||||
|
||||
virtual NetPacketHeader *GetData();
|
||||
virtual const NetPacketHeader *GetData() const;
|
||||
virtual void SetData(const NetPacketHeader *p);
|
||||
|
||||
virtual const NetPacketInit *ToNetPacketInit() const;
|
||||
|
||||
protected:
|
||||
NetPacketInit m_data;
|
||||
void Init();
|
||||
|
||||
private:
|
||||
NetPacketInitData m_data;
|
||||
};
|
||||
|
||||
class NetPacketInitAck : public NetPacket
|
||||
{
|
||||
public:
|
||||
NetPacketInitAck();
|
||||
NetPacketInitAck(u_int32_t value);
|
||||
virtual ~NetPacketInitAck();
|
||||
|
||||
virtual const NetPacketHeader *GetData() const;
|
||||
virtual void SetData(const NetPacketHeader *p);
|
||||
|
||||
virtual const NetPacketInitAck *ToNetPacketInitAck() const;
|
||||
|
||||
protected:
|
||||
void Init();
|
||||
|
||||
private:
|
||||
NetPacketInitAckData m_data;
|
||||
};
|
||||
|
||||
class NetPacketGameStart : public NetPacket
|
||||
{
|
||||
public:
|
||||
NetPacketGameStart();
|
||||
NetPacketGameStart(u_int32_t value);
|
||||
virtual ~NetPacketGameStart();
|
||||
|
||||
virtual const NetPacketHeader *GetData() const;
|
||||
virtual void SetData(const NetPacketHeader *p);
|
||||
|
||||
virtual const NetPacketGameStart *ToNetPacketGameStart() const;
|
||||
|
||||
protected:
|
||||
void Init();
|
||||
|
||||
private:
|
||||
NetPacketGameStartData m_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
// MUST be larger than MAX_PACKET_SIZE
|
||||
#define RECV_BUF_SIZE 10 * MAX_PACKET_SIZE
|
||||
#define RECV_TIMEOUT_MSEC 50
|
||||
|
||||
|
||||
class ReceiverHelper
|
||||
|
||||
@@ -16,18 +16,18 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
/* Generic callback interface for network system. */
|
||||
/* Callback interface for network server gui. */
|
||||
|
||||
#ifndef _NETCALLBACK_H_
|
||||
#define _NETCALLBACK_H_
|
||||
#ifndef _SERVERCALLBACK_H_
|
||||
#define _SERVERCALLBACK_H_
|
||||
|
||||
class NetCallback
|
||||
class ServerCallback
|
||||
{
|
||||
public:
|
||||
virtual ~NetCallback();
|
||||
virtual ~ServerCallback();
|
||||
|
||||
virtual void SignalNetSuccess(int actionID) = 0;
|
||||
virtual void SignalNetError(int errorID, int osErrorID) = 0;
|
||||
virtual void SignalNetServerSuccess(int actionID) = 0;
|
||||
virtual void SignalNetServerError(int errorID, int osErrorID) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -24,7 +24,8 @@
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <net/connectdata.h>
|
||||
|
||||
#define SERVER_INITIAL_STATE ServerRecvStateInit
|
||||
#define SERVER_INITIAL_STATE ServerRecvStateInit
|
||||
#define SERVER_START_GAME_STATE ServerRecvStateStartGame
|
||||
|
||||
class ServerRecvThread;
|
||||
class ServerCallback;
|
||||
@@ -35,7 +36,7 @@ public:
|
||||
virtual ~ServerRecvState();
|
||||
|
||||
// Handling of a new TCP connection.
|
||||
virtual void HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> data) = 0;
|
||||
virtual void HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData) = 0;
|
||||
|
||||
// Main processing function of the current state.
|
||||
virtual int Process(ServerRecvThread &server) = 0;
|
||||
@@ -62,4 +63,25 @@ protected:
|
||||
ServerRecvStateInit();
|
||||
};
|
||||
|
||||
// State: Start server game.
|
||||
class ServerRecvStateStartGame : public ServerRecvState
|
||||
{
|
||||
public:
|
||||
// Access the state singleton.
|
||||
static ServerRecvStateStartGame &Instance();
|
||||
|
||||
virtual ~ServerRecvStateStartGame();
|
||||
|
||||
//
|
||||
virtual void HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> data);
|
||||
|
||||
//
|
||||
virtual int Process(ServerRecvThread &server);
|
||||
|
||||
protected:
|
||||
|
||||
// Protected constructor - this is a singleton.
|
||||
ServerRecvStateStartGame();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,14 +23,17 @@
|
||||
|
||||
#include <core/thread.h>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <net/connectdata.h>
|
||||
#include <net/sessiondata.h>
|
||||
|
||||
class ServerRecvState;
|
||||
class SenderThread;
|
||||
class ReceiverHelper;
|
||||
class ServerSenderCallback;
|
||||
class NetPacket;
|
||||
|
||||
class ServerRecvThread : public Thread
|
||||
{
|
||||
@@ -38,18 +41,24 @@ public:
|
||||
ServerRecvThread();
|
||||
virtual ~ServerRecvThread();
|
||||
|
||||
void StartGame();
|
||||
void SendToAllClients(boost::shared_ptr<NetPacket> packet);
|
||||
void AddConnection(boost::shared_ptr<ConnectData> data);
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::map<SOCKET, boost::shared_ptr<SessionData> > SocketSessionMap;
|
||||
|
||||
// Main function of the thread.
|
||||
virtual void Main();
|
||||
|
||||
SOCKET Select();
|
||||
|
||||
ServerRecvState &GetState();
|
||||
void SetState(ServerRecvState &newState);
|
||||
|
||||
//const ServerRecvContext &GetContext() const;
|
||||
//ServerRecvContext &GetContext();
|
||||
boost::shared_ptr<SessionData> GetSession(SOCKET sock);
|
||||
void AddSession(boost::shared_ptr<ConnectData> connData, boost::shared_ptr<SessionData> sessionData);
|
||||
|
||||
SenderThread &GetSender();
|
||||
ReceiverHelper &GetReceiver();
|
||||
@@ -57,16 +66,19 @@ protected:
|
||||
ServerSenderCallback &GetSenderCallback();
|
||||
|
||||
private:
|
||||
//std::auto_ptr<ServerRecvContext> m_context;
|
||||
|
||||
std::deque<boost::shared_ptr<ConnectData> > m_connectQueue;
|
||||
mutable boost::mutex m_connectQueueMutex;
|
||||
ServerRecvState *m_curState;
|
||||
|
||||
SocketSessionMap m_sessions;
|
||||
|
||||
std::auto_ptr<ReceiverHelper> m_receiver;
|
||||
std::auto_ptr<SenderThread> m_sender;
|
||||
|
||||
std::auto_ptr<ServerSenderCallback> m_senderCallback;
|
||||
|
||||
friend class ServerRecvStateInit;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <core/thread.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <net/servercallback.h>
|
||||
|
||||
class ServerContext;
|
||||
class ServerRecvThread;
|
||||
@@ -33,11 +34,14 @@ class SenderThread;
|
||||
class ServerThread : public Thread
|
||||
{
|
||||
public:
|
||||
ServerThread(/*ServerCallback &gui*/);
|
||||
ServerThread(ServerCallback &gui);
|
||||
virtual ~ServerThread();
|
||||
|
||||
// Set the parameters.
|
||||
void Init(unsigned serverPort, bool ipv6, const std::string &pwd);
|
||||
void StartGame();
|
||||
|
||||
ServerCallback &GetCallback();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -55,6 +59,8 @@ protected:
|
||||
private:
|
||||
std::auto_ptr<ServerContext> m_context;
|
||||
std::auto_ptr<ServerRecvThread> m_recvThread;
|
||||
|
||||
ServerCallback &m_callback;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Lothar May *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
/* Session data (a session is a valid client connection). */
|
||||
|
||||
#ifndef _SESSIONDATA_H_
|
||||
#define _SESSIONDATA_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#define SESSION_ID_INIT 0
|
||||
|
||||
class SessionData
|
||||
{
|
||||
public:
|
||||
enum State { Init, Established };
|
||||
|
||||
SessionData();
|
||||
~SessionData();
|
||||
|
||||
unsigned GetId() const
|
||||
{return m_id;}
|
||||
void SetId(unsigned id)
|
||||
{m_id = id;}
|
||||
State GetState() const
|
||||
{return m_state;}
|
||||
void SetState(State state)
|
||||
{m_state = state;}
|
||||
|
||||
const std::string &GetClientAddr() const
|
||||
{return m_clientAddr;}
|
||||
void SetClientAddr(const std::string &addr)
|
||||
{m_clientAddr = addr;}
|
||||
|
||||
private:
|
||||
unsigned m_id;
|
||||
State m_state;
|
||||
std::string m_clientAddr;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -35,16 +35,22 @@
|
||||
#define ERR_SOCK_RECV_FAILED 13
|
||||
#define ERR_SOCK_SEND_FAILED 14
|
||||
#define ERR_SOCK_CONN_RESET 15
|
||||
#define ERR_SOCK_CONN_EXISTS 16
|
||||
|
||||
// This is an internal message which is not reported.
|
||||
#define MSG_SOCK_INTERNAL_PENDING 0
|
||||
|
||||
// The following messages are reported.
|
||||
// The following messages are connect messages.
|
||||
#define MSG_SOCK_INIT_DONE 1
|
||||
#define MSG_SOCK_RESOLVE_DONE 2
|
||||
#define MSG_SOCK_CONNECT_DONE 3
|
||||
#define MSG_SOCK_SESSION_DONE 4
|
||||
|
||||
#define MSG_SOCK_LIMIT_CONNECT MSG_SOCK_SESSION_DONE
|
||||
|
||||
// The following messages are game messages.
|
||||
#define MSG_SOCK_GAME_START 5
|
||||
|
||||
#define MSG_SOCK_LAST MSG_SOCK_SESSION_DONE
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user