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:
lotodore
2007-03-20 02:20:50 +00:00
parent 5f7ff8ca54
commit ef10602d5c
33 changed files with 731 additions and 113 deletions
+2 -1
View File
@@ -145,9 +145,10 @@ SOURCES += src/game.cpp \
src/net/common/serverexception.cpp \
src/net/common/serverrecvthread.cpp \
src/net/common/serverrecvstate.cpp \
src/net/common/servercallback.cpp \
src/net/common/sessiondata.cpp \
src/net/common/socket_helper_cmn.cpp \
src/net/common/clientexception.cpp \
src/net/common/netcallback.cpp \
src/net/common/netcontext.cpp \
src/net/common/netexception.cpp \
src/net/common/receiverhelper.cpp \
+2 -1
View File
@@ -21,6 +21,7 @@
#define GUIINTERFACE_H
#include <net/clientcallback.h>
#include <net/servercallback.h>
#include <string>
class Game;
@@ -28,7 +29,7 @@ class Session;
class HandInterface;
class GuiInterface : public ClientCallback {
class GuiInterface : public ClientCallback, public ServerCallback {
public:
virtual ~GuiInterface();
@@ -44,9 +44,9 @@ void connectToServerDialogImpl::refresh(int actionID) {
default: { label_actionMessage->setText("Please wait..."); }
}
progressBar->setValue(actionID*(100/MSG_SOCK_LAST));
progressBar->setValue(actionID*(100/MSG_SOCK_LIMIT_CONNECT));
if (actionID == MSG_SOCK_LAST)
if (actionID == MSG_SOCK_LIMIT_CONNECT)
QTimer::singleShot(1000, this, SLOT(accept()));
}
+7 -2
View File
@@ -88,5 +88,10 @@ void GuiWrapper::meInAction() const { myW->meInAction(); }
void GuiWrapper::logPlayerActionMsg(string playerName, int action, int setValue) { myLog->logPlayerActionMsg(playerName, action, setValue); }
void GuiWrapper::logNewGameHandMsg(int gameID, int handID) { myLog->logNewGameHandMsg(gameID, handID); }
void GuiWrapper::SignalNetSuccess(int actionID) { myW->SignalNetSuccess(actionID); }
void GuiWrapper::SignalNetError(int errorID, int osErrorID) { myW->SignalNetError(errorID, osErrorID); }
void GuiWrapper::SignalNetClientConnect(int actionID) { myW->SignalNetClientConnect(actionID); }
void GuiWrapper::SignalNetClientGameInfo(int actionID) { myW->SignalNetClientGameInfo(actionID); }
void GuiWrapper::SignalNetClientError(int errorID, int osErrorID) { myW->SignalNetClientError(errorID, osErrorID); }
void GuiWrapper::SignalNetServerSuccess(int actionID) { }
void GuiWrapper::SignalNetServerError(int errorID, int osErrorID) { }
+6 -2
View File
@@ -88,8 +88,12 @@ public:
void logPlayerActionMsg(std::string playerName, int action, int setValue) ;
void logNewGameHandMsg(int gameID, int handID) ;
void SignalNetSuccess(int actionID);
void SignalNetError(int errorID, int osErrorID);
void SignalNetClientConnect(int actionID);
void SignalNetClientGameInfo(int actionID);
void SignalNetClientError(int errorID, int osErrorID);
void SignalNetServerSuccess(int actionID);
void SignalNetServerError(int errorID, int osErrorID);
private:
+17 -22
View File
@@ -26,7 +26,7 @@
#include "connecttoserverdialogimpl.h"
#include "createnetworkgamedialogimpl.h"
#include "startnetworkgamedialogimpl.h"
#include "waitforservertostartgamedialogimpl.h"
#include "startsplash.h"
#include "mycardspixmaplabel.h"
@@ -427,6 +427,7 @@ mainWindowImpl::mainWindowImpl(QMainWindow *parent)
myConnectToServerDialog = new connectToServerDialogImpl(this);
myStartNetworkGameDialog = new startNetworkGameDialogImpl(this);
myCreateNetworkGameDialog = new createNetworkGameDialogImpl(this);
myWaitingForServerGameDialog = new waitForServerToStartGameDialogImpl(this);
//Connects
connect(dealFlopCards0Timer, SIGNAL(timeout()), this, SLOT( dealFlopCards1() ));
@@ -481,8 +482,10 @@ mainWindowImpl::mainWindowImpl(QMainWindow *parent)
connect ( pushButton_break, SIGNAL( clicked()), this, SLOT ( breakButtonClicked() ) ); // auch wieder starten!!!!
//Nachrichten Thread-Save
connect(this, SIGNAL(SignalNetSuccess(int)), myConnectToServerDialog, SLOT(refresh(int)));
connect(this, SIGNAL(SignalNetError(int, int)), myConnectToServerDialog, SLOT(error(int, int)));
connect(this, SIGNAL(SignalNetClientConnect(int)), myConnectToServerDialog, SLOT(refresh(int)));
connect(this, SIGNAL(SignalNetClientGameInfo(int)), myWaitingForServerGameDialog, SLOT(refresh(int)));
// TODO Fix, errors MUST be global, not within one dialog.
connect(this, SIGNAL(SignalNetClientError(int, int)), myConnectToServerDialog, SLOT(error(int, int)));
// textBrowser_Log->append(QString::number(this->pos().x(),10)+" "+QString::number(this->pos().y(),10));
// textBrowser_Log->append(QString::number(this->x(),10)+" "+QString::number(this->y(),10));
@@ -586,29 +589,18 @@ void mainWindowImpl::callAboutPokerthDialog() {
void mainWindowImpl::callCreateNetworkGameDialog() {
myCreateNetworkGameDialog->showDialog();
myCreateNetworkGameDialog->exec();
//
if (myCreateNetworkGameDialog->result() == QDialog::Accepted ) {
mySession->terminateNetworkServer();
mySession->startNetworkServer();
//
// mySession->terminateNetworkClient();
//
// // Maybe use QUrl::toPunycode.
// mySession->startNetworkClient(
// myJoinNetworkGameDialog->lineEdit_ipAddress->text().toUtf8().constData(),
// myJoinNetworkGameDialog->spinBox_port->value(),
// myJoinNetworkGameDialog->checkBox_ipv6->isChecked(),
// myJoinNetworkGameDialog->lineEdit_password->text().toUtf8().constData());
//
// //Dialog mit Statusbalken
// myConnectToServerDialog->exec();
//
// if (myConnectToServerDialog->result() == QDialog::Rejected ) {
// mySession->terminateNetworkClient();
// actionJoin_network_Game->trigger(); // re-trigger
// }
//
myStartNetworkGameDialog->exec();
if (myStartNetworkGameDialog->result() == QDialog::Accepted ) {
mySession->initiateNetworkServerGame();
}
}
}
@@ -635,6 +627,9 @@ void mainWindowImpl::callJoinNetworkGameDialog() {
mySession->terminateNetworkClient();
actionJoin_network_Game->trigger(); // re-trigger
}
else {
myWaitingForServerGameDialog->exec();
}
}
+5 -2
View File
@@ -42,6 +42,7 @@ class joinNetworkGameDialogImpl;
class connectToServerDialogImpl;
class createNetworkGameDialogImpl;
class startNetworkGameDialogImpl;
class waitForServerToStartGameDialogImpl;
class QColor;
@@ -88,8 +89,9 @@ public:
void setSpeeds();
signals:
void SignalNetSuccess(int actionID);
void SignalNetError(int errorID, int osErrorID);
void SignalNetClientConnect(int actionID);
void SignalNetClientGameInfo(int actionID);
void SignalNetClientError(int errorID, int osErrorID);
public slots:
@@ -258,6 +260,7 @@ private:
connectToServerDialogImpl *myConnectToServerDialog;
startNetworkGameDialogImpl *myStartNetworkGameDialog;
createNetworkGameDialogImpl *myCreateNetworkGameDialog;
waitForServerToStartGameDialogImpl *myWaitingForServerGameDialog;
int maxQuantityPlayers;
@@ -31,6 +31,10 @@ waitForServerToStartGameDialogImpl::waitForServerToStartGameDialogImpl(QWidget *
}
void waitForServerToStartGameDialogImpl::refresh(int actionID) {
QTimer::singleShot(1000, this, SLOT(accept()));
}
void waitForServerToStartGameDialogImpl::cancel() {
}
@@ -35,6 +35,7 @@ public:
public slots:
void refresh(int actionID);
void cancel();
void keyPressEvent ( QKeyEvent * event );
};
+5 -3
View File
@@ -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
View File
@@ -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
{
+2 -1
View File
@@ -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
+44 -5
View File
@@ -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;
+8 -4
View File
@@ -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);
+8 -1
View File
@@ -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
View File
@@ -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;
}
+18 -12
View File
@@ -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()
{
}
+69 -2
View File
@@ -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;
}
+110
View File
@@ -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()
{
+21 -5
View File
@@ -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()))
{
+30
View File
@@ -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()
{
}
+2 -5
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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 -2
View File
@@ -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
+15 -3
View File
@@ -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
+7 -1
View File
@@ -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
+56
View File
@@ -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
+7 -1
View File
@@ -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
+9 -2
View File
@@ -85,14 +85,21 @@ void Session::startNetworkServer()
{
if (myNetServer)
return; // TODO: throw exception
myNetServer = new ServerThread();
myNetServer = new ServerThread(*myGui);
myNetServer->Init(
myConfig->readConfigInt("ServerPort"),
myConfig->readConfigInt("ServerUseIpv6") == 1,
"");
""); // TODO: use pwd
myNetServer->Run();
}
void Session::initiateNetworkServerGame()
{
if (!myNetServer)
return; // TODO: throw exception
myNetServer->StartGame();
}
void Session::terminateNetworkServer()
{
if (!myNetServer)
+1
View File
@@ -41,6 +41,7 @@ public:
void terminateNetworkClient();
void startNetworkServer();
void initiateNetworkServerGame();
void terminateNetworkServer();
void setActualGameID(const int& theValue) { actualGameID = theValue; }