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/serverexception.cpp \
src/net/common/serverrecvthread.cpp \ src/net/common/serverrecvthread.cpp \
src/net/common/serverrecvstate.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/socket_helper_cmn.cpp \
src/net/common/clientexception.cpp \ src/net/common/clientexception.cpp \
src/net/common/netcallback.cpp \
src/net/common/netcontext.cpp \ src/net/common/netcontext.cpp \
src/net/common/netexception.cpp \ src/net/common/netexception.cpp \
src/net/common/receiverhelper.cpp \ src/net/common/receiverhelper.cpp \
+2 -1
View File
@@ -21,6 +21,7 @@
#define GUIINTERFACE_H #define GUIINTERFACE_H
#include <net/clientcallback.h> #include <net/clientcallback.h>
#include <net/servercallback.h>
#include <string> #include <string>
class Game; class Game;
@@ -28,7 +29,7 @@ class Session;
class HandInterface; class HandInterface;
class GuiInterface : public ClientCallback { class GuiInterface : public ClientCallback, public ServerCallback {
public: public:
virtual ~GuiInterface(); virtual ~GuiInterface();
@@ -44,9 +44,9 @@ void connectToServerDialogImpl::refresh(int actionID) {
default: { label_actionMessage->setText("Please wait..."); } 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())); 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::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::logNewGameHandMsg(int gameID, int handID) { myLog->logNewGameHandMsg(gameID, handID); }
void GuiWrapper::SignalNetSuccess(int actionID) { myW->SignalNetSuccess(actionID); } void GuiWrapper::SignalNetClientConnect(int actionID) { myW->SignalNetClientConnect(actionID); }
void GuiWrapper::SignalNetError(int errorID, int osErrorID) { myW->SignalNetError(errorID, osErrorID); } 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 logPlayerActionMsg(std::string playerName, int action, int setValue) ;
void logNewGameHandMsg(int gameID, int handID) ; void logNewGameHandMsg(int gameID, int handID) ;
void SignalNetSuccess(int actionID); void SignalNetClientConnect(int actionID);
void SignalNetError(int errorID, int osErrorID); void SignalNetClientGameInfo(int actionID);
void SignalNetClientError(int errorID, int osErrorID);
void SignalNetServerSuccess(int actionID);
void SignalNetServerError(int errorID, int osErrorID);
private: private:
+17 -22
View File
@@ -26,7 +26,7 @@
#include "connecttoserverdialogimpl.h" #include "connecttoserverdialogimpl.h"
#include "createnetworkgamedialogimpl.h" #include "createnetworkgamedialogimpl.h"
#include "startnetworkgamedialogimpl.h" #include "startnetworkgamedialogimpl.h"
#include "waitforservertostartgamedialogimpl.h"
#include "startsplash.h" #include "startsplash.h"
#include "mycardspixmaplabel.h" #include "mycardspixmaplabel.h"
@@ -427,6 +427,7 @@ mainWindowImpl::mainWindowImpl(QMainWindow *parent)
myConnectToServerDialog = new connectToServerDialogImpl(this); myConnectToServerDialog = new connectToServerDialogImpl(this);
myStartNetworkGameDialog = new startNetworkGameDialogImpl(this); myStartNetworkGameDialog = new startNetworkGameDialogImpl(this);
myCreateNetworkGameDialog = new createNetworkGameDialogImpl(this); myCreateNetworkGameDialog = new createNetworkGameDialogImpl(this);
myWaitingForServerGameDialog = new waitForServerToStartGameDialogImpl(this);
//Connects //Connects
connect(dealFlopCards0Timer, SIGNAL(timeout()), this, SLOT( dealFlopCards1() )); 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!!!! connect ( pushButton_break, SIGNAL( clicked()), this, SLOT ( breakButtonClicked() ) ); // auch wieder starten!!!!
//Nachrichten Thread-Save //Nachrichten Thread-Save
connect(this, SIGNAL(SignalNetSuccess(int)), myConnectToServerDialog, SLOT(refresh(int))); connect(this, SIGNAL(SignalNetClientConnect(int)), myConnectToServerDialog, SLOT(refresh(int)));
connect(this, SIGNAL(SignalNetError(int, int)), myConnectToServerDialog, SLOT(error(int, 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->pos().x(),10)+" "+QString::number(this->pos().y(),10));
// textBrowser_Log->append(QString::number(this->x(),10)+" "+QString::number(this->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() { void mainWindowImpl::callCreateNetworkGameDialog() {
myCreateNetworkGameDialog->showDialog(); myCreateNetworkGameDialog->exec();
// //
if (myCreateNetworkGameDialog->result() == QDialog::Accepted ) { if (myCreateNetworkGameDialog->result() == QDialog::Accepted ) {
mySession->terminateNetworkServer(); mySession->terminateNetworkServer();
mySession->startNetworkServer(); mySession->startNetworkServer();
//
// mySession->terminateNetworkClient(); myStartNetworkGameDialog->exec();
//
// // Maybe use QUrl::toPunycode. if (myStartNetworkGameDialog->result() == QDialog::Accepted ) {
// mySession->startNetworkClient( mySession->initiateNetworkServerGame();
// 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
// }
//
} }
} }
@@ -635,6 +627,9 @@ void mainWindowImpl::callJoinNetworkGameDialog() {
mySession->terminateNetworkClient(); mySession->terminateNetworkClient();
actionJoin_network_Game->trigger(); // re-trigger actionJoin_network_Game->trigger(); // re-trigger
} }
else {
myWaitingForServerGameDialog->exec();
}
} }
+5 -2
View File
@@ -42,6 +42,7 @@ class joinNetworkGameDialogImpl;
class connectToServerDialogImpl; class connectToServerDialogImpl;
class createNetworkGameDialogImpl; class createNetworkGameDialogImpl;
class startNetworkGameDialogImpl; class startNetworkGameDialogImpl;
class waitForServerToStartGameDialogImpl;
class QColor; class QColor;
@@ -88,8 +89,9 @@ public:
void setSpeeds(); void setSpeeds();
signals: signals:
void SignalNetSuccess(int actionID); void SignalNetClientConnect(int actionID);
void SignalNetError(int errorID, int osErrorID); void SignalNetClientGameInfo(int actionID);
void SignalNetClientError(int errorID, int osErrorID);
public slots: public slots:
@@ -258,6 +260,7 @@ private:
connectToServerDialogImpl *myConnectToServerDialog; connectToServerDialogImpl *myConnectToServerDialog;
startNetworkGameDialogImpl *myStartNetworkGameDialog; startNetworkGameDialogImpl *myStartNetworkGameDialog;
createNetworkGameDialogImpl *myCreateNetworkGameDialog; createNetworkGameDialogImpl *myCreateNetworkGameDialog;
waitForServerToStartGameDialogImpl *myWaitingForServerGameDialog;
int maxQuantityPlayers; int maxQuantityPlayers;
@@ -31,6 +31,10 @@ waitForServerToStartGameDialogImpl::waitForServerToStartGameDialogImpl(QWidget *
} }
void waitForServerToStartGameDialogImpl::refresh(int actionID) {
QTimer::singleShot(1000, this, SLOT(accept()));
}
void waitForServerToStartGameDialogImpl::cancel() { void waitForServerToStartGameDialogImpl::cancel() {
} }
@@ -35,6 +35,7 @@ public:
public slots: public slots:
void refresh(int actionID);
void cancel(); void cancel();
void keyPressEvent ( QKeyEvent * event ); void keyPressEvent ( QKeyEvent * event );
}; };
+5 -3
View File
@@ -21,12 +21,14 @@
#ifndef _CLIENTCALLBACK_H_ #ifndef _CLIENTCALLBACK_H_
#define _CLIENTCALLBACK_H_ #define _CLIENTCALLBACK_H_
#include <net/netcallback.h> class ClientCallback
class ClientCallback : public NetCallback
{ {
public: public:
virtual ~ClientCallback(); virtual ~ClientCallback();
virtual void SignalNetClientConnect(int actionID) = 0;
virtual void SignalNetClientGameInfo(int actionID) = 0;
virtual void SignalNetClientError(int errorID, int osErrorID) = 0;
}; };
#endif #endif
+19 -1
View File
@@ -164,7 +164,7 @@ public:
virtual ~ClientStateWaitSession(); virtual ~ClientStateWaitSession();
// sleep. // select on socket.
virtual int Process(ClientThread &client); virtual int Process(ClientThread &client);
protected: protected:
@@ -173,6 +173,24 @@ protected:
ClientStateWaitSession(); 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). // State: Final (TODO).
class ClientStateFinal : public ClientState class ClientStateFinal : public ClientState
{ {
+2 -1
View File
@@ -24,10 +24,10 @@
#include <core/thread.h> #include <core/thread.h>
#include <string> #include <string>
#include <memory> #include <memory>
#include <net/clientcallback.h>
class ClientContext; class ClientContext;
class ClientState; class ClientState;
class ClientCallback;
class SenderThread; class SenderThread;
class ReceiverHelper; class ReceiverHelper;
class ClientSenderCallback; class ClientSenderCallback;
@@ -77,6 +77,7 @@ friend class ClientStateStartConnect;
friend class ClientStateConnecting; friend class ClientStateConnecting;
friend class ClientStateStartSession; friend class ClientStateStartSession;
friend class ClientStateWaitSession; friend class ClientStateWaitSession;
friend class ClientStateWaitGame;
}; };
#endif #endif
+44 -5
View File
@@ -321,7 +321,7 @@ ClientStateStartSession::~ClientStateStartSession()
int int
ClientStateStartSession::Process(ClientThread &client) 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.GetSender().Send(packet, client.GetContext().GetSocket());
client.SetState(ClientStateWaitSession::Instance()); client.SetState(ClientStateWaitSession::Instance());
@@ -356,15 +356,54 @@ ClientStateWaitSession::Process(ClientThread &client)
boost::shared_ptr<NetPacket> tmpPacket = client.GetReceiver().Recv(context.GetSocket()); boost::shared_ptr<NetPacket> tmpPacket = client.GetReceiver().Recv(context.GetSocket());
if (tmpPacket.get()) if (tmpPacket.get() && tmpPacket->ToNetPacketInitAck())
{ {
client.SetState(ClientStateFinal::Instance()); client.SetState(ClientStateWaitGame::Instance());
retVal = MSG_SOCK_SESSION_DONE; 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; retVal = MSG_SOCK_INTERNAL_PENDING;
Thread::Msleep(CLIENT_WAIT_TIMEOUT_MSEC);
} }
return retVal; return retVal;
+8 -4
View File
@@ -22,7 +22,6 @@
#include <net/clientcontext.h> #include <net/clientcontext.h>
#include <net/senderthread.h> #include <net/senderthread.h>
#include <net/receiverhelper.h> #include <net/receiverhelper.h>
#include <net/clientcallback.h>
#include <net/clientexception.h> #include <net/clientexception.h>
#include <net/socket_msg.h> #include <net/socket_msg.h>
@@ -43,7 +42,7 @@ public:
// For now, we ignore the socket. // For now, we ignore the socket.
// Just signal the error. // Just signal the error.
// We assume that the client thread will be terminated. // We assume that the client thread will be terminated.
m_client.GetCallback().SignalNetError(errorID, osErrorID); m_client.GetCallback().SignalNetClientError(errorID, osErrorID);
} }
private: private:
@@ -97,11 +96,16 @@ ClientThread::Main()
{ {
int msg = GetState().Process(*this); int msg = GetState().Process(*this);
if (msg != MSG_SOCK_INTERNAL_PENDING) 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) } catch (const NetException &e)
{ {
GetCallback().SignalNetError(e.GetErrorId(), e.GetOsErrorCode()); GetCallback().SignalNetClientError(e.GetErrorId(), e.GetOsErrorCode());
} }
GetSender().SignalTermination(); GetSender().SignalTermination();
GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT); GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT);
+8 -1
View File
@@ -22,7 +22,6 @@
ConnectData::ConnectData() ConnectData::ConnectData()
: m_sockfd(INVALID_SOCKET) : m_sockfd(INVALID_SOCKET)
{ {
bzero(&m_sockaddr, sizeof(m_sockaddr));
} }
ConnectData::~ConnectData() ConnectData::~ConnectData()
@@ -31,3 +30,11 @@ ConnectData::~ConnectData()
CLOSESOCKET(m_sockfd); 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()
{ {
} }
//----------------------------------------------------------------------------- const NetPacketInit *
NetPacket::ToNetPacketInit() const
TestNetPacket::TestNetPacket()
{ {
return NULL;
} }
TestNetPacket::TestNetPacket(u_int32_t value) const NetPacketInitAck *
NetPacket::ToNetPacketInitAck() const
{ {
m_data.head.type = htons(NET_TYPE_TEST); return NULL;
m_data.head.length = htons(sizeof(m_data)); }
const NetPacketGameStart *
NetPacket::ToNetPacketGameStart() const
{
return NULL;
}
//-----------------------------------------------------------------------------
NetPacketInit::NetPacketInit()
{
Init();
}
NetPacketInit::NetPacketInit(u_int32_t value)
{
Init();
m_data.test = htonl(value); m_data.test = htonl(value);
} }
TestNetPacket::~TestNetPacket() NetPacketInit::~NetPacketInit()
{ {
} }
NetPacketHeader *
TestNetPacket::GetData()
{
return (NetPacketHeader *)&m_data;
}
void 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); u_int16_t tmpLen = ntohs(p->length);
if (tmpLen != sizeof(m_data) if (tmpLen != sizeof(m_data)
|| ntohs(p->type) != NET_TYPE_TEST) || ntohs(p->type) != NET_TYPE_INIT)
{ {
throw NetException(ERR_SOCK_INTERNAL, 0); throw NetException(ERR_SOCK_INTERNAL, 0);
} }
@@ -61,3 +87,109 @@ TestNetPacket::SetData(const NetPacketHeader *p)
memcpy(&m_data, p, tmpLen); 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;
}
+13 -7
View File
@@ -24,7 +24,6 @@
using namespace std; using namespace std;
#define RECV_TIMEOUT_MSEC 50
ReceiverHelper::ReceiverHelper() ReceiverHelper::ReceiverHelper()
: m_socket(INVALID_SOCKET), m_tmpInBufSize(0) : m_socket(INVALID_SOCKET), m_tmpInBufSize(0)
@@ -124,19 +123,26 @@ ReceiverHelper::InternalCreateNetPacket(const NetPacketHeader *p)
{ {
boost::shared_ptr<NetPacket> tmpPacket; boost::shared_ptr<NetPacket> tmpPacket;
switch(ntohs(p->type))
{
case NET_TYPE_TEST:
try try
{ {
tmpPacket = boost::shared_ptr<NetPacket>(new TestNetPacket); 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); tmpPacket->SetData(p);
} catch (const NetException &) } catch (const NetException &)
{ {
tmpPacket.reset(); tmpPacket.reset();
} }
break;
}
return tmpPacket; return tmpPacket;
} }
@@ -17,10 +17,10 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * 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/serverrecvstate.h>
#include <net/serverrecvthread.h> #include <net/serverrecvthread.h>
#include <net/receiverhelper.h>
#include <net/senderthread.h>
#include <net/netpacket.h>
#include <net/socket_msg.h> #include <net/socket_msg.h>
using namespace std; using namespace std;
@@ -48,14 +51,78 @@ ServerRecvStateInit::~ServerRecvStateInit()
} }
void 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 int
ServerRecvStateInit::Process(ServerRecvThread &server) 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; 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 void
ServerRecvThread::AddConnection(boost::shared_ptr<ConnectData> data) ServerRecvThread::AddConnection(boost::shared_ptr<ConnectData> data)
{ {
@@ -91,6 +113,67 @@ ServerRecvThread::Main()
} }
GetSender().SignalTermination(); GetSender().SignalTermination();
GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT); 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 & ServerRecvState &
@@ -106,6 +189,33 @@ ServerRecvThread::SetState(ServerRecvState &newState)
m_curState = &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 & SenderThread &
ServerRecvThread::GetSender() ServerRecvThread::GetSender()
{ {
+21 -5
View File
@@ -29,7 +29,8 @@
#define NET_SERVER_LISTEN_BACKLOG 5 #define NET_SERVER_LISTEN_BACKLOG 5
ServerThread::ServerThread() ServerThread::ServerThread(ServerCallback &cb)
: m_callback(cb)
{ {
m_context.reset(new ServerContext); m_context.reset(new ServerContext);
} }
@@ -51,6 +52,22 @@ ServerThread::Init(unsigned serverPort, bool ipv6, const std::string &pwd)
context.SetPassword(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 void
ServerThread::Main() ServerThread::Main()
{ {
@@ -65,9 +82,9 @@ ServerThread::Main()
// The main server thread is simple. It only accepts connections. // The main server thread is simple. It only accepts connections.
AcceptLoop(); 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 if (selectResult > 0) // accept is possible
{ {
boost::shared_ptr<ConnectData> tmpData(new ConnectData); boost::shared_ptr<ConnectData> tmpData(new ConnectData);
socklen_t addrSize = sizeof(*tmpData->GetSockaddr()); tmpData->SetSocket(accept(context.GetSocket(), NULL, NULL));
tmpData->SetSocket(accept(context.GetSocket(), (struct sockaddr *)tmpData->GetSockaddr(), &addrSize));
if (!IS_VALID_SOCKET(tmpData->GetSocket())) 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;} {return m_sockfd;}
void SetSocket(SOCKET sockfd) void SetSocket(SOCKET sockfd)
{m_sockfd = sockfd;} {m_sockfd = sockfd;}
const sockaddr_storage *GetSockaddr() const
{return &m_sockaddr;} SOCKET ReleaseSocket();
sockaddr_storage *GetSockaddr()
{return &m_sockaddr;}
private: private:
SOCKET m_sockfd; SOCKET m_sockfd;
sockaddr_storage m_sockaddr;
}; };
#endif #endif
+73 -9
View File
@@ -26,7 +26,9 @@
#define MAX_PACKET_SIZE 256 #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 #ifdef _MSC_VER
#pragma pack(push, 2) #pragma pack(push, 2)
@@ -40,7 +42,19 @@ struct NetPacketHeader
u_int16_t length; 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; NetPacketHeader head;
u_int32_t test; u_int32_t test;
@@ -52,6 +66,9 @@ struct NetPacketInit
#pragma align 0 #pragma align 0
#endif #endif
class NetPacketInit;
class NetPacketInitAck;
class NetPacketGameStart;
class NetPacket class NetPacket
{ {
@@ -59,21 +76,68 @@ public:
virtual ~NetPacket(); virtual ~NetPacket();
virtual void SetData(const NetPacketHeader *p) = 0; 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: public:
TestNetPacket(); NetPacketInit();
TestNetPacket(u_int32_t value); NetPacketInit(u_int32_t value);
virtual ~TestNetPacket(); virtual ~NetPacketInit();
virtual NetPacketHeader *GetData(); virtual const NetPacketHeader *GetData() const;
virtual void SetData(const NetPacketHeader *p); virtual void SetData(const NetPacketHeader *p);
virtual const NetPacketInit *ToNetPacketInit() const;
protected: 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 #endif
+1
View File
@@ -29,6 +29,7 @@
// MUST be larger than MAX_PACKET_SIZE // MUST be larger than MAX_PACKET_SIZE
#define RECV_BUF_SIZE 10 * MAX_PACKET_SIZE #define RECV_BUF_SIZE 10 * MAX_PACKET_SIZE
#define RECV_TIMEOUT_MSEC 50
class ReceiverHelper class ReceiverHelper
@@ -16,18 +16,18 @@
* Free Software Foundation, Inc., * * Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * 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_ #ifndef _SERVERCALLBACK_H_
#define _NETCALLBACK_H_ #define _SERVERCALLBACK_H_
class NetCallback class ServerCallback
{ {
public: public:
virtual ~NetCallback(); virtual ~ServerCallback();
virtual void SignalNetSuccess(int actionID) = 0; virtual void SignalNetServerSuccess(int actionID) = 0;
virtual void SignalNetError(int errorID, int osErrorID) = 0; virtual void SignalNetServerError(int errorID, int osErrorID) = 0;
}; };
#endif #endif
+23 -1
View File
@@ -25,6 +25,7 @@
#include <net/connectdata.h> #include <net/connectdata.h>
#define SERVER_INITIAL_STATE ServerRecvStateInit #define SERVER_INITIAL_STATE ServerRecvStateInit
#define SERVER_START_GAME_STATE ServerRecvStateStartGame
class ServerRecvThread; class ServerRecvThread;
class ServerCallback; class ServerCallback;
@@ -35,7 +36,7 @@ public:
virtual ~ServerRecvState(); virtual ~ServerRecvState();
// Handling of a new TCP connection. // 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. // Main processing function of the current state.
virtual int Process(ServerRecvThread &server) = 0; virtual int Process(ServerRecvThread &server) = 0;
@@ -62,4 +63,25 @@ protected:
ServerRecvStateInit(); 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 #endif
+15 -3
View File
@@ -23,14 +23,17 @@
#include <core/thread.h> #include <core/thread.h>
#include <deque> #include <deque>
#include <map>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <net/connectdata.h> #include <net/connectdata.h>
#include <net/sessiondata.h>
class ServerRecvState; class ServerRecvState;
class SenderThread; class SenderThread;
class ReceiverHelper; class ReceiverHelper;
class ServerSenderCallback; class ServerSenderCallback;
class NetPacket;
class ServerRecvThread : public Thread class ServerRecvThread : public Thread
{ {
@@ -38,18 +41,24 @@ public:
ServerRecvThread(); ServerRecvThread();
virtual ~ServerRecvThread(); virtual ~ServerRecvThread();
void StartGame();
void SendToAllClients(boost::shared_ptr<NetPacket> packet);
void AddConnection(boost::shared_ptr<ConnectData> data); void AddConnection(boost::shared_ptr<ConnectData> data);
protected: protected:
typedef std::map<SOCKET, boost::shared_ptr<SessionData> > SocketSessionMap;
// Main function of the thread. // Main function of the thread.
virtual void Main(); virtual void Main();
SOCKET Select();
ServerRecvState &GetState(); ServerRecvState &GetState();
void SetState(ServerRecvState &newState); void SetState(ServerRecvState &newState);
//const ServerRecvContext &GetContext() const; boost::shared_ptr<SessionData> GetSession(SOCKET sock);
//ServerRecvContext &GetContext(); void AddSession(boost::shared_ptr<ConnectData> connData, boost::shared_ptr<SessionData> sessionData);
SenderThread &GetSender(); SenderThread &GetSender();
ReceiverHelper &GetReceiver(); ReceiverHelper &GetReceiver();
@@ -57,16 +66,19 @@ protected:
ServerSenderCallback &GetSenderCallback(); ServerSenderCallback &GetSenderCallback();
private: private:
//std::auto_ptr<ServerRecvContext> m_context;
std::deque<boost::shared_ptr<ConnectData> > m_connectQueue; std::deque<boost::shared_ptr<ConnectData> > m_connectQueue;
mutable boost::mutex m_connectQueueMutex; mutable boost::mutex m_connectQueueMutex;
ServerRecvState *m_curState; ServerRecvState *m_curState;
SocketSessionMap m_sessions;
std::auto_ptr<ReceiverHelper> m_receiver; std::auto_ptr<ReceiverHelper> m_receiver;
std::auto_ptr<SenderThread> m_sender; std::auto_ptr<SenderThread> m_sender;
std::auto_ptr<ServerSenderCallback> m_senderCallback; std::auto_ptr<ServerSenderCallback> m_senderCallback;
friend class ServerRecvStateInit;
}; };
#endif #endif
+7 -1
View File
@@ -24,6 +24,7 @@
#include <core/thread.h> #include <core/thread.h>
#include <string> #include <string>
#include <memory> #include <memory>
#include <net/servercallback.h>
class ServerContext; class ServerContext;
class ServerRecvThread; class ServerRecvThread;
@@ -33,11 +34,14 @@ class SenderThread;
class ServerThread : public Thread class ServerThread : public Thread
{ {
public: public:
ServerThread(/*ServerCallback &gui*/); ServerThread(ServerCallback &gui);
virtual ~ServerThread(); virtual ~ServerThread();
// Set the parameters. // Set the parameters.
void Init(unsigned serverPort, bool ipv6, const std::string &pwd); void Init(unsigned serverPort, bool ipv6, const std::string &pwd);
void StartGame();
ServerCallback &GetCallback();
protected: protected:
@@ -55,6 +59,8 @@ protected:
private: private:
std::auto_ptr<ServerContext> m_context; std::auto_ptr<ServerContext> m_context;
std::auto_ptr<ServerRecvThread> m_recvThread; std::auto_ptr<ServerRecvThread> m_recvThread;
ServerCallback &m_callback;
}; };
#endif #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_RECV_FAILED 13
#define ERR_SOCK_SEND_FAILED 14 #define ERR_SOCK_SEND_FAILED 14
#define ERR_SOCK_CONN_RESET 15 #define ERR_SOCK_CONN_RESET 15
#define ERR_SOCK_CONN_EXISTS 16
// This is an internal message which is not reported. // This is an internal message which is not reported.
#define MSG_SOCK_INTERNAL_PENDING 0 #define MSG_SOCK_INTERNAL_PENDING 0
// The following messages are reported. // The following messages are connect messages.
#define MSG_SOCK_INIT_DONE 1 #define MSG_SOCK_INIT_DONE 1
#define MSG_SOCK_RESOLVE_DONE 2 #define MSG_SOCK_RESOLVE_DONE 2
#define MSG_SOCK_CONNECT_DONE 3 #define MSG_SOCK_CONNECT_DONE 3
#define MSG_SOCK_SESSION_DONE 4 #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 #define MSG_SOCK_LAST MSG_SOCK_SESSION_DONE
#endif #endif
+9 -2
View File
@@ -85,14 +85,21 @@ void Session::startNetworkServer()
{ {
if (myNetServer) if (myNetServer)
return; // TODO: throw exception return; // TODO: throw exception
myNetServer = new ServerThread(); myNetServer = new ServerThread(*myGui);
myNetServer->Init( myNetServer->Init(
myConfig->readConfigInt("ServerPort"), myConfig->readConfigInt("ServerPort"),
myConfig->readConfigInt("ServerUseIpv6") == 1, myConfig->readConfigInt("ServerUseIpv6") == 1,
""); ""); // TODO: use pwd
myNetServer->Run(); myNetServer->Run();
} }
void Session::initiateNetworkServerGame()
{
if (!myNetServer)
return; // TODO: throw exception
myNetServer->StartGame();
}
void Session::terminateNetworkServer() void Session::terminateNetworkServer()
{ {
if (!myNetServer) if (!myNetServer)
+1
View File
@@ -41,6 +41,7 @@ public:
void terminateNetworkClient(); void terminateNetworkClient();
void startNetworkServer(); void startNetworkServer();
void initiateNetworkServerGame();
void terminateNetworkServer(); void terminateNetworkServer();
void setActualGameID(const int& theValue) { actualGameID = theValue; } void setActualGameID(const int& theValue) { actualGameID = theValue; }