diff --git a/pokerth_lib.pro b/pokerth_lib.pro index 0702493c..d86a94dc 100644 --- a/pokerth_lib.pro +++ b/pokerth_lib.pro @@ -81,6 +81,7 @@ HEADERS += \ src/net/irccallback.h \ src/net/ircthread.h \ src/net/netexception.h \ + src/net/servermanager.h \ src/core/tinyxml/tinystr.h \ src/core/tinyxml/tinyxml.h \ src/core/libircclient/include/libircclient.h \ @@ -170,6 +171,7 @@ SOURCES += \ src/net/common/receiverhelper.cpp \ src/net/common/irccallback.cpp \ src/net/common/ircthread.cpp \ + src/net/common/servermanager.cpp \ src/gui/generic/serverguiwrapper.cpp \ src/gui/qttoolsinterface.cpp diff --git a/src/game_defs.h b/src/game_defs.h index 274c252a..fb1dfbec 100644 --- a/src/game_defs.h +++ b/src/game_defs.h @@ -34,6 +34,11 @@ #define POKERTH_BETA_REVISION 5 +enum ServerNetworkMode { + NETWORK_MODE_TCP = 1, + NETWORK_MODE_SCTP = 2, + NETWORK_MODE_TCP_SCTP = 3}; + enum GameState { GAME_STATE_PREFLOP = 0, GAME_STATE_FLOP, diff --git a/src/net/common/serveracceptthread.cpp b/src/net/common/serveracceptthread.cpp index 3c786441..03973879 100644 --- a/src/net/common/serveracceptthread.cpp +++ b/src/net/common/serveracceptthread.cpp @@ -35,11 +35,10 @@ using namespace std; -ServerAcceptThread::ServerAcceptThread(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager) -: m_gui(gui) +ServerAcceptThread::ServerAcceptThread(ServerCallback &serverCallback) +: m_serverCallback(serverCallback) { m_context.reset(new ServerContext); - m_lobbyThread.reset(new ServerLobbyThread(gui, config, avatarManager)); } ServerAcceptThread::~ServerAcceptThread() @@ -47,7 +46,7 @@ ServerAcceptThread::~ServerAcceptThread() } void -ServerAcceptThread::Init(unsigned serverPort, bool ipv6, bool sctp, const string &pwd, const string &logDir, boost::shared_ptr ircThread) +ServerAcceptThread::Init(unsigned serverPort, bool ipv6, bool sctp, const string &pwd, const string &logDir, boost::shared_ptr lobbyThread) { if (IsRunning()) { @@ -63,82 +62,14 @@ ServerAcceptThread::Init(unsigned serverPort, bool ipv6, bool sctp, const string context.SetAddrFamily(socket_has_dual_stack() ? AF_INET6 : (ipv6 ? AF_INET6 : AF_INET)); context.SetServerPort(serverPort); + m_lobbyThread = lobbyThread; GetLobbyThread().Init(pwd, logDir); - m_ircThread = ircThread; } ServerCallback & ServerAcceptThread::GetCallback() { - return m_gui; -} - -GuiInterface & -ServerAcceptThread::GetGui() -{ - return m_gui; -} - -void -ServerAcceptThread::SignalIrcConnect(const std::string &server) -{ - LOG_MSG("Connected to IRC server " << server << "."); -} - -void -ServerAcceptThread::SignalIrcSelfJoined(const std::string &nickName, const std::string &channel) -{ - LOG_MSG("Joined IRC channel " << channel << " as user " << nickName << "."); - m_ircNick = nickName; -} - -void -ServerAcceptThread::SignalIrcChatMsg(const std::string &nickName, const std::string &msg) -{ - if (m_ircThread) - { - istringstream msgStream(msg); - string target; - msgStream >> target; - if (boost::algorithm::iequals(target, m_ircNick + ":")) - { - string command; - msgStream >> command; - if (command == "kick") - { - while (msgStream.peek() == ' ') - msgStream.get(); - string playerName(msgStream.str().substr(msgStream.tellg())); - if (!playerName.empty()) - { - if (GetLobbyThread().KickPlayerByName(playerName)) - m_ircThread->SendChatMessage(nickName + ": Successfully kicked player \"" + playerName + "\" from the server."); - else - m_ircThread->SendChatMessage(nickName + ": Player \"" + playerName + "\" was not found on the server."); - } - } - else if (command == "stat") - { - ServerStats tmpStats = GetLobbyThread().GetStats(); - ostringstream statStream; - statStream - << "Players on Server: " << tmpStats.numberOfPlayersOnServer; - m_ircThread->SendChatMessage(statStream.str()); - } - else - m_ircThread->SendChatMessage(nickName + ": Invalid command \"" + command + "\"."); - } - } -} - -void -ServerAcceptThread::SignalIrcError(int errorCode) -{ -} - -void -ServerAcceptThread::SignalIrcServerError(int errorCode) -{ + return m_serverCallback; } void @@ -147,11 +78,8 @@ ServerAcceptThread::Main() try { Listen(); - if (m_ircThread) - m_ircThread->Run(); - GetLobbyThread().Run(); - while (!ShouldTerminate() && !GetLobbyThread().Join(0)) + while (!ShouldTerminate()) { // The main server thread is simple. It only accepts connections. AcceptLoop(); @@ -161,14 +89,6 @@ ServerAcceptThread::Main() GetCallback().SignalNetServerError(e.GetErrorId(), e.GetOsErrorCode()); LOG_ERROR(e.what()); } - GetLobbyThread().SignalTermination(); - GetLobbyThread().Join(LOBBY_THREAD_TERMINATE_TIMEOUT_MSEC); - - if (m_ircThread) - { - m_ircThread->SignalTermination(); - m_ircThread->Join(ADMIN_IRC_TERMINATE_TIMEOUT_MSEC); - } } void diff --git a/src/net/common/servermanager.cpp b/src/net/common/servermanager.cpp new file mode 100644 index 00000000..0afa1387 --- /dev/null +++ b/src/net/common/servermanager.cpp @@ -0,0 +1,179 @@ +/*************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; + +ServerManager::ServerManager(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager) +: m_gui(gui), m_playerConfig(config), m_avatarManager(avatarManager) +{ +} + +ServerManager::~ServerManager() +{ +} + +void +ServerManager::Init(unsigned serverPort, bool ipv6, ServerNetworkMode mode, const string &pwd, const string &logDir, boost::shared_ptr ircThread) +{ + m_lobbyThread.reset(new ServerLobbyThread(GetGui(), m_playerConfig, m_avatarManager)); + GetLobbyThread().Init(pwd, logDir); + + if (mode & NETWORK_MODE_TCP) + { + boost::shared_ptr tcpAcceptThread(new ServerAcceptThread(GetGui())); + tcpAcceptThread->Init(serverPort, ipv6, false, pwd, logDir, m_lobbyThread); + m_acceptThreadPool.push_back(tcpAcceptThread); + } + if (mode & NETWORK_MODE_SCTP) + { + boost::shared_ptr sctpAcceptThread(new ServerAcceptThread(GetGui())); + sctpAcceptThread->Init(serverPort, ipv6, true, pwd, logDir, m_lobbyThread); + m_acceptThreadPool.push_back(sctpAcceptThread); + } + m_ircThread = ircThread; +} + +GuiInterface & +ServerManager::GetGui() +{ + return m_gui; +} + +void +ServerManager::SignalIrcConnect(const std::string &server) +{ + LOG_MSG("Connected to IRC server " << server << "."); +} + +void +ServerManager::SignalIrcSelfJoined(const std::string &nickName, const std::string &channel) +{ + LOG_MSG("Joined IRC channel " << channel << " as user " << nickName << "."); + m_ircNick = nickName; +} + +void +ServerManager::SignalIrcChatMsg(const std::string &nickName, const std::string &msg) +{ + if (m_ircThread) + { + istringstream msgStream(msg); + string target; + msgStream >> target; + if (boost::algorithm::iequals(target, m_ircNick + ":")) + { + string command; + msgStream >> command; + if (command == "kick") + { + while (msgStream.peek() == ' ') + msgStream.get(); + string playerName(msgStream.str().substr(msgStream.tellg())); + if (!playerName.empty()) + { + if (GetLobbyThread().KickPlayerByName(playerName)) + m_ircThread->SendChatMessage(nickName + ": Successfully kicked player \"" + playerName + "\" from the server."); + else + m_ircThread->SendChatMessage(nickName + ": Player \"" + playerName + "\" was not found on the server."); + } + } + else if (command == "stat") + { + ServerStats tmpStats = GetLobbyThread().GetStats(); + ostringstream statStream; + statStream + << "Players on Server: " << tmpStats.numberOfPlayersOnServer; + m_ircThread->SendChatMessage(statStream.str()); + } + else + m_ircThread->SendChatMessage(nickName + ": Invalid command \"" + command + "\"."); + } + } +} + +void +ServerManager::SignalIrcError(int errorCode) +{ + LOG_MSG("IRC error " << errorCode << "."); +} + +void +ServerManager::SignalIrcServerError(int errorCode) +{ + LOG_MSG("IRC server error " << errorCode << "."); +} + +void +ServerManager::RunAll() +{ + if (m_ircThread) + m_ircThread->Run(); + GetLobbyThread().Run(); + for_each(m_acceptThreadPool.begin(), m_acceptThreadPool.end(), boost::mem_fn(&ServerAcceptThread::Run)); +} + +void +ServerManager::SignalTerminationAll() +{ + if (m_ircThread) + m_ircThread->SignalTermination(); + GetLobbyThread().SignalTermination(); + for_each(m_acceptThreadPool.begin(), m_acceptThreadPool.end(), boost::mem_fn(&ServerAcceptThread::SignalTermination)); +} + +bool +ServerManager::JoinAll(bool wait) +{ + if (m_ircThread) + m_ircThread->Join(wait ? NET_ADMIN_IRC_TERMINATE_TIMEOUT_MSEC : 0); + bool lobbyThreadTerminated = GetLobbyThread().Join(wait ? NET_LOBBY_THREAD_TERMINATE_TIMEOUT_MSEC : 0); + bool allAcceptThreadsTerminated = true; + AcceptThreadList::iterator i = m_acceptThreadPool.begin(); + AcceptThreadList::iterator end = m_acceptThreadPool.end(); + while (i != end) + { + if (!(*i)->Join(wait ? NET_ACCEPT_THREAD_TERMINATE_TIMEOUT_MSEC : 0)) + allAcceptThreadsTerminated = false; + ++i; + } + return lobbyThreadTerminated || allAcceptThreadsTerminated; +} + +ServerLobbyThread & +ServerManager::GetLobbyThread() +{ + assert(m_lobbyThread.get()); + return *m_lobbyThread; +} + diff --git a/src/net/serveracceptthread.h b/src/net/serveracceptthread.h index 3648e220..5e5eacdc 100644 --- a/src/net/serveracceptthread.h +++ b/src/net/serveracceptthread.h @@ -27,6 +27,8 @@ #include #include +#define NET_ACCEPT_THREAD_TERMINATE_TIMEOUT_MSEC 2000 + class ServerContext; class ServerLobbyThread; class ServerSenderCallback; @@ -36,27 +38,16 @@ class AvatarManager; class IrcThread; struct GameData; -class ServerAcceptThread : public Thread, public IrcCallback +class ServerAcceptThread : public Thread { public: - ServerAcceptThread(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager); + ServerAcceptThread(ServerCallback &serverCallback); virtual ~ServerAcceptThread(); // Set the parameters. - void Init(unsigned serverPort, bool ipv6, bool sctp, const std::string &pwd, const std::string &logDir, boost::shared_ptr ircThread); + void Init(unsigned serverPort, bool ipv6, bool sctp, const std::string &pwd, const std::string &logDir, boost::shared_ptr lobbyThread); ServerCallback &GetCallback(); - GuiInterface &GetGui(); - - virtual void SignalIrcConnect(const std::string &server); - virtual void SignalIrcSelfJoined(const std::string &nickName, const std::string &channel); - virtual void SignalIrcPlayerJoined(const std::string & /*nickName*/) {} - virtual void SignalIrcPlayerChanged(const std::string & /*oldNick*/, const std::string & /*newNick*/) {} - virtual void SignalIrcPlayerKicked(const std::string & /*nickName*/, const std::string & /*byWhom*/, const std::string & /*reason*/) {} - virtual void SignalIrcPlayerLeft(const std::string & /*nickName*/) {} - virtual void SignalIrcChatMsg(const std::string &nickName, const std::string &msg); - virtual void SignalIrcError(int errorCode); - virtual void SignalIrcServerError(int errorCode); protected: @@ -72,13 +63,10 @@ protected: ServerLobbyThread &GetLobbyThread(); private: + ServerCallback &m_serverCallback; + boost::shared_ptr m_context; boost::shared_ptr m_lobbyThread; - - GuiInterface &m_gui; - - std::string m_ircNick; - boost::shared_ptr m_ircThread; }; #endif diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index 5b539959..8d4a8421 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -31,8 +31,8 @@ #include #include -#define LOBBY_THREAD_TERMINATE_TIMEOUT_MSEC 20000 -#define ADMIN_IRC_TERMINATE_TIMEOUT_MSEC 2000 +#define NET_LOBBY_THREAD_TERMINATE_TIMEOUT_MSEC 20000 +#define NET_ADMIN_IRC_TERMINATE_TIMEOUT_MSEC 4000 class SenderThread; diff --git a/src/net/servermanager.h b/src/net/servermanager.h new file mode 100644 index 00000000..e791c9aa --- /dev/null +++ b/src/net/servermanager.h @@ -0,0 +1,81 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ +/* Manager thread for the server. */ + +#ifndef _SERVERMANAGER_H_ +#define _SERVERMANAGER_H_ + +#include + +#include +#include +#include + +class ServerLobbyThread; +class ServerAcceptThread; +class SenderThread; +class ConfigFile; +class AvatarManager; +class IrcThread; + +class ServerManager : public IrcCallback +{ +public: + ServerManager(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager); + virtual ~ServerManager(); + + // Set the parameters. + void Init(unsigned serverPort, bool ipv6, ServerNetworkMode mode, const std::string &pwd, const std::string &logDir, boost::shared_ptr ircThread); + + // Main start function. + void RunAll(); + + void SignalTerminationAll(); + bool JoinAll(bool wait); + + GuiInterface &GetGui(); + + virtual void SignalIrcConnect(const std::string &server); + virtual void SignalIrcSelfJoined(const std::string &nickName, const std::string &channel); + virtual void SignalIrcPlayerJoined(const std::string & /*nickName*/) {} + virtual void SignalIrcPlayerChanged(const std::string & /*oldNick*/, const std::string & /*newNick*/) {} + virtual void SignalIrcPlayerKicked(const std::string & /*nickName*/, const std::string & /*byWhom*/, const std::string & /*reason*/) {} + virtual void SignalIrcPlayerLeft(const std::string & /*nickName*/) {} + virtual void SignalIrcChatMsg(const std::string &nickName, const std::string &msg); + virtual void SignalIrcError(int errorCode); + virtual void SignalIrcServerError(int errorCode); + +protected: + typedef std::list > AcceptThreadList; + + ServerLobbyThread &GetLobbyThread(); + +private: + GuiInterface &m_gui; + ConfigFile *m_playerConfig; + AvatarManager &m_avatarManager; + + std::string m_ircNick; + + boost::shared_ptr m_lobbyThread; + boost::shared_ptr m_ircThread; + AcceptThreadList m_acceptThreadPool; +}; + +#endif diff --git a/src/pokerth_server.cpp b/src/pokerth_server.cpp index 83e0b96b..7beb54f8 100644 --- a/src/pokerth_server.cpp +++ b/src/pokerth_server.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -96,7 +97,8 @@ main(int argc, char *argv[]) myServerGuiInterface->getSession().startNetworkServer(); while (!g_pokerthTerminate) { - if (myServerGuiInterface->getSession().waitForNetworkServer(100)) + Thread::Msleep(100); + if (myServerGuiInterface->getSession().pollNetworkServerTerminated()) g_pokerthTerminate = true; } myServerGuiInterface->getSession().terminateNetworkServer(); diff --git a/src/session.cpp b/src/session.cpp index a8c8bbe2..4b346165 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -24,14 +24,13 @@ #include #include #include -#include +#include #include #include #include #define NET_CLIENT_TERMINATE_TIMEOUT_MSEC 1000 -#define NET_SERVER_TERMINATE_TIMEOUT_MSEC 10000 #define NET_IRC_TERMINATE_TIMEOUT_MSEC 2000 #define NET_DEFAULT_GAME "default" @@ -258,7 +257,7 @@ void Session::startNetworkServer() return; } - myNetServer = new ServerAcceptThread(*myGui, myConfig, *myAvatarManager); + myNetServer = new ServerManager(*myGui, myConfig, *myAvatarManager); boost::shared_ptr tmpIrcThread; if (myConfig->readConfigInt("UseAdminIRC")) @@ -277,40 +276,36 @@ void Session::startNetworkServer() myNetServer->Init( myConfig->readConfigInt("ServerPort"), myConfig->readConfigInt("ServerUseIpv6") == 1, - myConfig->readConfigInt("ServerUseSctp") == 1, + myConfig->readConfigInt("ServerUseSctp") == 1 ? NETWORK_MODE_TCP_SCTP : NETWORK_MODE_TCP, myConfig->readConfigString("ServerPassword"), myConfig->readConfigString("LogDir"), tmpIrcThread ); - myNetServer->Run(); + myNetServer->RunAll(); } void Session::terminateNetworkServer() { if (!myNetServer) return; // already terminated - myNetServer->SignalTermination(); + myNetServer->SignalTerminationAll(); // Give the thread some time to terminate. - if (myNetServer->Join(NET_SERVER_TERMINATE_TIMEOUT_MSEC)) + if (myNetServer->JoinAll(true)) delete myNetServer; // If termination fails, leave a memory leak to prevent a crash. myNetServer = 0; } -bool Session::waitForNetworkServer(unsigned timeoutMsec) +bool Session::pollNetworkServerTerminated() { bool retVal = false; if (!myNetServer) retVal = true; // already terminated else { - if (myNetServer->Join(timeoutMsec)) - { - delete myNetServer; - myNetServer = 0; + if (myNetServer->JoinAll(false)) retVal = true; - } } return retVal; } diff --git a/src/session.h b/src/session.h index 6e91238b..dbbaa4ed 100755 --- a/src/session.h +++ b/src/session.h @@ -30,7 +30,7 @@ class GuiInterface; class Game; class ConfigFile; class ClientThread; -class ServerAcceptThread; +class ServerManager; class IrcThread; class AvatarManager; @@ -67,7 +67,7 @@ public: void sendLeaveCurrentGame(); void sendStartEvent(bool fillUpWithCpuPlayers); void terminateNetworkServer(); - bool waitForNetworkServer(unsigned timeoutMsec); + bool pollNetworkServerTerminated(); void sendIrcChatMessage(const std::string &message); void setIrcNick(const std::string &value) { myIrcNick = value; } @@ -95,7 +95,7 @@ private: std::string myIrcNick; ClientThread *myNetClient; - ServerAcceptThread *myNetServer; + ServerManager *myNetServer; IrcThread *myClientIrcThread; boost::shared_ptr myAvatarManager;