diff --git a/pokerth_game.pro b/pokerth_game.pro index f160aa0d..858f81e2 100644 --- a/pokerth_game.pro +++ b/pokerth_game.pro @@ -4,7 +4,7 @@ TEMPLATE = app CODECFORSRC = UTF-8 CONFIG += qt thread embed_manifest_exe exceptions rtti stl warn_on release -# CONFIG += qt thread embed_manifest_exe exceptions rtti stl warn_on debug +#CONFIG += qt thread embed_manifest_exe exceptions rtti stl warn_on debug # ####Uncomment this for RELEASE on Linux/Unix/BSD (only for static Qt) #QTPLUGIN += qjpeg qgif @@ -118,7 +118,6 @@ HEADERS += src/game.h \ src/net/clientthread.h \ src/net/genericsocket.h \ src/net/netpacket.h \ - src/net/resolverthread.h \ src/net/senderhelper.h \ src/net/serveraccepthelper.h \ src/net/serverlobbythread.h \ diff --git a/pokerth_lib.pro b/pokerth_lib.pro index 5596c3fe..c6d70fa7 100644 --- a/pokerth_lib.pro +++ b/pokerth_lib.pro @@ -72,10 +72,8 @@ HEADERS += \ src/net/clientthread.h \ src/net/genericsocket.h \ src/net/netpacket.h \ - src/net/resolverthread.h \ src/net/senderhelper.h \ src/net/sendercallback.h \ - src/net/servercontext.h \ src/net/serverexception.h \ src/net/serveraccepthelper.h \ src/net/servergame.h \ @@ -172,10 +170,8 @@ SOURCES += \ src/net/common/downloadhelper.cpp \ src/net/common/downloaderthread.cpp \ src/net/common/netpacket.cpp \ - src/net/common/resolverthread.cpp \ src/net/common/senderhelper.cpp \ src/net/common/sendercallback.cpp \ - src/net/common/servercontext.cpp \ src/net/common/serverexception.cpp \ src/net/common/serveraccepthelper.cpp \ src/net/common/servergame.cpp \ diff --git a/pokerth_server.pro b/pokerth_server.pro index d59205ce..01eaf1c7 100644 --- a/pokerth_server.pro +++ b/pokerth_server.pro @@ -70,7 +70,6 @@ HEADERS += \ src/net/clientthread.h \ src/net/genericsocket.h \ src/net/netpacket.h \ - src/net/resolverthread.h \ src/net/senderhelper.h \ src/net/serveraccepthelper.h \ src/net/serverlobbythread.h \ diff --git a/src/net/clientcontext.h b/src/net/clientcontext.h index 61158b7b..c3cfb841 100644 --- a/src/net/clientcontext.h +++ b/src/net/clientcontext.h @@ -23,21 +23,20 @@ #include -#include #include #include -class ClientContext : public NetContext +class ClientContext { public: ClientContext(); virtual ~ClientContext(); - virtual SOCKET GetSocket() const; - boost::shared_ptr GetSessionData() const; void SetSessionData(boost::shared_ptr sessionData); + boost::shared_ptr GetResolver() const; + void SetResolver(boost::shared_ptr resolver); int GetProtocol() const {return m_protocol;} void SetProtocol(int protocol) @@ -70,10 +69,6 @@ public: {return m_password;} void SetPassword(const std::string &password) {m_password = password;} - const sockaddr_storage *GetClientSockaddr() const - {return &m_clientSockaddr;} - sockaddr_storage *GetClientSockaddr() - {return &m_clientSockaddr;} const std::string &GetPlayerName() const {return m_playerName;} void SetPlayerName(const std::string &playerName) @@ -91,14 +86,12 @@ public: void SetSubscribeLobbyMsg(bool setSubscribe) {m_hasSubscribedLobbyMsg = setSubscribe;} - int GetClientSockaddrSize() const - {return m_addrFamily == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in);} - ReceiveBuffer &GetReceiveBuffer() {return m_receiveBuffer;} private: boost::shared_ptr m_sessionData; + boost::shared_ptr m_resolver; int m_protocol; int m_addrFamily; std::string m_serverAddr; @@ -107,7 +100,6 @@ private: unsigned m_serverPort; std::string m_avatarServerAddr; std::string m_password; - sockaddr_storage m_clientSockaddr; std::string m_playerName; std::string m_avatarFile; std::string m_cacheDir; diff --git a/src/net/clientstate.h b/src/net/clientstate.h index ca536a5f..41f4c5fc 100644 --- a/src/net/clientstate.h +++ b/src/net/clientstate.h @@ -21,11 +21,9 @@ #ifndef _CLIENTSTATE_H_ #define _CLIENTSTATE_H_ -#include +#include +#include #include -#include - -#include // needed for correct order of header files. #define CLIENT_INITIAL_STATE ClientStateInit @@ -41,8 +39,10 @@ class ClientState public: virtual ~ClientState(); - // Main processing function of the current state. - virtual int Process(ClientThread &client) = 0; + virtual void Enter(boost::shared_ptr client) = 0; + virtual void Exit(boost::shared_ptr client) = 0; + + virtual void HandleRead(const boost::system::error_code& ec, boost::shared_ptr client, size_t bytesRead) = 0; }; // State: Initialization. @@ -51,14 +51,15 @@ class ClientStateInit : public ClientState public: // Access the state singleton. static ClientStateInit &Instance(); - virtual ~ClientStateInit(); // Some basic initialization (socket creation, basic checks). - virtual int Process(ClientThread &client); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + + virtual void HandleRead(const boost::system::error_code& /*ec*/, boost::shared_ptr /*client*/, size_t /*bytesRead*/) {} protected: - // Protected constructor - this is a singleton. ClientStateInit(); }; @@ -69,55 +70,36 @@ class ClientStateStartResolve : public ClientState public: // Access the state singleton. static ClientStateStartResolve &Instance(); - virtual ~ClientStateStartResolve(); // Initiate the name resolution. - virtual int Process(ClientThread &client); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + + virtual void HandleRead(const boost::system::error_code& /*ec*/, boost::shared_ptr /*client*/, size_t /*bytesRead*/) {} protected: + void HandleResolve( + const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator, + boost::shared_ptr client); // Protected constructor - this is a singleton. ClientStateStartResolve(); }; -// State: Name resolution. -class ClientStateResolving : public ClientState -{ -public: - // Access the state singleton. - static ClientStateResolving &Instance(); - - virtual ~ClientStateResolving(); - - void SetResolver(ResolverThread *resolver); - - // Poll for the completion of the name resolution. - virtual int Process(ClientThread &client); - -protected: - - // Protected constructor - this is a singleton. - ClientStateResolving(); - - void Cleanup(); - -private: - - ResolverThread *m_resolver; -}; - // State: Start download of the server list. class ClientStateStartServerListDownload : public ClientState { public: // Access the state singleton. static ClientStateStartServerListDownload &Instance(); - virtual ~ClientStateStartServerListDownload(); // Initiate the name resolution. - virtual int Process(ClientThread &client); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + + virtual void HandleRead(const boost::system::error_code& /*ec*/, boost::shared_ptr /*client*/, size_t /*bytesRead*/) {} protected: @@ -131,22 +113,26 @@ class ClientStateSynchronizingServerList : public ClientState public: // Access the state singleton. static ClientStateSynchronizingServerList &Instance(); - virtual ~ClientStateSynchronizingServerList(); - void SetDownloadHelper(DownloadHelper *helper); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); - // Poll for the completion of the download. - virtual int Process(ClientThread &client); + virtual void HandleRead(const boost::system::error_code& /*ec*/, boost::shared_ptr /*client*/, size_t /*bytesRead*/) {} + + void SetDownloadHelper(boost::shared_ptr helper); protected: // Protected constructor - this is a singleton. ClientStateSynchronizingServerList(); + // Poll for the completion of the download. + void TimerLoop(const boost::system::error_code& ec, boost::shared_ptr client); + private: - std::auto_ptr m_downloadHelper; + boost::shared_ptr m_downloadHelper; }; // State: Downloading the server list. @@ -155,22 +141,26 @@ class ClientStateDownloadingServerList : public ClientState public: // Access the state singleton. static ClientStateDownloadingServerList &Instance(); - virtual ~ClientStateDownloadingServerList(); - void SetDownloadHelper(DownloadHelper *helper); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); - // Poll for the completion of the download. - virtual int Process(ClientThread &client); + virtual void HandleRead(const boost::system::error_code& /*ec*/, boost::shared_ptr /*client*/, size_t /*bytesRead*/) {} + + void SetDownloadHelper(boost::shared_ptr helper); protected: // Protected constructor - this is a singleton. ClientStateDownloadingServerList(); + // Poll for the completion of the download. + void TimerLoop(const boost::system::error_code& ec, boost::shared_ptr client); + private: - std::auto_ptr m_downloadHelper; + boost::shared_ptr m_downloadHelper; }; // State: Reading the server list. @@ -178,10 +168,12 @@ class ClientStateReadingServerList : public ClientState { public: static ClientStateReadingServerList &Instance(); - virtual ~ClientStateReadingServerList(); - virtual int Process(ClientThread &client); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + + virtual void HandleRead(const boost::system::error_code& /*ec*/, boost::shared_ptr /*client*/, size_t /*bytesRead*/) {} protected: @@ -194,15 +186,19 @@ class ClientStateWaitChooseServer : public ClientState { public: static ClientStateWaitChooseServer &Instance(); - virtual ~ClientStateWaitChooseServer(); - virtual int Process(ClientThread &client); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + + virtual void HandleRead(const boost::system::error_code& /*ec*/, boost::shared_ptr /*client*/, size_t /*bytesRead*/) {} protected: // Protected constructor - this is a singleton. ClientStateWaitChooseServer(); + + void TimerLoop(const boost::system::error_code& ec, boost::shared_ptr client); }; // State: Initiate server connection. @@ -211,40 +207,29 @@ class ClientStateStartConnect : public ClientState public: // Access the state singleton. static ClientStateStartConnect &Instance(); - virtual ~ClientStateStartConnect(); // Call connect. - virtual int Process(ClientThread &client); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + + virtual void HandleRead(const boost::system::error_code& /*ec*/, boost::shared_ptr /*client*/, size_t /*bytesRead*/) {} + + void SetRemoteEndpoint(boost::asio::ip::tcp::resolver::iterator endpointIterator); protected: // Protected constructor - this is a singleton. ClientStateStartConnect(); -}; -// State: Connecting to server. -class ClientStateConnecting : public ClientState -{ -public: - // Access the state singleton. - static ClientStateConnecting &Instance(); + void HandleConnect(const boost::system::error_code& ec, + boost::asio::ip::tcp::resolver::iterator endpoint_iterator, + boost::shared_ptr client); - virtual ~ClientStateConnecting(); - - void SetTimer(const boost::timers::portable::microsec_timer &timer); - - // "Poll" for the completion of the TCP/IP connect call. - virtual int Process(ClientThread &client); - -protected: - - // Protected constructor - this is a singleton. - ClientStateConnecting(); + void TimerTimeout(const boost::system::error_code& ec, boost::shared_ptr client); private: - - boost::timers::portable::microsec_timer m_connectTimer; + boost::asio::ip::tcp::resolver::iterator m_remoteEndpointIterator; }; // State: Session init. @@ -253,11 +238,12 @@ class ClientStateStartSession : public ClientState public: // Access the state singleton. static ClientStateStartSession &Instance(); - virtual ~ClientStateStartSession(); - // sleep. - virtual int Process(ClientThread &client); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + + virtual void HandleRead(const boost::system::error_code& /*ec*/, boost::shared_ptr /*client*/, size_t /*bytesRead*/) {} protected: @@ -271,14 +257,13 @@ class AbstractClientStateReceiving : public ClientState public: virtual ~AbstractClientStateReceiving(); - // select on socket. - virtual int Process(ClientThread &client); + virtual void HandleRead(const boost::system::error_code& ec, boost::shared_ptr client, size_t bytesRead); protected: - - virtual int InternalProcess(ClientThread &client, boost::shared_ptr packet) = 0; - AbstractClientStateReceiving(); + + void HandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket); + virtual void InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket) = 0; }; // State: Wait for Session ACK. @@ -287,16 +272,16 @@ class ClientStateWaitSession : public AbstractClientStateReceiving public: // Access the state singleton. static ClientStateWaitSession &Instance(); - virtual ~ClientStateWaitSession(); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); protected: - // Protected constructor - this is a singleton. ClientStateWaitSession(); - virtual int InternalProcess(ClientThread &client, boost::shared_ptr packet); + virtual void InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket); }; // State: Wait for Join. @@ -305,16 +290,17 @@ class ClientStateWaitJoin : public AbstractClientStateReceiving public: // Access the state singleton. static ClientStateWaitJoin &Instance(); - virtual ~ClientStateWaitJoin(); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); protected: // Protected constructor - this is a singleton. ClientStateWaitJoin(); - virtual int InternalProcess(ClientThread &client, boost::shared_ptr packet); + virtual void InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket); }; // State: Wait for start of the game or start info. @@ -323,15 +309,17 @@ class ClientStateWaitGame : public AbstractClientStateReceiving public: // Access the state singleton. static ClientStateWaitGame &Instance(); - virtual ~ClientStateWaitGame(); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + protected: // Protected constructor - this is a singleton. ClientStateWaitGame(); - virtual int InternalProcess(ClientThread &client, boost::shared_ptr packet); + virtual void InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket); }; // State: Synchronize on game start. @@ -340,16 +328,18 @@ class ClientStateSynchronizeStart : public AbstractClientStateReceiving public: // Access the state singleton. static ClientStateSynchronizeStart &Instance(); - virtual ~ClientStateSynchronizeStart(); - virtual int Process(ClientThread &client); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + protected: // Protected constructor - this is a singleton. ClientStateSynchronizeStart(); - virtual int InternalProcess(ClientThread &client, boost::shared_ptr packet); + void TimerLoop(const boost::system::error_code& ec, boost::shared_ptr client); + virtual void InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket); }; // State: Wait for game start. @@ -358,15 +348,17 @@ class ClientStateWaitStart : public AbstractClientStateReceiving public: // Access the state singleton. static ClientStateWaitStart &Instance(); - virtual ~ClientStateWaitStart(); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + protected: // Protected constructor - this is a singleton. ClientStateWaitStart(); - virtual int InternalProcess(ClientThread &client, boost::shared_ptr packet); + virtual void InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket); }; // State: Wait for start of the next hand. @@ -375,15 +367,17 @@ class ClientStateWaitHand : public AbstractClientStateReceiving public: // Access the state singleton. static ClientStateWaitHand &Instance(); - virtual ~ClientStateWaitHand(); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + protected: // Protected constructor - this is a singleton. ClientStateWaitHand(); - virtual int InternalProcess(ClientThread &client, boost::shared_ptr packet); + virtual void InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket); }; // State: Hand Loop. @@ -392,36 +386,20 @@ class ClientStateRunHand : public AbstractClientStateReceiving public: // Access the state singleton. static ClientStateRunHand &Instance(); - virtual ~ClientStateRunHand(); + virtual void Enter(boost::shared_ptr client); + virtual void Exit(boost::shared_ptr client); + protected: // Protected constructor - this is a singleton. ClientStateRunHand(); - virtual int InternalProcess(ClientThread &client, boost::shared_ptr packet); + virtual void InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket); static void ResetPlayerActions(Game &curGame); static void ResetPlayerSets(Game &curGame); }; -// State: Final (just for testing, should not be used). -class ClientStateFinal : public ClientState -{ -public: - // Access the state singleton. - static ClientStateFinal &Instance(); - - virtual ~ClientStateFinal(); - - // sleep. - virtual int Process(ClientThread &client); - -protected: - - // Protected constructor - this is a singleton. - ClientStateFinal(); -}; - #endif diff --git a/src/net/clientthread.h b/src/net/clientthread.h index a11ca478..a5de40bc 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -42,7 +43,7 @@ class NetPacket; class AvatarManager; class QtToolsInterface; -class ClientThread : public Thread +class ClientThread : public Thread, public boost::enable_shared_from_this { public: ClientThread(GuiInterface &gui, AvatarManager &avatarManager); @@ -63,6 +64,7 @@ public: const std::string &playerName, const std::string &avatarFile, const std::string &cacheDir); + virtual void SignalTermination(); void SendKickPlayer(unsigned playerId); void SendLeaveCurrentGame(); @@ -76,6 +78,9 @@ public: void SendAskKickPlayer(unsigned playerId); void SendVoteKick(bool doKick); + void StartAsyncRead(); + void HandleRead(const boost::system::error_code& ec, size_t bytesRead); + void SelectServer(unsigned serverId); ServerInfo GetServerInfo(unsigned serverId) const; @@ -98,9 +103,12 @@ protected: // Main function of the thread. virtual void Main(); + void RegisterTimers(); + void CancelTimers(); + void InitGame(); void AddPacket(boost::shared_ptr packet); - void SendPacketLoop(); + void TimerSendPacketLoop(const boost::system::error_code &ec); bool GetCachedPlayerInfo(unsigned id, PlayerInfo &info) const; void RequestPlayerInfo(unsigned id, bool requestAvatar = false); @@ -115,7 +123,7 @@ protected: void PassAvatarDataToManager(unsigned playerId, boost::shared_ptr avatarData); void SetUnknownAvatar(unsigned playerId); - void CheckAvatarDownloads(); + void TimerCheckAvatarDownloads(const boost::system::error_code& ec); void UnsubscribeLobbyMsg(); void ResubscribeLobbyMsg(); @@ -126,6 +134,7 @@ protected: ClientState &GetState(); void SetState(ClientState &newState); + boost::asio::deadline_timer &GetStateTimer(); SenderHelper &GetSender(); ReceiverHelper &GetReceiver(); @@ -235,6 +244,10 @@ private: mutable boost::mutex m_curStatsMutex; ServerStats m_curStats; + boost::asio::deadline_timer m_stateTimer; + boost::asio::deadline_timer m_avatarTimer; + boost::asio::deadline_timer m_sendTimer; + friend class AbstractClientStateReceiving; friend class ClientStateInit; friend class ClientStateStartResolve; diff --git a/src/net/common/clientcontext.cpp b/src/net/common/clientcontext.cpp index b4e7914c..cc4fc42d 100644 --- a/src/net/common/clientcontext.cpp +++ b/src/net/common/clientcontext.cpp @@ -24,7 +24,6 @@ ClientContext::ClientContext() : m_protocol(0), m_addrFamily(AF_INET), m_useServerList(false), m_serverPort(0), m_hasSubscribedLobbyMsg(true) { - bzero(&m_clientSockaddr, sizeof(m_clientSockaddr)); } ClientContext::~ClientContext() @@ -32,13 +31,6 @@ ClientContext::~ClientContext() m_sessionData.reset(); } -SOCKET -ClientContext::GetSocket() const -{ - assert(m_sessionData.get()); - return m_sessionData->GetSocket(); -} - boost::shared_ptr ClientContext::GetSessionData() const { @@ -51,3 +43,15 @@ ClientContext::SetSessionData(boost::shared_ptr sessionData) m_sessionData = sessionData; } +boost::shared_ptr +ClientContext::GetResolver() const +{ + return m_resolver; +} + +void +ClientContext::SetResolver(boost::shared_ptr resolver) +{ + m_resolver = resolver; +} + diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 75b4f916..29c35c6a 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -75,10 +75,10 @@ ClientStateInit::~ClientStateInit() { } -int -ClientStateInit::Process(ClientThread &client) +void +ClientStateInit::Enter(boost::shared_ptr client) { - ClientContext &context = client.GetContext(); + ClientContext &context = client->GetContext(); if (context.GetServerAddr().empty()) throw ClientException(__FILE__, __LINE__, ERR_SOCK_SERVERADDR_NOT_SET, 0); @@ -86,14 +86,19 @@ ClientStateInit::Process(ClientThread &client) if (context.GetServerPort() < 1024) throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_PORT, 0); - client.CreateContextSession(); + client->CreateContextSession(); + client->GetCallback().SignalNetClientConnect(MSG_SOCK_INIT_DONE); if (context.GetUseServerList()) - client.SetState(ClientStateStartServerListDownload::Instance()); + client->SetState(ClientStateStartServerListDownload::Instance()); else - client.SetState(ClientStateStartResolve::Instance()); + client->SetState(ClientStateStartResolve::Instance()); +} - return MSG_SOCK_INIT_DONE; +void +ClientStateInit::Exit(boost::shared_ptr /*client*/) +{ + // Nothing to do. } //----------------------------------------------------------------------------- @@ -113,108 +118,44 @@ ClientStateStartResolve::~ClientStateStartResolve() { } -int -ClientStateStartResolve::Process(ClientThread &client) +void +ClientStateStartResolve::Enter(boost::shared_ptr client) { - int retVal = MSG_SOCK_INTERNAL_PENDING; + ClientContext &context = client->GetContext(); + ostringstream portStr; + portStr << context.GetServerPort(); + boost::asio::ip::tcp::resolver::query q(context.GetServerAddr(), portStr.str()); - ClientContext &context = client.GetContext(); - - context.GetClientSockaddr()->ss_family = context.GetAddrFamily(); - - // Treat the server address as numbers first. - if (socket_string_to_addr( - context.GetServerAddr().c_str(), - context.GetAddrFamily(), - (struct sockaddr *)context.GetClientSockaddr(), - context.GetClientSockaddrSize())) - { - // Success - but we still need to set the port. - if (!socket_set_port(context.GetServerPort(), context.GetAddrFamily(), (struct sockaddr *)context.GetClientSockaddr(), context.GetClientSockaddrSize())) - throw ClientException(__FILE__, __LINE__, ERR_SOCK_SET_PORT_FAILED, 0); - - // No need to resolve - start connecting. - client.SetState(ClientStateStartConnect::Instance()); - retVal = MSG_SOCK_RESOLVE_DONE; - } - else - { - // Start name resolution in a separate thread, since it is blocking - // for up to about 30 seconds. - std::auto_ptr resolver(new ResolverThread); - resolver->Init(context); - resolver->Run(); - - ClientStateResolving::Instance().SetResolver(resolver.release()); - client.SetState(ClientStateResolving::Instance()); - } - - return retVal; -} - -//----------------------------------------------------------------------------- - -ClientStateResolving & -ClientStateResolving::Instance() -{ - static ClientStateResolving state; - return state; -} - -ClientStateResolving::ClientStateResolving() -: m_resolver(NULL) -{ -} - -ClientStateResolving::~ClientStateResolving() -{ - Cleanup(); + context.GetResolver()->async_resolve( + q, + boost::bind(&ClientStateStartResolve::HandleResolve, + this, + boost::asio::placeholders::error, + boost::asio::placeholders::iterator, + client)); } void -ClientStateResolving::SetResolver(ResolverThread *resolver) +ClientStateStartResolve::Exit(boost::shared_ptr client) { - Cleanup(); - m_resolver = resolver; + client->GetContext().GetResolver()->cancel(); } -int -ClientStateResolving::Process(ClientThread &client) +void +ClientStateStartResolve::HandleResolve(const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator, + boost::shared_ptr client) { - int retVal; - - if (!m_resolver) - throw ClientException(__FILE__, __LINE__, ERR_SOCK_RESOLVE_FAILED, 0); - - if (m_resolver->Join(CLIENT_WAIT_TIMEOUT_MSEC)) + if (!ec && &client->GetState() == this) { - ClientContext &context = client.GetContext(); - bool success = m_resolver->GetResult(context); - Cleanup(); // Not required, but better keep things clean. - - if (!success) + client->GetCallback().SignalNetClientConnect(MSG_SOCK_RESOLVE_DONE); + // Use the first resolver result. + ClientStateStartConnect::Instance().SetRemoteEndpoint(endpoint_iterator); + client->SetState(ClientStateStartConnect::Instance()); + } + else + { + if (ec != boost::asio::error::operation_aborted) throw ClientException(__FILE__, __LINE__, ERR_SOCK_RESOLVE_FAILED, 0); - - client.SetState(ClientStateStartConnect::Instance()); - retVal = MSG_SOCK_RESOLVE_DONE; - } - else - retVal = MSG_SOCK_INTERNAL_PENDING; - - return retVal; -} - - -void -ClientStateResolving::Cleanup() -{ - if (m_resolver) - { - if (m_resolver->Join(500)) - delete m_resolver; - // If the resolver does not terminate fast enough, leave it - // as memory leak. - m_resolver = NULL; } } @@ -235,12 +176,10 @@ ClientStateStartServerListDownload::~ClientStateStartServerListDownload() { } -int -ClientStateStartServerListDownload::Process(ClientThread &client) +void +ClientStateStartServerListDownload::Enter(boost::shared_ptr client) { - int retVal = MSG_SOCK_INTERNAL_PENDING; - - const ClientContext &context = client.GetContext(); + const ClientContext &context = client->GetContext(); path tmpServerListPath(context.GetCacheDir()); string serverListUrl(context.GetServerListUrl()); // Retrieve the file name from the URL. @@ -254,21 +193,25 @@ ClientStateStartServerListDownload::Process(ClientThread &client) { // Download and compare md5. tmpServerListPath = change_extension(tmpServerListPath, extension(tmpServerListPath) + ".md5"); - std::auto_ptr downloader(new DownloadHelper); + boost::shared_ptr downloader(new DownloadHelper); downloader->Init(serverListUrl + ".md5", tmpServerListPath.directory_string()); - ClientStateSynchronizingServerList::Instance().SetDownloadHelper(downloader.release()); - client.SetState(ClientStateSynchronizingServerList::Instance()); + ClientStateSynchronizingServerList::Instance().SetDownloadHelper(downloader); + client->SetState(ClientStateSynchronizingServerList::Instance()); } else { // Download server list. - std::auto_ptr downloader(new DownloadHelper); + boost::shared_ptr downloader(new DownloadHelper); downloader->Init(serverListUrl, tmpServerListPath.directory_string()); - ClientStateDownloadingServerList::Instance().SetDownloadHelper(downloader.release()); - client.SetState(ClientStateDownloadingServerList::Instance()); + ClientStateDownloadingServerList::Instance().SetDownloadHelper(downloader); + client->SetState(ClientStateDownloadingServerList::Instance()); } +} - return retVal; +void +ClientStateStartServerListDownload::Exit(boost::shared_ptr /*client*/) +{ + // Nothing to do. } //----------------------------------------------------------------------------- @@ -289,60 +232,84 @@ ClientStateSynchronizingServerList::~ClientStateSynchronizingServerList() } void -ClientStateSynchronizingServerList::SetDownloadHelper(DownloadHelper *helper) +ClientStateSynchronizingServerList::Enter(boost::shared_ptr client) { - m_downloadHelper.reset(helper); + client->GetStateTimer().expires_from_now( + boost::posix_time::milliseconds(CLIENT_WAIT_TIMEOUT_MSEC)); + client->GetStateTimer().async_wait( + boost::bind( + &ClientStateSynchronizingServerList::TimerLoop, this, boost::asio::placeholders::error, client)); } -int -ClientStateSynchronizingServerList::Process(ClientThread &client) +void +ClientStateSynchronizingServerList::Exit(boost::shared_ptr client) { - int retVal = MSG_SOCK_INTERNAL_PENDING; + client->GetStateTimer().cancel(); +} - if (m_downloadHelper->Process()) +void +ClientStateSynchronizingServerList::SetDownloadHelper(boost::shared_ptr helper) +{ + m_downloadHelper = helper; +} + +void +ClientStateSynchronizingServerList::TimerLoop(const boost::system::error_code& ec, boost::shared_ptr client) +{ + if (!ec && &client->GetState() == this) { - m_downloadHelper.reset(NULL); - ClientContext &context = client.GetContext(); - path md5ServerListPath(context.GetCacheDir()); + if (m_downloadHelper->Process()) + { + m_downloadHelper.reset(); + ClientContext &context = client->GetContext(); + path md5ServerListPath(context.GetCacheDir()); - // No more checking needed as this was done before. - md5ServerListPath /= context.GetServerListUrl().substr(context.GetServerListUrl().find_last_of('/') + 1) + ".md5"; - path serverListPath = change_extension(md5ServerListPath, ""); - // Compare the md5 sums. - string tmpMd5; - { - ifstream inFile(md5ServerListPath.directory_string().c_str(), ios_base::in); - if (inFile.fail()) - throw ClientException(__FILE__, __LINE__, ERR_SOCK_OPEN_MD5_FAILED, 0); - inFile >> tmpMd5; - } - MD5Buf downloadedMd5; - if (!downloadedMd5.FromString(tmpMd5)) - throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_MD5, 0); - MD5Buf currentMd5; - if (!CryptHelper::MD5Sum(serverListPath.directory_string(), currentMd5)) - throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_MD5, 0); - if (downloadedMd5 == currentMd5) - { - // Server list is still current. - client.SetState(ClientStateReadingServerList::Instance()); + // No more checking needed as this was done before. + md5ServerListPath /= context.GetServerListUrl().substr(context.GetServerListUrl().find_last_of('/') + 1) + ".md5"; + path serverListPath = change_extension(md5ServerListPath, ""); + // Compare the md5 sums. + string tmpMd5; + { + ifstream inFile(md5ServerListPath.directory_string().c_str(), ios_base::in); + if (inFile.fail()) + throw ClientException(__FILE__, __LINE__, ERR_SOCK_OPEN_MD5_FAILED, 0); + inFile >> tmpMd5; + } + MD5Buf downloadedMd5; + if (!downloadedMd5.FromString(tmpMd5)) + throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_MD5, 0); + MD5Buf currentMd5; + if (!CryptHelper::MD5Sum(serverListPath.directory_string(), currentMd5)) + throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_MD5, 0); + if (downloadedMd5 == currentMd5) + { + // Server list is still current. + client->SetState(ClientStateReadingServerList::Instance()); + } + else + { + // Download new server list. + // Paranoia check before removing the file, we do not want to delete wrong files. + path tmpPath(serverListPath); + if (path(context.GetCacheDir()) == tmpPath.remove_leaf()) + { + remove(serverListPath); + client->SetState(ClientStateStartServerListDownload::Instance()); + } + else + throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_URL, 0); + } } else { - // Download new server list. - // Paranoia check before removing the file, we do not want to delete wrong files. - path tmpPath(serverListPath); - if (path(context.GetCacheDir()) == tmpPath.remove_leaf()) - { - remove(serverListPath); - client.SetState(ClientStateStartServerListDownload::Instance()); - } - else - throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_URL, 0); + // Download still in process. Delay. + client->GetStateTimer().expires_from_now( + boost::posix_time::milliseconds(CLIENT_WAIT_TIMEOUT_MSEC)); + client->GetStateTimer().async_wait( + boost::bind( + &ClientStateSynchronizingServerList::TimerLoop, this, boost::asio::placeholders::error, client)); } } - - return retVal; } //----------------------------------------------------------------------------- @@ -363,23 +330,46 @@ ClientStateDownloadingServerList::~ClientStateDownloadingServerList() } void -ClientStateDownloadingServerList::SetDownloadHelper(DownloadHelper *helper) +ClientStateDownloadingServerList::Enter(boost::shared_ptr client) { - m_downloadHelper.reset(helper); + client->GetStateTimer().expires_from_now( + boost::posix_time::milliseconds(CLIENT_WAIT_TIMEOUT_MSEC)); + client->GetStateTimer().async_wait( + boost::bind( + &ClientStateDownloadingServerList::TimerLoop, this, boost::asio::placeholders::error, client)); } -int -ClientStateDownloadingServerList::Process(ClientThread &client) +void +ClientStateDownloadingServerList::Exit(boost::shared_ptr client) { - int retVal = MSG_SOCK_INTERNAL_PENDING; + client->GetStateTimer().cancel(); +} - if (m_downloadHelper->Process()) +void +ClientStateDownloadingServerList::SetDownloadHelper(boost::shared_ptr helper) +{ + m_downloadHelper = helper; +} + +void +ClientStateDownloadingServerList::TimerLoop(const boost::system::error_code& ec, boost::shared_ptr client) +{ + if (!ec && &client->GetState() == this) { - m_downloadHelper.reset(NULL); - client.SetState(ClientStateReadingServerList::Instance()); + if (m_downloadHelper->Process()) + { + m_downloadHelper.reset(); + client->SetState(ClientStateReadingServerList::Instance()); + } + else + { + client->GetStateTimer().expires_from_now( + boost::posix_time::milliseconds(CLIENT_WAIT_TIMEOUT_MSEC)); + client->GetStateTimer().async_wait( + boost::bind( + &ClientStateDownloadingServerList::TimerLoop, this, boost::asio::placeholders::error, client)); + } } - - return retVal; } //----------------------------------------------------------------------------- @@ -399,12 +389,10 @@ ClientStateReadingServerList::~ClientStateReadingServerList() { } -int -ClientStateReadingServerList::Process(ClientThread &client) +void +ClientStateReadingServerList::Enter(boost::shared_ptr client) { - int retVal = MSG_SOCK_INTERNAL_PENDING; - - ClientContext &context = client.GetContext(); + ClientContext &context = client->GetContext(); path zippedServerListPath(context.GetCacheDir()); zippedServerListPath /= context.GetServerListUrl().substr(context.GetServerListUrl().find_last_of('/') + 1); path xmlServerListPath; @@ -433,7 +421,7 @@ ClientStateReadingServerList::Process(ClientThread &client) if (doc.LoadFile()) { - client.ClearServerInfoMap(); + client->ClearServerInfoMap(); int serverCount = 0; unsigned lastServerInfoId = 0; TiXmlHandle docHandle(&doc); @@ -480,7 +468,7 @@ ClientStateReadingServerList::Process(ClientThread &client) if (avatarNode && avatarNode->ToElement()) serverInfo.avatarServerAddr = avatarNode->ToElement()->Attribute("value"); - client.AddServerInfo(serverInfo.id, serverInfo); + client->AddServerInfo(serverInfo.id, serverInfo); nextServer = nextServer->NextSiblingElement(); lastServerInfoId = serverInfo.id; serverCount++; @@ -488,23 +476,26 @@ ClientStateReadingServerList::Process(ClientThread &client) if (serverCount == 1) { - client.UseServer(lastServerInfoId); - client.SetState(ClientStateStartResolve::Instance()); - retVal = MSG_SOCK_SERVER_LIST_DONE; + client->UseServer(lastServerInfoId); + client->GetCallback().SignalNetClientConnect(MSG_SOCK_SERVER_LIST_DONE); + client->SetState(ClientStateStartResolve::Instance()); } else if (serverCount > 1) { - client.GetCallback().SignalNetClientServerListShow(); - client.SetState(ClientStateWaitChooseServer::Instance()); + client->GetCallback().SignalNetClientServerListShow(); + client->SetState(ClientStateWaitChooseServer::Instance()); } else throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_XML, 0); } else throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_XML, 0); +} - - return retVal; +void +ClientStateReadingServerList::Exit(boost::shared_ptr /*client*/) +{ + // Nothing to do. } //----------------------------------------------------------------------------- @@ -524,22 +515,43 @@ ClientStateWaitChooseServer::~ClientStateWaitChooseServer() { } -int -ClientStateWaitChooseServer::Process(ClientThread &client) +void +ClientStateWaitChooseServer::Enter(boost::shared_ptr client) { - int retVal = MSG_SOCK_INTERNAL_PENDING; + client->GetStateTimer().expires_from_now( + boost::posix_time::milliseconds(CLIENT_WAIT_TIMEOUT_MSEC)); + client->GetStateTimer().async_wait( + boost::bind( + &ClientStateWaitChooseServer::TimerLoop, this, boost::asio::placeholders::error, client)); +} - unsigned serverId; - if (client.GetSelectedServer(serverId)) +void +ClientStateWaitChooseServer::Exit(boost::shared_ptr client) +{ + client->GetStateTimer().cancel(); +} + +void +ClientStateWaitChooseServer::TimerLoop(const boost::system::error_code& ec, boost::shared_ptr client) +{ + if (!ec && &client->GetState() == this) { - client.UseServer(serverId); - client.SetState(ClientStateStartResolve::Instance()); - retVal = MSG_SOCK_SERVER_LIST_DONE; + unsigned serverId; + if (client->GetSelectedServer(serverId)) + { + client->UseServer(serverId); + client->GetCallback().SignalNetClientConnect(MSG_SOCK_SERVER_LIST_DONE); + client->SetState(ClientStateStartResolve::Instance()); + } + else + { + client->GetStateTimer().expires_from_now( + boost::posix_time::milliseconds(CLIENT_WAIT_TIMEOUT_MSEC)); + client->GetStateTimer().async_wait( + boost::bind( + &ClientStateWaitChooseServer::TimerLoop, this, boost::asio::placeholders::error, client)); + } } - else - Thread::Msleep(20); - - return retVal; } //----------------------------------------------------------------------------- @@ -559,98 +571,78 @@ ClientStateStartConnect::~ClientStateStartConnect() { } -int -ClientStateStartConnect::Process(ClientThread &client) +void +ClientStateStartConnect::Enter(boost::shared_ptr client) { - int retVal; - ClientContext &context = client.GetContext(); + client->GetStateTimer().expires_from_now( + boost::posix_time::seconds(CLIENT_CONNECT_TIMEOUT_SEC)); + client->GetStateTimer().async_wait( + boost::bind( + &ClientStateStartConnect::TimerTimeout, this, boost::asio::placeholders::error, client)); - int connectResult = connect(context.GetSocket(), (struct sockaddr *)context.GetClientSockaddr(), context.GetClientSockaddrSize()); - - if (IS_VALID_CONNECT(connectResult)) - { - client.SetState(ClientStateStartSession::Instance()); - retVal = MSG_SOCK_CONNECT_DONE; - } - else - { - int errCode = SOCKET_ERRNO(); - if (IS_SOCKET_ERR_WOULDBLOCK(errCode)) - { - boost::timers::portable::microsec_timer connectTimer; - ClientStateConnecting::Instance().SetTimer(connectTimer); - client.SetState(ClientStateConnecting::Instance()); - retVal = MSG_SOCK_INTERNAL_PENDING; - } - else - throw ClientException(__FILE__, __LINE__, ERR_SOCK_CONNECT_FAILED, SOCKET_ERRNO()); - } - - return retVal; -} - -//----------------------------------------------------------------------------- - -ClientStateConnecting & -ClientStateConnecting::Instance() -{ - static ClientStateConnecting state; - return state; -} - -ClientStateConnecting::ClientStateConnecting() -{ -} - -ClientStateConnecting::~ClientStateConnecting() -{ + boost::asio::ip::tcp::endpoint endpoint = *m_remoteEndpointIterator; + client->GetContext().GetSessionData()->GetAsioSocket()->async_connect( + endpoint, + boost::bind(&ClientStateStartConnect::HandleConnect, + this, + boost::asio::placeholders::error, + ++m_remoteEndpointIterator, + client)); } void -ClientStateConnecting::SetTimer(const boost::timers::portable::microsec_timer &timer) +ClientStateStartConnect::Exit(boost::shared_ptr client) { - m_connectTimer = timer; + client->GetStateTimer().cancel(); } -int -ClientStateConnecting::Process(ClientThread &client) +void +ClientStateStartConnect::SetRemoteEndpoint(boost::asio::ip::tcp::resolver::iterator endpointIterator) { - int retVal; - ClientContext &context = client.GetContext(); + m_remoteEndpointIterator = endpointIterator; +} - fd_set writeSet; - struct timeval timeout; - - FD_ZERO(&writeSet); - FD_SET(context.GetSocket(), &writeSet); - - timeout.tv_sec = 0; - timeout.tv_usec = CLIENT_WAIT_TIMEOUT_MSEC * 1000; - int selectResult = select(context.GetSocket() + 1, NULL, &writeSet, NULL, &timeout); - - if (selectResult > 0) // success +void +ClientStateStartConnect::HandleConnect(const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator, + boost::shared_ptr client) +{ + if (&client->GetState() == this) { - // Check whether the connect call succeeded. - int connectResult = 0; - socklen_t tmpSize = sizeof(connectResult); - getsockopt(context.GetSocket(), SOL_SOCKET, SO_ERROR, (char *)&connectResult, &tmpSize); - if (connectResult != 0) - throw ClientException(__FILE__, __LINE__, ERR_SOCK_CONNECT_FAILED, connectResult); - client.SetState(ClientStateStartSession::Instance()); - retVal = MSG_SOCK_CONNECT_DONE; - } - else if (selectResult == 0) // timeout - { - if (m_connectTimer.elapsed().total_seconds() >= CLIENT_CONNECT_TIMEOUT_SEC) - throw ClientException(__FILE__, __LINE__, ERR_SOCK_CONNECT_TIMEOUT, 0); + if (!ec) + { + client->GetCallback().SignalNetClientConnect(MSG_SOCK_CONNECT_DONE); + client->SetState(ClientStateStartSession::Instance()); + } + else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) + { + // Try next resolve entry. + ClientContext &context = client->GetContext(); + context.GetSessionData()->GetAsioSocket()->close(); + boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator; + context.GetSessionData()->GetAsioSocket()->async_connect( + endpoint, + boost::bind(&ClientStateStartConnect::HandleConnect, + this, + boost::asio::placeholders::error, + ++m_remoteEndpointIterator, + client)); + } else - retVal = MSG_SOCK_INTERNAL_PENDING; + { + if (ec != boost::asio::error::operation_aborted) + throw ClientException(__FILE__, __LINE__, ERR_SOCK_CONNECT_FAILED, ec.value()); + } } - else - throw ClientException(__FILE__, __LINE__, ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO()); +} - - return retVal; +void +ClientStateStartConnect::TimerTimeout(const boost::system::error_code& ec, boost::shared_ptr client) +{ + if (!ec && &client->GetState() == this) + { + client->GetContext().GetSessionData()->GetAsioSocket()->close(); + throw ClientException(__FILE__, __LINE__, ERR_SOCK_CONNECT_TIMEOUT, 0); + } } //----------------------------------------------------------------------------- @@ -670,30 +662,33 @@ ClientStateStartSession::~ClientStateStartSession() { } -int -ClientStateStartSession::Process(ClientThread &client) +void +ClientStateStartSession::Enter(boost::shared_ptr client) { - ClientContext &context = client.GetContext(); + ClientContext &context = client->GetContext(); NetPacketInit::Data initData; initData.password = context.GetPassword(); initData.playerName = context.GetPlayerName(); - string avatarFile = client.GetQtToolsInterface().stringFromUtf8(context.GetAvatarFile()); + string avatarFile = client->GetQtToolsInterface().stringFromUtf8(context.GetAvatarFile()); initData.showAvatar = false; if (!avatarFile.empty()) { - if (client.GetAvatarManager().GetHashForAvatar(avatarFile, initData.avatar)) + if (client->GetAvatarManager().GetHashForAvatar(avatarFile, initData.avatar)) initData.showAvatar = true; } boost::shared_ptr packet(new NetPacketInit); ((NetPacketInit *)packet.get())->SetData(initData); - client.GetSender().Send(context.GetSessionData(), packet); + client->GetSender().Send(context.GetSessionData(), packet); - client.SetState(ClientStateWaitSession::Instance()); + client->SetState(ClientStateWaitSession::Instance()); +} - return MSG_SOCK_INTERNAL_PENDING; +void +ClientStateStartSession::Exit(boost::shared_ptr /*client*/) +{ } //----------------------------------------------------------------------------- @@ -706,214 +701,224 @@ AbstractClientStateReceiving::~AbstractClientStateReceiving() { } -int -AbstractClientStateReceiving::Process(ClientThread &client) +void +AbstractClientStateReceiving::HandleRead(const boost::system::error_code& ec, boost::shared_ptr client, size_t bytesRead) { - int retVal = MSG_SOCK_INTERNAL_PENDING; - - // Check for avatar downloads. - client.CheckAvatarDownloads(); - - // Delegate to receiver helper class. - boost::shared_ptr tmpPacket = - client.GetReceiver().Recv(client.GetContext().GetSocket(), client.GetContext().GetReceiveBuffer()); - - if (tmpPacket.get()) + if (!ec) { - if (tmpPacket->ToNetPacketPlayerInfo()) - { - NetPacketPlayerInfo::Data infoData; - tmpPacket->ToNetPacketPlayerInfo()->GetData(infoData); - client.SetPlayerInfo(infoData.playerId, infoData.playerInfo); - } - else if (tmpPacket->ToNetPacketUnknownPlayerId()) - { - NetPacketUnknownPlayerId::Data unknownIdData; - tmpPacket->ToNetPacketUnknownPlayerId()->GetData(unknownIdData); - client.SetUnknownPlayer(unknownIdData.playerId); - } - else if (tmpPacket->ToNetPacketRemovedFromGame()) - { - NetPacketRemovedFromGame::Data removedData; - tmpPacket->ToNetPacketRemovedFromGame()->GetData(removedData); - client.ClearPlayerDataList(); - // Resubscribe Lobby messages. - client.ResubscribeLobbyMsg(); - // Show Lobby. - client.GetCallback().SignalNetClientWaitDialog(); - client.GetCallback().SignalNetClientRemovedFromGame(removedData.removeReason); - client.SetState(ClientStateWaitJoin::Instance()); - } - else if (tmpPacket->ToNetPacketTimeoutWarning()) - { - NetPacketTimeoutWarning::Data warningData; - tmpPacket->ToNetPacketTimeoutWarning()->GetData(warningData); - client.GetCallback().SignalNetClientShowTimeoutDialog(warningData.timeoutReason, warningData.remainingSeconds); - } - else if (tmpPacket->ToNetPacketChatText()) - { - // Chat message - display it in the GUI. - NetPacketChatText::Data chatData; - tmpPacket->ToNetPacketChatText()->GetData(chatData); + ReceiveBuffer &buf = client->GetContext().GetSessionData()->GetReceiveBuffer(); + buf.recvBufUsed += bytesRead; + client->GetReceiver().ScanPackets(buf); - string playerName; - if (chatData.playerId == 0) - { - playerName = "(global notice)"; - } - else - { - boost::shared_ptr tmpPlayer = client.GetPlayerDataByUniqueId(chatData.playerId); - if (tmpPlayer.get()) - playerName = tmpPlayer->GetName(); - } - if (!playerName.empty()) - client.GetCallback().SignalNetClientChatMsg(playerName, chatData.text); - } - else if (tmpPacket->ToNetPacketMsgBoxText()) + while (!buf.receivedPackets.empty()) { - // Message box - display it in the GUI. - NetPacketMsgBoxText::Data msgData; - tmpPacket->ToNetPacketMsgBoxText()->GetData(msgData); - client.GetCallback().SignalNetClientMsgBox(msgData.text); + boost::shared_ptr packet = buf.receivedPackets.front(); + buf.receivedPackets.pop_front(); + if (packet) + HandlePacket(client, packet); } - else if (tmpPacket->ToNetPacketPlayerLeft()) - { - // A player left the game. - NetPacketPlayerLeft::Data playerLeftData; - tmpPacket->ToNetPacketPlayerLeft()->GetData(playerLeftData); + } + else + { + if (ec != boost::asio::error::operation_aborted) + throw NetException(__FILE__, __LINE__, ERR_SOCK_CONN_RESET, 0); + } +} - // Signal to GUI and remove from data list. - client.RemovePlayerData(playerLeftData.playerId, playerLeftData.removeReason); - } - else if (tmpPacket->ToNetPacketGameAdminChanged()) - { - // New admin for the game. - NetPacketGameAdminChanged::Data adminChangedData; - tmpPacket->ToNetPacketGameAdminChanged()->GetData(adminChangedData); +void +AbstractClientStateReceiving::HandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket) +{ + if (tmpPacket->ToNetPacketPlayerInfo()) + { + NetPacketPlayerInfo::Data infoData; + tmpPacket->ToNetPacketPlayerInfo()->GetData(infoData); + client->SetPlayerInfo(infoData.playerId, infoData.playerInfo); + } + else if (tmpPacket->ToNetPacketUnknownPlayerId()) + { + NetPacketUnknownPlayerId::Data unknownIdData; + tmpPacket->ToNetPacketUnknownPlayerId()->GetData(unknownIdData); + client->SetUnknownPlayer(unknownIdData.playerId); + } + else if (tmpPacket->ToNetPacketRemovedFromGame()) + { + NetPacketRemovedFromGame::Data removedData; + tmpPacket->ToNetPacketRemovedFromGame()->GetData(removedData); + client->ClearPlayerDataList(); + // Resubscribe Lobby messages. + client->ResubscribeLobbyMsg(); + // Show Lobby. + client->GetCallback().SignalNetClientWaitDialog(); + client->GetCallback().SignalNetClientRemovedFromGame(removedData.removeReason); + client->SetState(ClientStateWaitJoin::Instance()); + } + else if (tmpPacket->ToNetPacketTimeoutWarning()) + { + NetPacketTimeoutWarning::Data warningData; + tmpPacket->ToNetPacketTimeoutWarning()->GetData(warningData); + client->GetCallback().SignalNetClientShowTimeoutDialog(warningData.timeoutReason, warningData.remainingSeconds); + } + else if (tmpPacket->ToNetPacketChatText()) + { + // Chat message - display it in the GUI. + NetPacketChatText::Data chatData; + tmpPacket->ToNetPacketChatText()->GetData(chatData); - // Set new game admin and signal to GUI. - client.SetNewGameAdmin(adminChangedData.playerId); - } - else if (tmpPacket->ToNetPacketGameListNew()) + string playerName; + if (chatData.playerId == 0) { - // A new game was created on the server. - NetPacketGameListNew::Data gameListNewData; - tmpPacket->ToNetPacketGameListNew()->GetData(gameListNewData); - - // Request player info for players if needed. - PlayerIdList::const_iterator i = gameListNewData.gameInfo.players.begin(); - PlayerIdList::const_iterator end = gameListNewData.gameInfo.players.end(); - while (i != end) - { - PlayerInfo info; - if (!client.GetCachedPlayerInfo(*i, info)) - { - // Request player info. - client.RequestPlayerInfo(*i); - } - ++i; - } - - client.AddGameInfo(gameListNewData.gameId, gameListNewData.gameInfo); - } - else if (tmpPacket->ToNetPacketGameListUpdate()) - { - // An existing game was updated on the server. - NetPacketGameListUpdate::Data gameListUpdateData; - tmpPacket->ToNetPacketGameListUpdate()->GetData(gameListUpdateData); - if (gameListUpdateData.gameMode == GAME_MODE_CLOSED) - client.RemoveGameInfo(gameListUpdateData.gameId); - else - client.UpdateGameInfoMode(gameListUpdateData.gameId, gameListUpdateData.gameMode); - } - else if (tmpPacket->ToNetPacketGameListPlayerJoined()) - { - NetPacketGameListPlayerJoined::Data playerJoinedData; - tmpPacket->ToNetPacketGameListPlayerJoined()->GetData(playerJoinedData); - client.ModifyGameInfoAddPlayer(playerJoinedData.gameId, playerJoinedData.playerId); - // Request player info if needed. - PlayerInfo info; - if (!client.GetCachedPlayerInfo(playerJoinedData.playerId, info)) - { - client.RequestPlayerInfo(playerJoinedData.playerId); - } - } - else if (tmpPacket->ToNetPacketGameListPlayerLeft()) - { - NetPacketGameListPlayerLeft::Data playerLeftData; - tmpPacket->ToNetPacketGameListPlayerLeft()->GetData(playerLeftData); - client.ModifyGameInfoRemovePlayer(playerLeftData.gameId, playerLeftData.playerId); - } - else if (tmpPacket->ToNetPacketGameListAdminChanged()) - { - NetPacketGameListAdminChanged::Data adminChangedData; - tmpPacket->ToNetPacketGameListAdminChanged()->GetData(adminChangedData); - client.UpdateGameInfoAdmin(adminChangedData.gameId, adminChangedData.newAdminplayerId); - } - else if (tmpPacket->ToNetPacketStartKickPlayerPetition()) - { - NetPacketStartKickPlayerPetition::Data startPetitionData; - tmpPacket->ToNetPacketStartKickPlayerPetition()->GetData(startPetitionData); - client.StartPetition(startPetitionData.petitionId, startPetitionData.proposingPlayerId, - startPetitionData.kickPlayerId, startPetitionData.kickTimeoutSec, startPetitionData.numVotesNeededToKick); - } - else if (tmpPacket->ToNetPacketKickPlayerPetitionUpdate()) - { - NetPacketKickPlayerPetitionUpdate::Data updatePetitionData; - tmpPacket->ToNetPacketKickPlayerPetitionUpdate()->GetData(updatePetitionData); - client.UpdatePetition(updatePetitionData.petitionId, updatePetitionData.numVotesAgainstKicking, - updatePetitionData.numVotesInFavourOfKicking, updatePetitionData.numVotesNeededToKick); - } - else if (tmpPacket->ToNetPacketEndKickPlayerPetition()) - { - NetPacketEndKickPlayerPetition::Data endPetitionData; - tmpPacket->ToNetPacketEndKickPlayerPetition()->GetData(endPetitionData); - client.EndPetition(endPetitionData.petitionId); - } - else if (tmpPacket->ToNetPacketAvatarHeader()) - { - NetPacketAvatarHeader::Data headerData; - tmpPacket->ToNetPacketAvatarHeader()->GetData(headerData); - client.AddTempAvatarData(headerData.requestId, headerData.avatarFileSize, headerData.avatarFileType); - } - else if (tmpPacket->ToNetPacketAvatarFile()) - { - NetPacketAvatarFile::Data fileData; - tmpPacket->ToNetPacketAvatarFile()->GetData(fileData); - client.StoreInTempAvatarData(fileData.requestId, fileData.fileData); - } - else if (tmpPacket->ToNetPacketAvatarEnd()) - { - NetPacketAvatarEnd::Data endData; - tmpPacket->ToNetPacketAvatarEnd()->GetData(endData); - client.CompleteTempAvatarData(endData.requestId); - } - else if (tmpPacket->ToNetPacketUnknownAvatar()) - { - NetPacketUnknownAvatar::Data unknownAvatarData; - tmpPacket->ToNetPacketUnknownAvatar()->GetData(unknownAvatarData); - client.SetUnknownAvatar(unknownAvatarData.requestId); - } - else if (tmpPacket->ToNetPacketStatisticsChanged()) - { - NetPacketStatisticsChanged::Data statData; - tmpPacket->ToNetPacketStatisticsChanged()->GetData(statData); - client.UpdateStatData(statData.stats); - } - else if (tmpPacket->ToNetPacketError()) - { - // Server reported an error. - NetPacketError::Data errorData; - tmpPacket->ToNetPacketError()->GetData(errorData); - // Show the error. - throw ClientException(__FILE__, __LINE__, errorData.errorCode, 0); + playerName = "(global notice)"; } else - retVal = InternalProcess(client, tmpPacket); + { + boost::shared_ptr tmpPlayer = client->GetPlayerDataByUniqueId(chatData.playerId); + if (tmpPlayer.get()) + playerName = tmpPlayer->GetName(); + } + if (!playerName.empty()) + client->GetCallback().SignalNetClientChatMsg(playerName, chatData.text); } + else if (tmpPacket->ToNetPacketMsgBoxText()) + { + // Message box - display it in the GUI. + NetPacketMsgBoxText::Data msgData; + tmpPacket->ToNetPacketMsgBoxText()->GetData(msgData); + client->GetCallback().SignalNetClientMsgBox(msgData.text); + } + else if (tmpPacket->ToNetPacketPlayerLeft()) + { + // A player left the game. + NetPacketPlayerLeft::Data playerLeftData; + tmpPacket->ToNetPacketPlayerLeft()->GetData(playerLeftData); - return retVal; + // Signal to GUI and remove from data list. + client->RemovePlayerData(playerLeftData.playerId, playerLeftData.removeReason); + } + else if (tmpPacket->ToNetPacketGameAdminChanged()) + { + // New admin for the game. + NetPacketGameAdminChanged::Data adminChangedData; + tmpPacket->ToNetPacketGameAdminChanged()->GetData(adminChangedData); + + // Set new game admin and signal to GUI. + client->SetNewGameAdmin(adminChangedData.playerId); + } + else if (tmpPacket->ToNetPacketGameListNew()) + { + // A new game was created on the server. + NetPacketGameListNew::Data gameListNewData; + tmpPacket->ToNetPacketGameListNew()->GetData(gameListNewData); + + // Request player info for players if needed. + PlayerIdList::const_iterator i = gameListNewData.gameInfo.players.begin(); + PlayerIdList::const_iterator end = gameListNewData.gameInfo.players.end(); + while (i != end) + { + PlayerInfo info; + if (!client->GetCachedPlayerInfo(*i, info)) + { + // Request player info. + client->RequestPlayerInfo(*i); + } + ++i; + } + + client->AddGameInfo(gameListNewData.gameId, gameListNewData.gameInfo); + } + else if (tmpPacket->ToNetPacketGameListUpdate()) + { + // An existing game was updated on the server. + NetPacketGameListUpdate::Data gameListUpdateData; + tmpPacket->ToNetPacketGameListUpdate()->GetData(gameListUpdateData); + if (gameListUpdateData.gameMode == GAME_MODE_CLOSED) + client->RemoveGameInfo(gameListUpdateData.gameId); + else + client->UpdateGameInfoMode(gameListUpdateData.gameId, gameListUpdateData.gameMode); + } + else if (tmpPacket->ToNetPacketGameListPlayerJoined()) + { + NetPacketGameListPlayerJoined::Data playerJoinedData; + tmpPacket->ToNetPacketGameListPlayerJoined()->GetData(playerJoinedData); + client->ModifyGameInfoAddPlayer(playerJoinedData.gameId, playerJoinedData.playerId); + // Request player info if needed. + PlayerInfo info; + if (!client->GetCachedPlayerInfo(playerJoinedData.playerId, info)) + { + client->RequestPlayerInfo(playerJoinedData.playerId); + } + } + else if (tmpPacket->ToNetPacketGameListPlayerLeft()) + { + NetPacketGameListPlayerLeft::Data playerLeftData; + tmpPacket->ToNetPacketGameListPlayerLeft()->GetData(playerLeftData); + client->ModifyGameInfoRemovePlayer(playerLeftData.gameId, playerLeftData.playerId); + } + else if (tmpPacket->ToNetPacketGameListAdminChanged()) + { + NetPacketGameListAdminChanged::Data adminChangedData; + tmpPacket->ToNetPacketGameListAdminChanged()->GetData(adminChangedData); + client->UpdateGameInfoAdmin(adminChangedData.gameId, adminChangedData.newAdminplayerId); + } + else if (tmpPacket->ToNetPacketStartKickPlayerPetition()) + { + NetPacketStartKickPlayerPetition::Data startPetitionData; + tmpPacket->ToNetPacketStartKickPlayerPetition()->GetData(startPetitionData); + client->StartPetition(startPetitionData.petitionId, startPetitionData.proposingPlayerId, + startPetitionData.kickPlayerId, startPetitionData.kickTimeoutSec, startPetitionData.numVotesNeededToKick); + } + else if (tmpPacket->ToNetPacketKickPlayerPetitionUpdate()) + { + NetPacketKickPlayerPetitionUpdate::Data updatePetitionData; + tmpPacket->ToNetPacketKickPlayerPetitionUpdate()->GetData(updatePetitionData); + client->UpdatePetition(updatePetitionData.petitionId, updatePetitionData.numVotesAgainstKicking, + updatePetitionData.numVotesInFavourOfKicking, updatePetitionData.numVotesNeededToKick); + } + else if (tmpPacket->ToNetPacketEndKickPlayerPetition()) + { + NetPacketEndKickPlayerPetition::Data endPetitionData; + tmpPacket->ToNetPacketEndKickPlayerPetition()->GetData(endPetitionData); + client->EndPetition(endPetitionData.petitionId); + } + else if (tmpPacket->ToNetPacketAvatarHeader()) + { + NetPacketAvatarHeader::Data headerData; + tmpPacket->ToNetPacketAvatarHeader()->GetData(headerData); + client->AddTempAvatarData(headerData.requestId, headerData.avatarFileSize, headerData.avatarFileType); + } + else if (tmpPacket->ToNetPacketAvatarFile()) + { + NetPacketAvatarFile::Data fileData; + tmpPacket->ToNetPacketAvatarFile()->GetData(fileData); + client->StoreInTempAvatarData(fileData.requestId, fileData.fileData); + } + else if (tmpPacket->ToNetPacketAvatarEnd()) + { + NetPacketAvatarEnd::Data endData; + tmpPacket->ToNetPacketAvatarEnd()->GetData(endData); + client->CompleteTempAvatarData(endData.requestId); + } + else if (tmpPacket->ToNetPacketUnknownAvatar()) + { + NetPacketUnknownAvatar::Data unknownAvatarData; + tmpPacket->ToNetPacketUnknownAvatar()->GetData(unknownAvatarData); + client->SetUnknownAvatar(unknownAvatarData.requestId); + } + else if (tmpPacket->ToNetPacketStatisticsChanged()) + { + NetPacketStatisticsChanged::Data statData; + tmpPacket->ToNetPacketStatisticsChanged()->GetData(statData); + client->UpdateStatData(statData.stats); + } + else if (tmpPacket->ToNetPacketError()) + { + // Server reported an error. + NetPacketError::Data errorData; + tmpPacket->ToNetPacketError()->GetData(errorData); + // Show the error. + throw ClientException(__FILE__, __LINE__, errorData.errorCode, 0); + } + else + InternalHandlePacket(client, tmpPacket); } //----------------------------------------------------------------------------- @@ -933,47 +938,55 @@ ClientStateWaitSession::~ClientStateWaitSession() { } -int -ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr packet) +void +ClientStateWaitSession::Enter(boost::shared_ptr client) { - int retVal = MSG_SOCK_INTERNAL_PENDING; + // Now we finally start receiving data. + client->StartAsyncRead(); +} - if (packet->ToNetPacketInitAck()) +void +ClientStateWaitSession::Exit(boost::shared_ptr /*client*/) +{ +} + +void +ClientStateWaitSession::InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket) +{ + if (tmpPacket->ToNetPacketInitAck()) { // Everything is fine - we are in the lobby. NetPacketInitAck::Data initAckData; - packet->ToNetPacketInitAck()->GetData(initAckData); + tmpPacket->ToNetPacketInitAck()->GetData(initAckData); // Check current game version. if (initAckData.latestGameVersion != POKERTH_VERSION) - client.GetCallback().SignalNetClientNotification(NTF_NET_NEW_RELEASE_AVAILABLE); + client->GetCallback().SignalNetClientNotification(NTF_NET_NEW_RELEASE_AVAILABLE); else if (POKERTH_BETA_REVISION && initAckData.latestBetaRevision != POKERTH_BETA_REVISION) - client.GetCallback().SignalNetClientNotification(NTF_NET_OUTDATED_BETA); + client->GetCallback().SignalNetClientNotification(NTF_NET_OUTDATED_BETA); - client.SetGuiPlayerId(initAckData.playerId); + client->SetGuiPlayerId(initAckData.playerId); - client.SetState(ClientStateWaitJoin::Instance()); - client.SetSessionEstablished(true); - retVal = MSG_SOCK_SESSION_DONE; + client->SetSessionEstablished(true); + client->GetCallback().SignalNetClientConnect(MSG_SOCK_SESSION_DONE); + client->SetState(ClientStateWaitJoin::Instance()); } - else if (packet->ToNetPacketRetrieveAvatar()) + else if (tmpPacket->ToNetPacketRetrieveAvatar()) { // Before letting us join the lobby, the server requests our avatar. NetPacketRetrieveAvatar::Data retrieveAvatarData; - packet->ToNetPacketRetrieveAvatar()->GetData(retrieveAvatarData); + tmpPacket->ToNetPacketRetrieveAvatar()->GetData(retrieveAvatarData); NetPacketList tmpList; - int avatarError = client.GetAvatarManager().AvatarFileToNetPackets( - client.GetQtToolsInterface().stringFromUtf8(client.GetContext().GetAvatarFile()), + int avatarError = client->GetAvatarManager().AvatarFileToNetPackets( + client->GetQtToolsInterface().stringFromUtf8(client->GetContext().GetAvatarFile()), retrieveAvatarData.requestId, tmpList); if (!avatarError) - client.GetSender().Send(client.GetContext().GetSessionData(), tmpList); + client->GetSender().Send(client->GetContext().GetSessionData(), tmpList); else throw ClientException(__FILE__, __LINE__, avatarError, 0); } - - return retVal; } //----------------------------------------------------------------------------- @@ -993,39 +1006,46 @@ ClientStateWaitJoin::~ClientStateWaitJoin() { } -int -ClientStateWaitJoin::InternalProcess(ClientThread &client, boost::shared_ptr packet) +void +ClientStateWaitJoin::Enter(boost::shared_ptr /*client*/) { - int retVal = MSG_SOCK_INTERNAL_PENDING; - ClientContext &context = client.GetContext(); +} - if (packet->ToNetPacketJoinGameAck()) +void +ClientStateWaitJoin::Exit(boost::shared_ptr /*client*/) +{ +} + +void +ClientStateWaitJoin::InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket) +{ + ClientContext &context = client->GetContext(); + + if (tmpPacket->ToNetPacketJoinGameAck()) { // Successfully joined a game. NetPacketJoinGameAck::Data joinGameAckData; - packet->ToNetPacketJoinGameAck()->GetData(joinGameAckData); - client.SetGameId(joinGameAckData.gameId); - client.SetGameData(joinGameAckData.gameData); + tmpPacket->ToNetPacketJoinGameAck()->GetData(joinGameAckData); + client->SetGameId(joinGameAckData.gameId); + client->SetGameData(joinGameAckData.gameData); // Player number is 0 on init. Will be set when the game starts. boost::shared_ptr playerData( - new PlayerData(client.GetGuiPlayerId(), 0, PLAYER_TYPE_HUMAN, joinGameAckData.prights)); + new PlayerData(client->GetGuiPlayerId(), 0, PLAYER_TYPE_HUMAN, joinGameAckData.prights)); playerData->SetName(context.GetPlayerName()); playerData->SetAvatarFile(context.GetAvatarFile()); - client.AddPlayerData(playerData); + client->AddPlayerData(playerData); - client.SetState(ClientStateWaitGame::Instance()); - retVal = MSG_NET_GAME_CLIENT_JOIN; + client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_JOIN); + client->SetState(ClientStateWaitGame::Instance()); } - else if (packet->ToNetPacketJoinGameFailed()) + else if (tmpPacket->ToNetPacketJoinGameFailed()) { // Failed to join a game. NetPacketJoinGameFailed::Data joinGameFailedData; - packet->ToNetPacketJoinGameFailed()->GetData(joinGameFailedData); - client.GetCallback().SignalNetClientNotification(joinGameFailedData.failureCode); + tmpPacket->ToNetPacketJoinGameFailed()->GetData(joinGameFailedData); + client->GetCallback().SignalNetClientNotification(joinGameFailedData.failureCode); } - - return retVal; } //----------------------------------------------------------------------------- @@ -1045,24 +1065,32 @@ ClientStateWaitGame::~ClientStateWaitGame() { } -int -ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptr packet) +void +ClientStateWaitGame::Enter(boost::shared_ptr /*client*/) { - int retVal = MSG_SOCK_INTERNAL_PENDING; +} - if (packet->ToNetPacketStartEvent()) +void +ClientStateWaitGame::Exit(boost::shared_ptr /*client*/) +{ +} + +void +ClientStateWaitGame::InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket) +{ + if (tmpPacket->ToNetPacketStartEvent()) { - client.SetState(ClientStateSynchronizeStart::Instance()); + client->SetState(ClientStateSynchronizeStart::Instance()); } - else if (packet->ToNetPacketPlayerJoined()) + else if (tmpPacket->ToNetPacketPlayerJoined()) { // Another player joined the network game. NetPacketPlayerJoined::Data netPlayerData; - packet->ToNetPacketPlayerJoined()->GetData(netPlayerData); + tmpPacket->ToNetPacketPlayerJoined()->GetData(netPlayerData); boost::shared_ptr playerData; PlayerInfo info; - if (client.GetCachedPlayerInfo(netPlayerData.playerId, info)) + if (client->GetCachedPlayerInfo(netPlayerData.playerId, info)) { playerData.reset( new PlayerData(netPlayerData.playerId, 0, info.ptype, netPlayerData.prights)); @@ -1070,10 +1098,10 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptrSetAvatarFile(client.GetQtToolsInterface().stringToUtf8(avatarFile)); + if (client->GetAvatarManager().GetAvatarFileName(info.avatar, avatarFile)) + playerData->SetAvatarFile(client->GetQtToolsInterface().stringToUtf8(avatarFile)); else - client.RetrieveAvatarIfNeeded(netPlayerData.playerId, info); + client->RetrieveAvatarIfNeeded(netPlayerData.playerId, info); } } else @@ -1082,16 +1110,14 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptrRequestPlayerInfo(netPlayerData.playerId, true); // Use temporary data until the PlayerInfo request is completed. playerData.reset( new PlayerData(netPlayerData.playerId, 0, PLAYER_TYPE_HUMAN, netPlayerData.prights)); playerData->SetName(name.str()); } - client.AddPlayerData(playerData); + client->AddPlayerData(playerData); } - - return retVal; } //----------------------------------------------------------------------------- @@ -1111,34 +1137,53 @@ ClientStateSynchronizeStart::~ClientStateSynchronizeStart() { } -int -ClientStateSynchronizeStart::Process(ClientThread &client) +void +ClientStateSynchronizeStart::Enter(boost::shared_ptr client) { - int retVal = AbstractClientStateReceiving::Process(client); - - if (client.IsSynchronized()) - { - // Acknowledge start. - boost::shared_ptr startAck(new NetPacketStartEventAck); - client.GetSender().Send(client.GetContext().GetSessionData(), startAck); - // Unsubscribe lobby messages. - client.UnsubscribeLobbyMsg(); - - client.SetState(ClientStateWaitStart::Instance()); - } - - return retVal; + client->GetStateTimer().expires_from_now( + boost::posix_time::milliseconds(CLIENT_WAIT_TIMEOUT_MSEC)); + client->GetStateTimer().async_wait( + boost::bind( + &ClientStateSynchronizeStart::TimerLoop, this, boost::asio::placeholders::error, client)); } -int -ClientStateSynchronizeStart::InternalProcess(ClientThread &/*client*/, boost::shared_ptr packet) +void +ClientStateSynchronizeStart::Exit(boost::shared_ptr client) { - int retVal = MSG_SOCK_INTERNAL_PENDING; + client->GetStateTimer().cancel(); +} - if (packet->ToNetPacketGameStart()) +void +ClientStateSynchronizeStart::TimerLoop(const boost::system::error_code& ec, boost::shared_ptr client) +{ + if (!ec && &client->GetState() == this) + { + if (client->IsSynchronized()) + { + // Acknowledge start. + boost::shared_ptr startAck(new NetPacketStartEventAck); + client->GetSender().Send(client->GetContext().GetSessionData(), startAck); + // Unsubscribe lobby messages. + client->UnsubscribeLobbyMsg(); + + client->SetState(ClientStateWaitStart::Instance()); + } + else + { + client->GetStateTimer().expires_from_now( + boost::posix_time::milliseconds(CLIENT_WAIT_TIMEOUT_MSEC)); + client->GetStateTimer().async_wait( + boost::bind( + &ClientStateSynchronizeStart::TimerLoop, this, boost::asio::placeholders::error, client)); + } + } +} + +void +ClientStateSynchronizeStart::InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket) +{ + if (tmpPacket->ToNetPacketGameStart()) throw ClientException(__FILE__, __LINE__, ERR_NET_START_TIMEOUT, 0); - - return retVal; } //----------------------------------------------------------------------------- @@ -1158,18 +1203,26 @@ ClientStateWaitStart::~ClientStateWaitStart() { } -int -ClientStateWaitStart::InternalProcess(ClientThread &client, boost::shared_ptr packet) +void +ClientStateWaitStart::Enter(boost::shared_ptr /*client*/) { - int retVal = MSG_SOCK_INTERNAL_PENDING; +} - if (packet->ToNetPacketGameStart()) +void +ClientStateWaitStart::Exit(boost::shared_ptr /*client*/) +{ +} + +void +ClientStateWaitStart::InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket) +{ + if (tmpPacket->ToNetPacketGameStart()) { // Start the network game as client. NetPacketGameStart::Data gameStartData; - packet->ToNetPacketGameStart()->GetData(gameStartData); + tmpPacket->ToNetPacketGameStart()->GetData(gameStartData); - client.SetStartData(gameStartData.startData); + client->SetStartData(gameStartData.startData); // Set player numbers using the game start data slots. NetPacketGameStart::PlayerSlotList::const_iterator slot_i = gameStartData.playerSlots.begin(); @@ -1179,7 +1232,7 @@ ClientStateWaitStart::InternalProcess(ClientThread &client, boost::shared_ptr tmpPlayer = client.GetPlayerDataByUniqueId(playerId); + boost::shared_ptr tmpPlayer = client->GetPlayerDataByUniqueId(playerId); if (!tmpPlayer.get()) throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); tmpPlayer->SetNumber(num); @@ -1188,11 +1241,10 @@ ClientStateWaitStart::InternalProcess(ClientThread &client, boost::shared_ptrInitGame(); + client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_START); + client->SetState(ClientStateWaitHand::Instance()); } - - return retVal; } //----------------------------------------------------------------------------- @@ -1212,57 +1264,62 @@ ClientStateWaitHand::~ClientStateWaitHand() { } -int -ClientStateWaitHand::InternalProcess(ClientThread &client, boost::shared_ptr packet) +void +ClientStateWaitHand::Enter(boost::shared_ptr /*client*/) { - int retVal = MSG_SOCK_INTERNAL_PENDING; +} - if (packet->ToNetPacketHandStart()) +void +ClientStateWaitHand::Exit(boost::shared_ptr /*client*/) +{ +} + +void +ClientStateWaitHand::InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket) +{ + if (tmpPacket->ToNetPacketHandStart()) { // Remove all players which left the server. - client.RemoveDisconnectedPlayers(); + client->RemoveDisconnectedPlayers(); // Hand was started. // These are the cards. Good luck. NetPacketHandStart::Data tmpData; - packet->ToNetPacketHandStart()->GetData(tmpData); + tmpPacket->ToNetPacketHandStart()->GetData(tmpData); int myCards[2]; myCards[0] = (int)tmpData.yourCards[0]; myCards[1] = (int)tmpData.yourCards[1]; - client.GetGame()->getSeatsList()->front()->setMyCards(myCards); - client.GetGame()->initHand(); - client.GetGame()->getCurrentHand()->setSmallBlind(tmpData.smallBlind); - client.GetGame()->getCurrentHand()->getCurrentBeRo()->setMinimumRaise(2 * tmpData.smallBlind); - client.GetGame()->startHand(); - client.GetGui().dealHoleCards(); - client.GetGui().refreshGameLabels(GAME_STATE_PREFLOP); - client.GetGui().refreshPot(); - client.GetGui().waitForGuiUpdateDone(); + client->GetGame()->getSeatsList()->front()->setMyCards(myCards); + client->GetGame()->initHand(); + client->GetGame()->getCurrentHand()->setSmallBlind(tmpData.smallBlind); + client->GetGame()->getCurrentHand()->getCurrentBeRo()->setMinimumRaise(2 * tmpData.smallBlind); + client->GetGame()->startHand(); + client->GetGui().dealHoleCards(); + client->GetGui().refreshGameLabels(GAME_STATE_PREFLOP); + client->GetGui().refreshPot(); + client->GetGui().waitForGuiUpdateDone(); - client.SetState(ClientStateRunHand::Instance()); - - retVal = MSG_NET_GAME_CLIENT_HAND_START; + client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_HAND_START); + client->SetState(ClientStateRunHand::Instance()); } - else if (packet->ToNetPacketEndOfGame()) + else if (tmpPacket->ToNetPacketEndOfGame()) { - boost::shared_ptr curGame = client.GetGame(); + boost::shared_ptr curGame = client->GetGame(); if (curGame.get()) { NetPacketEndOfGame::Data endData; - packet->ToNetPacketEndOfGame()->GetData(endData); + tmpPacket->ToNetPacketEndOfGame()->GetData(endData); boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId(endData.winnerPlayerId); if (!tmpPlayer) throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); - client.GetGui().logPlayerWinGame(tmpPlayer->getMyName(), curGame->getMyGameID()); + client->GetGui().logPlayerWinGame(tmpPlayer->getMyName(), curGame->getMyGameID()); // Resubscribe Lobby messages. - client.ResubscribeLobbyMsg(); + client->ResubscribeLobbyMsg(); // Show Lobby dialog. - client.GetCallback().SignalNetClientWaitDialog(); - client.SetState(ClientStateWaitGame::Instance()); - retVal = MSG_NET_GAME_CLIENT_END; + client->GetCallback().SignalNetClientWaitDialog(); + client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_END); + client->SetState(ClientStateWaitGame::Instance()); } } - - return MSG_SOCK_INTERNAL_PENDING; } //----------------------------------------------------------------------------- @@ -1282,287 +1339,290 @@ ClientStateRunHand::~ClientStateRunHand() { } -int -ClientStateRunHand::InternalProcess(ClientThread &client, boost::shared_ptr packet) +void +ClientStateRunHand::Enter(boost::shared_ptr /*client*/) { - int retVal = MSG_SOCK_INTERNAL_PENDING; +} - if (packet.get()) +void +ClientStateRunHand::Exit(boost::shared_ptr /*client*/) +{ +} + +void +ClientStateRunHand::InternalHandlePacket(boost::shared_ptr client, boost::shared_ptr tmpPacket) +{ + boost::shared_ptr curGame = client->GetGame(); + if (tmpPacket->ToNetPacketPlayersActionDone()) { - boost::shared_ptr curGame = client.GetGame(); - if (packet->ToNetPacketPlayersActionDone()) + NetPacketPlayersActionDone::Data actionDoneData; + tmpPacket->ToNetPacketPlayersActionDone()->GetData(actionDoneData); + boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId(actionDoneData.playerId); + if (!tmpPlayer) + throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); + + bool isBigBlind = false; + + if (actionDoneData.gameState == GAME_STATE_PREFLOP_SMALL_BLIND) { - NetPacketPlayersActionDone::Data actionDoneData; - packet->ToNetPacketPlayersActionDone()->GetData(actionDoneData); - boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId(actionDoneData.playerId); - if (!tmpPlayer) - throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); - - bool isBigBlind = false; - - if (actionDoneData.gameState == GAME_STATE_PREFLOP_SMALL_BLIND) - { - curGame->getCurrentHand()->getCurrentBeRo()->setSmallBlindPositionId(tmpPlayer->getMyUniqueID()); - tmpPlayer->setMyButton(BUTTON_SMALL_BLIND); - } - else if (actionDoneData.gameState == GAME_STATE_PREFLOP_BIG_BLIND) - { - curGame->getCurrentHand()->getCurrentBeRo()->setBigBlindPositionId(tmpPlayer->getMyUniqueID()); - tmpPlayer->setMyButton(BUTTON_BIG_BLIND); - isBigBlind = true; - } - else // no blind -> log - { - if (actionDoneData.playerAction) - { - assert(actionDoneData.totalPlayerBet >= (unsigned)tmpPlayer->getMySet()); - client.GetGui().logPlayerActionMsg( - tmpPlayer->getMyName(), - actionDoneData.playerAction, - actionDoneData.totalPlayerBet - tmpPlayer->getMySet()); - } - // Update last players turn only after the blinds. - curGame->getCurrentHand()->setLastPlayersTurn(tmpPlayer->getMyID()); - } - - tmpPlayer->setMyAction(actionDoneData.playerAction); - tmpPlayer->setMySetAbsolute(actionDoneData.totalPlayerBet); - tmpPlayer->setMyCash(actionDoneData.playerMoney); - curGame->getCurrentHand()->getCurrentBeRo()->setHighestSet(actionDoneData.highestSet); - curGame->getCurrentHand()->getCurrentBeRo()->setMinimumRaise(actionDoneData.minimumRaise); - curGame->getCurrentHand()->getBoard()->collectSets(); - curGame->getCurrentHand()->switchRounds(); - - //log blinds sets after setting bigblind-button - if (isBigBlind) { - client.GetGui().logNewBlindsSetsMsg(curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getSmallBlindPositionId())->getMySet(), curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getBigBlindPositionId())->getMySet(), curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getSmallBlindPositionId())->getMyName(), curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getBigBlindPositionId())->getMyName()); - client.GetGui().flushLogAtHand(); - } - - // Stop the timeout for the player. - client.GetGui().stopTimeoutAnimation(tmpPlayer->getMyID()); - - // Unmark last player in GUI. - client.GetGui().refreshGroupbox(tmpPlayer->getMyID(), 3); - - // Refresh GUI - if (tmpPlayer->getMyID() == 0) - client.GetGui().disableMyButtons(); - client.GetGui().refreshAction(tmpPlayer->getMyID(), tmpPlayer->getMyAction()); - client.GetGui().refreshPot(); - client.GetGui().refreshSet(); - client.GetGui().refreshCash(); - client.GetGui().refreshButton(); - client.GetGui().updateMyButtonsState(); + curGame->getCurrentHand()->getCurrentBeRo()->setSmallBlindPositionId(tmpPlayer->getMyUniqueID()); + tmpPlayer->setMyButton(BUTTON_SMALL_BLIND); } - else if (packet->ToNetPacketPlayersTurn()) + else if (actionDoneData.gameState == GAME_STATE_PREFLOP_BIG_BLIND) { - NetPacketPlayersTurn::Data turnData; - packet->ToNetPacketPlayersTurn()->GetData(turnData); - boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId(turnData.playerId); + curGame->getCurrentHand()->getCurrentBeRo()->setBigBlindPositionId(tmpPlayer->getMyUniqueID()); + tmpPlayer->setMyButton(BUTTON_BIG_BLIND); + isBigBlind = true; + } + else // no blind -> log + { + if (actionDoneData.playerAction) + { + assert(actionDoneData.totalPlayerBet >= (unsigned)tmpPlayer->getMySet()); + client->GetGui().logPlayerActionMsg( + tmpPlayer->getMyName(), + actionDoneData.playerAction, + actionDoneData.totalPlayerBet - tmpPlayer->getMySet()); + } + // Update last players turn only after the blinds. + curGame->getCurrentHand()->setLastPlayersTurn(tmpPlayer->getMyID()); + } + + tmpPlayer->setMyAction(actionDoneData.playerAction); + tmpPlayer->setMySetAbsolute(actionDoneData.totalPlayerBet); + tmpPlayer->setMyCash(actionDoneData.playerMoney); + curGame->getCurrentHand()->getCurrentBeRo()->setHighestSet(actionDoneData.highestSet); + curGame->getCurrentHand()->getCurrentBeRo()->setMinimumRaise(actionDoneData.minimumRaise); + curGame->getCurrentHand()->getBoard()->collectSets(); + curGame->getCurrentHand()->switchRounds(); + + //log blinds sets after setting bigblind-button + if (isBigBlind) { + client->GetGui().logNewBlindsSetsMsg(curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getSmallBlindPositionId())->getMySet(), curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getBigBlindPositionId())->getMySet(), curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getSmallBlindPositionId())->getMyName(), curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getBigBlindPositionId())->getMyName()); + client->GetGui().flushLogAtHand(); + } + + // Stop the timeout for the player. + client->GetGui().stopTimeoutAnimation(tmpPlayer->getMyID()); + + // Unmark last player in GUI. + client->GetGui().refreshGroupbox(tmpPlayer->getMyID(), 3); + + // Refresh GUI + if (tmpPlayer->getMyID() == 0) + client->GetGui().disableMyButtons(); + client->GetGui().refreshAction(tmpPlayer->getMyID(), tmpPlayer->getMyAction()); + client->GetGui().refreshPot(); + client->GetGui().refreshSet(); + client->GetGui().refreshCash(); + client->GetGui().refreshButton(); + client->GetGui().updateMyButtonsState(); + } + else if (tmpPacket->ToNetPacketPlayersTurn()) + { + NetPacketPlayersTurn::Data turnData; + tmpPacket->ToNetPacketPlayersTurn()->GetData(turnData); + boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId(turnData.playerId); + if (!tmpPlayer) + throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); + + // Set round. + if (curGame->getCurrentHand()->getCurrentRound() != turnData.gameState) + { + ResetPlayerActions(*curGame); + curGame->getCurrentHand()->setCurrentRound(turnData.gameState); + // Refresh actions. + client->GetGui().refreshSet(); + client->GetGui().refreshAction(); + } + + // Next player's turn. + curGame->getCurrentHand()->getCurrentBeRo()->setCurrentPlayersTurnId(tmpPlayer->getMyID()); + curGame->getCurrentHand()->getCurrentBeRo()->setPlayersTurn(tmpPlayer->getMyID()); + + // Mark current player in GUI. + int guiStatus = 2; + if (!tmpPlayer->getMyActiveStatus()) + guiStatus = 0; + else if (tmpPlayer->getMyAction() == PLAYER_ACTION_FOLD) + guiStatus = 1; + client->GetGui().refreshGroupbox(tmpPlayer->getMyID(), guiStatus); + client->GetGui().refreshAction(tmpPlayer->getMyID(), PLAYER_ACTION_NONE); + + // Start displaying the timeout for the player. + client->GetGui().startTimeoutAnimation(tmpPlayer->getMyID(), client->GetGameData().playerActionTimeoutSec); + + if (tmpPlayer->getMyID() == 0) // Is this the GUI player? + client->GetGui().meInAction(); + } + else if (tmpPacket->ToNetPacketDealFlopCards()) + { + NetPacketDealFlopCards::Data cardsData; + tmpPacket->ToNetPacketDealFlopCards()->GetData(cardsData); + int tmpCards[5]; + for (int num = 0; num < 3; num++) + tmpCards[num] = static_cast(cardsData.flopCards[num]); + tmpCards[3] = tmpCards[4] = 0; + curGame->getCurrentHand()->getBoard()->setMyCards(tmpCards); + curGame->getCurrentHand()->getBoard()->collectPot(); + curGame->getCurrentHand()->setLastPlayersTurn(-1); + + client->GetGui().logDealBoardCardsMsg(GAME_STATE_FLOP, tmpCards[0], tmpCards[1], tmpCards[2], tmpCards[3], tmpCards[4]); + client->GetGui().refreshGameLabels(GAME_STATE_FLOP); + client->GetGui().refreshPot(); + client->GetGui().refreshSet(); + client->GetGui().dealBeRoCards(1); + } + else if (tmpPacket->ToNetPacketDealTurnCard()) + { + NetPacketDealTurnCard::Data cardsData; + tmpPacket->ToNetPacketDealTurnCard()->GetData(cardsData); + int tmpCards[5]; + curGame->getCurrentHand()->getBoard()->getMyCards(tmpCards); + tmpCards[3] = static_cast(cardsData.turnCard); + curGame->getCurrentHand()->getBoard()->setMyCards(tmpCards); + curGame->getCurrentHand()->getBoard()->collectPot(); + curGame->getCurrentHand()->setLastPlayersTurn(-1); + + client->GetGui().logDealBoardCardsMsg(GAME_STATE_TURN, tmpCards[0], tmpCards[1], tmpCards[2], tmpCards[3], tmpCards[4]); + client->GetGui().refreshGameLabels(GAME_STATE_TURN); + client->GetGui().refreshPot(); + client->GetGui().refreshSet(); + client->GetGui().dealBeRoCards(2); + } + else if (tmpPacket->ToNetPacketDealRiverCard()) + { + NetPacketDealRiverCard::Data cardsData; + tmpPacket->ToNetPacketDealRiverCard()->GetData(cardsData); + int tmpCards[5]; + curGame->getCurrentHand()->getBoard()->getMyCards(tmpCards); + tmpCards[4] = static_cast(cardsData.riverCard); + curGame->getCurrentHand()->getBoard()->setMyCards(tmpCards); + curGame->getCurrentHand()->getBoard()->collectPot(); + curGame->getCurrentHand()->setLastPlayersTurn(-1); + + client->GetGui().logDealBoardCardsMsg(GAME_STATE_RIVER, tmpCards[0], tmpCards[1], tmpCards[2], tmpCards[3], tmpCards[4]); + client->GetGui().refreshGameLabels(GAME_STATE_RIVER); + client->GetGui().refreshPot(); + client->GetGui().refreshSet(); + client->GetGui().dealBeRoCards(3); + } + else if (tmpPacket->ToNetPacketAllInShowCards()) + { + curGame->getCurrentHand()->setAllInCondition(true); + + NetPacketAllInShowCards::Data allInData; + tmpPacket->ToNetPacketAllInShowCards()->GetData(allInData); + + NetPacketAllInShowCards::PlayerCardsList::const_iterator i + = allInData.playerCards.begin(); + NetPacketAllInShowCards::PlayerCardsList::const_iterator end + = allInData.playerCards.end(); + + while (i != end) + { + boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId((*i).playerId); if (!tmpPlayer) throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); - // Set round. - if (curGame->getCurrentHand()->getCurrentRound() != turnData.gameState) - { - ResetPlayerActions(*curGame); - curGame->getCurrentHand()->setCurrentRound(turnData.gameState); - // Refresh actions. - client.GetGui().refreshSet(); - client.GetGui().refreshAction(); - } - - // Next player's turn. - curGame->getCurrentHand()->getCurrentBeRo()->setCurrentPlayersTurnId(tmpPlayer->getMyID()); - curGame->getCurrentHand()->getCurrentBeRo()->setPlayersTurn(tmpPlayer->getMyID()); - - // Mark current player in GUI. - int guiStatus = 2; - if (!tmpPlayer->getMyActiveStatus()) - guiStatus = 0; - else if (tmpPlayer->getMyAction() == PLAYER_ACTION_FOLD) - guiStatus = 1; - client.GetGui().refreshGroupbox(tmpPlayer->getMyID(), guiStatus); - client.GetGui().refreshAction(tmpPlayer->getMyID(), PLAYER_ACTION_NONE); - - // Start displaying the timeout for the player. - client.GetGui().startTimeoutAnimation(tmpPlayer->getMyID(), client.GetGameData().playerActionTimeoutSec); - - if (tmpPlayer->getMyID() == 0) // Is this the GUI player? - client.GetGui().meInAction(); + int tmpCards[2]; + tmpCards[0] = static_cast((*i).cards[0]); + tmpCards[1] = static_cast((*i).cards[1]); + tmpPlayer->setMyCards(tmpCards); + ++i; } - else if (packet->ToNetPacketDealFlopCards()) + client->GetGui().flipHolecardsAllIn(); + } + else if (tmpPacket->ToNetPacketEndOfHandHideCards()) + { + curGame->getCurrentHand()->getBoard()->collectPot(); + // Reset player sets + ResetPlayerSets(*curGame); + client->GetGui().refreshPot(); + client->GetGui().refreshSet(); + // Synchronize with GUI. + client->GetGui().waitForGuiUpdateDone(); + + // End of Hand, but keep cards hidden. + NetPacketEndOfHandHideCards::Data endHandData; + tmpPacket->ToNetPacketEndOfHandHideCards()->GetData(endHandData); + + boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId(endHandData.playerId); + if (!tmpPlayer) + throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); + + tmpPlayer->setMyCash(endHandData.playerMoney); + tmpPlayer->setLastMoneyWon(endHandData.moneyWon); + list winnerList; + winnerList.push_back(tmpPlayer->getMyUniqueID()); + + curGame->getCurrentHand()->getBoard()->setPot(0); + curGame->getCurrentHand()->getBoard()->setWinners(winnerList); + + client->GetGui().postRiverRunAnimation1(); + + // Wait for next Hand. + client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_SERVER_HAND_END); + client->SetState(ClientStateWaitHand::Instance()); + } + else if (tmpPacket->ToNetPacketEndOfHandShowCards()) + { + curGame->getCurrentHand()->getBoard()->collectPot(); + // Reset player sets + ResetPlayerSets(*curGame); + client->GetGui().refreshPot(); + client->GetGui().refreshSet(); + // Synchronize with GUI. + client->GetGui().waitForGuiUpdateDone(); + + // End of Hand, show cards. + NetPacketEndOfHandShowCards::Data endHandData; + tmpPacket->ToNetPacketEndOfHandShowCards()->GetData(endHandData); + + NetPacketEndOfHandShowCards::PlayerResultList::const_iterator i + = endHandData.playerResults.begin(); + NetPacketEndOfHandShowCards::PlayerResultList::const_iterator end + = endHandData.playerResults.end(); + + list winnerList; + int highestValueOfCards = 0; + while (i != end) { - NetPacketDealFlopCards::Data cardsData; - packet->ToNetPacketDealFlopCards()->GetData(cardsData); - int tmpCards[5]; - for (int num = 0; num < 3; num++) - tmpCards[num] = static_cast(cardsData.flopCards[num]); - tmpCards[3] = tmpCards[4] = 0; - curGame->getCurrentHand()->getBoard()->setMyCards(tmpCards); - curGame->getCurrentHand()->getBoard()->collectPot(); - curGame->getCurrentHand()->setLastPlayersTurn(-1); - - client.GetGui().logDealBoardCardsMsg(GAME_STATE_FLOP, tmpCards[0], tmpCards[1], tmpCards[2], tmpCards[3], tmpCards[4]); - client.GetGui().refreshGameLabels(GAME_STATE_FLOP); - client.GetGui().refreshPot(); - client.GetGui().refreshSet(); - client.GetGui().dealBeRoCards(1); - } - else if (packet->ToNetPacketDealTurnCard()) - { - NetPacketDealTurnCard::Data cardsData; - packet->ToNetPacketDealTurnCard()->GetData(cardsData); - int tmpCards[5]; - curGame->getCurrentHand()->getBoard()->getMyCards(tmpCards); - tmpCards[3] = static_cast(cardsData.turnCard); - curGame->getCurrentHand()->getBoard()->setMyCards(tmpCards); - curGame->getCurrentHand()->getBoard()->collectPot(); - curGame->getCurrentHand()->setLastPlayersTurn(-1); - - client.GetGui().logDealBoardCardsMsg(GAME_STATE_TURN, tmpCards[0], tmpCards[1], tmpCards[2], tmpCards[3], tmpCards[4]); - client.GetGui().refreshGameLabels(GAME_STATE_TURN); - client.GetGui().refreshPot(); - client.GetGui().refreshSet(); - client.GetGui().dealBeRoCards(2); - } - else if (packet->ToNetPacketDealRiverCard()) - { - NetPacketDealRiverCard::Data cardsData; - packet->ToNetPacketDealRiverCard()->GetData(cardsData); - int tmpCards[5]; - curGame->getCurrentHand()->getBoard()->getMyCards(tmpCards); - tmpCards[4] = static_cast(cardsData.riverCard); - curGame->getCurrentHand()->getBoard()->setMyCards(tmpCards); - curGame->getCurrentHand()->getBoard()->collectPot(); - curGame->getCurrentHand()->setLastPlayersTurn(-1); - - client.GetGui().logDealBoardCardsMsg(GAME_STATE_RIVER, tmpCards[0], tmpCards[1], tmpCards[2], tmpCards[3], tmpCards[4]); - client.GetGui().refreshGameLabels(GAME_STATE_RIVER); - client.GetGui().refreshPot(); - client.GetGui().refreshSet(); - client.GetGui().dealBeRoCards(3); - } - else if (packet->ToNetPacketAllInShowCards()) - { - curGame->getCurrentHand()->setAllInCondition(true); - - NetPacketAllInShowCards::Data allInData; - packet->ToNetPacketAllInShowCards()->GetData(allInData); - - NetPacketAllInShowCards::PlayerCardsList::const_iterator i - = allInData.playerCards.begin(); - NetPacketAllInShowCards::PlayerCardsList::const_iterator end - = allInData.playerCards.end(); - - while (i != end) - { - boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId((*i).playerId); - if (!tmpPlayer) - throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); - - int tmpCards[2]; - tmpCards[0] = static_cast((*i).cards[0]); - tmpCards[1] = static_cast((*i).cards[1]); - tmpPlayer->setMyCards(tmpCards); - ++i; - } - client.GetGui().flipHolecardsAllIn(); - } - else if (packet->ToNetPacketEndOfHandHideCards()) - { - curGame->getCurrentHand()->getBoard()->collectPot(); - // Reset player sets - ResetPlayerSets(*curGame); - client.GetGui().refreshPot(); - client.GetGui().refreshSet(); - // Synchronize with GUI. - client.GetGui().waitForGuiUpdateDone(); - - // End of Hand, but keep cards hidden. - NetPacketEndOfHandHideCards::Data endHandData; - packet->ToNetPacketEndOfHandHideCards()->GetData(endHandData); - - boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId(endHandData.playerId); + boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId((*i).playerId); if (!tmpPlayer) throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); - tmpPlayer->setMyCash(endHandData.playerMoney); - tmpPlayer->setLastMoneyWon(endHandData.moneyWon); - list winnerList; - winnerList.push_back(tmpPlayer->getMyUniqueID()); + int tmpCards[2]; + int bestHandPos[5]; + tmpCards[0] = static_cast((*i).cards[0]); + tmpCards[1] = static_cast((*i).cards[1]); + tmpPlayer->setMyCards(tmpCards); + for (int num = 0; num < 5; num++) + bestHandPos[num] = (*i).bestHandPos[num]; + tmpPlayer->setMyCardsValueInt((*i).valueOfCards); + tmpPlayer->setMyBestHandPosition(bestHandPos); + if (tmpPlayer->getMyCardsValueInt() > highestValueOfCards) + highestValueOfCards = tmpPlayer->getMyCardsValueInt(); + tmpPlayer->setMyCash((*i).playerMoney); + tmpPlayer->setLastMoneyWon((*i).moneyWon); + if ((*i).moneyWon) + winnerList.push_back((*i).playerId); - curGame->getCurrentHand()->getBoard()->setPot(0); - curGame->getCurrentHand()->getBoard()->setWinners(winnerList); - - client.GetGui().postRiverRunAnimation1(); - - // Wait for next Hand. - client.SetState(ClientStateWaitHand::Instance()); - retVal = MSG_NET_GAME_SERVER_HAND_END; + ++i; } - else if (packet->ToNetPacketEndOfHandShowCards()) - { - curGame->getCurrentHand()->getBoard()->collectPot(); - // Reset player sets - ResetPlayerSets(*curGame); - client.GetGui().refreshPot(); - client.GetGui().refreshSet(); - // Synchronize with GUI. - client.GetGui().waitForGuiUpdateDone(); + curGame->getCurrentHand()->getCurrentBeRo()->setHighestCardsValue(highestValueOfCards); + curGame->getCurrentHand()->getBoard()->setPot(0); + curGame->getCurrentHand()->getBoard()->setWinners(winnerList); - // End of Hand, show cards. - NetPacketEndOfHandShowCards::Data endHandData; - packet->ToNetPacketEndOfHandShowCards()->GetData(endHandData); + client->GetGui().postRiverRunAnimation1(); - NetPacketEndOfHandShowCards::PlayerResultList::const_iterator i - = endHandData.playerResults.begin(); - NetPacketEndOfHandShowCards::PlayerResultList::const_iterator end - = endHandData.playerResults.end(); - - list winnerList; - int highestValueOfCards = 0; - while (i != end) - { - boost::shared_ptr tmpPlayer = curGame->getPlayerByUniqueId((*i).playerId); - if (!tmpPlayer) - throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); - - int tmpCards[2]; - int bestHandPos[5]; - tmpCards[0] = static_cast((*i).cards[0]); - tmpCards[1] = static_cast((*i).cards[1]); - tmpPlayer->setMyCards(tmpCards); - for (int num = 0; num < 5; num++) - bestHandPos[num] = (*i).bestHandPos[num]; - tmpPlayer->setMyCardsValueInt((*i).valueOfCards); - tmpPlayer->setMyBestHandPosition(bestHandPos); - if (tmpPlayer->getMyCardsValueInt() > highestValueOfCards) - highestValueOfCards = tmpPlayer->getMyCardsValueInt(); - tmpPlayer->setMyCash((*i).playerMoney); - tmpPlayer->setLastMoneyWon((*i).moneyWon); - if ((*i).moneyWon) - winnerList.push_back((*i).playerId); - - ++i; - } - curGame->getCurrentHand()->getCurrentBeRo()->setHighestCardsValue(highestValueOfCards); - curGame->getCurrentHand()->getBoard()->setPot(0); - curGame->getCurrentHand()->getBoard()->setWinners(winnerList); - - client.GetGui().postRiverRunAnimation1(); - - // Wait for next Hand. - client.SetState(ClientStateWaitHand::Instance()); - retVal = MSG_NET_GAME_CLIENT_HAND_END; - } + // Wait for next Hand. + client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_HAND_END); + client->SetState(ClientStateWaitHand::Instance()); } // Synchronize with GUI. - client.GetGui().waitForGuiUpdateDone(); - - return retVal; + client->GetGui().waitForGuiUpdateDone(); } void @@ -1594,27 +1654,3 @@ ClientStateRunHand::ResetPlayerSets(Game &curGame) } } -//----------------------------------------------------------------------------- - -ClientStateFinal & -ClientStateFinal::Instance() -{ - static ClientStateFinal state; - return state; -} - -ClientStateFinal::ClientStateFinal() -{ -} - -ClientStateFinal::~ClientStateFinal() -{ -} - -int -ClientStateFinal::Process(ClientThread &/*client*/) -{ - Thread::Msleep(20); - - return MSG_SOCK_INTERNAL_PENDING; -} diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index 104aebeb..c72d2d34 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -39,6 +39,8 @@ #include #define TEMP_AVATAR_FILENAME "avatar.tmp" +#define CLIENT_AVATAR_LOOP_MSEC 100 +#define CLIENT_SEND_LOOP_MSEC 50 using namespace std; using boost::asio::ip::tcp; @@ -62,10 +64,11 @@ private: }; ClientThread::ClientThread(GuiInterface &gui, AvatarManager &avatarManager) -: m_curState(NULL), m_gui(gui), m_avatarManager(avatarManager), m_isServerSelected(false), - m_curGameId(0), m_curGameNum(1), m_guiPlayerId(0), m_sessionEstablished(false) +: m_ioService(new boost::asio::io_service), m_curState(NULL), m_gui(gui), + m_avatarManager(avatarManager), m_isServerSelected(false), + m_curGameId(0), m_curGameNum(1), m_guiPlayerId(0), m_sessionEstablished(false), + m_stateTimer(*m_ioService), m_avatarTimer(*m_ioService), m_sendTimer(*m_ioService) { - m_ioService.reset(new boost::asio::io_service()); m_context.reset(new ClientContext); m_receiver.reset(new ReceiverHelper); myQtToolsInterface.reset(CreateQtToolsWrapper()); @@ -106,6 +109,13 @@ ClientThread::Init( context.SetCacheDir(cacheDir); } +void +ClientThread::SignalTermination() +{ + Thread::SignalTermination(); + m_ioService->stop(); +} + void ClientThread::SendKickPlayer(unsigned playerId) { @@ -286,6 +296,27 @@ ClientThread::SendVoteKick(bool doKick) m_outPacketList.push_back(vote); } +void +ClientThread::StartAsyncRead() +{ + ReceiveBuffer &buf = GetContext().GetSessionData()->GetReceiveBuffer(); + GetContext().GetSessionData()->GetAsioSocket()->async_read_some( + boost::asio::buffer(buf.recvBuf + buf.recvBufUsed, RECV_BUF_SIZE - buf.recvBufUsed), + boost::bind( + &ClientThread::HandleRead, + shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + +void +ClientThread::HandleRead(const boost::system::error_code& ec, size_t bytesRead) +{ + GetState().HandleRead(ec, shared_from_this(), bytesRead); + if (!ec) + StartAsyncRead(); +} + void ClientThread::SelectServer(unsigned serverId) { @@ -381,51 +412,67 @@ ClientThread::Main() m_avatarDownloader.reset(new DownloaderThread); m_avatarDownloader->Run(); SetState(CLIENT_INITIAL_STATE::Instance()); + RegisterTimers(); // Main loop. boost::asio::io_service::work ioWork(*m_ioService); try { - while (!ShouldTerminate()) { - int msg = GetState().Process(*this); - if (msg != MSG_SOCK_INTERNAL_PENDING) - { - if (msg <= MSG_SOCK_LIMIT_CONNECT) - GetCallback().SignalNetClientConnect(msg); - else - GetCallback().SignalNetClientGameInfo(msg); - - // Additionally signal the start of the game. - if (msg == MSG_NET_GAME_CLIENT_START) - { - // EngineFactory erstellen - boost::shared_ptr factory(new ClientEngineFactory); // LocalEngine erstellen - - MapPlayerDataList(); - if (GetPlayerDataList().size() != (unsigned)GetStartData().numberOfPlayers) - throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PLAYER_COUNT, 0); - m_game.reset(new Game(&m_gui, factory, GetPlayerDataList(), GetGameData(), GetStartData(), m_curGameNum++)); - // Initialize GUI speed. - GetGui().initGui(GetGameData().guiSpeed); - // Signal start of game to GUI. - GetCallback().SignalNetClientGameStart(m_game); - } - } - if (IsSessionEstablished()) - SendPacketLoop(); - m_ioService->poll(); - Thread::Msleep(10); + boost::asio::io_service::work ioWork(*m_ioService); + m_ioService->run(); // Will only be aborted asynchronously. } } catch (const PokerTHException &e) { GetCallback().SignalNetClientError(e.GetErrorId(), e.GetOsErrorCode()); } + // Cancel timers. + GetStateTimer().cancel(); + CancelTimers(); // Terminate sub-threads. m_avatarDownloader->SignalTermination(); m_avatarDownloader->Join(DOWNLOADER_THREAD_TERMINATE_TIMEOUT); } +void +ClientThread::RegisterTimers() +{ + m_avatarTimer.expires_from_now( + boost::posix_time::milliseconds(CLIENT_AVATAR_LOOP_MSEC)); + m_avatarTimer.async_wait( + boost::bind( + &ClientThread::TimerCheckAvatarDownloads, shared_from_this(), boost::asio::placeholders::error)); + + m_sendTimer.expires_from_now( + boost::posix_time::milliseconds(CLIENT_SEND_LOOP_MSEC)); + m_sendTimer.async_wait( + boost::bind( + &ClientThread::TimerSendPacketLoop, shared_from_this(), boost::asio::placeholders::error)); +} + +void +ClientThread::CancelTimers() +{ + m_avatarTimer.cancel(); + m_sendTimer.cancel(); +} + +void +ClientThread::InitGame() +{ + // EngineFactory erstellen + boost::shared_ptr factory(new ClientEngineFactory); // LocalEngine erstellen + + MapPlayerDataList(); + if (GetPlayerDataList().size() != (unsigned)GetStartData().numberOfPlayers) + throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PLAYER_COUNT, 0); + m_game.reset(new Game(&m_gui, factory, GetPlayerDataList(), GetGameData(), GetStartData(), m_curGameNum++)); + // Initialize GUI speed. + GetGui().initGui(GetGameData().guiSpeed); + // Signal start of game to GUI. + GetCallback().SignalNetClientGameStart(m_game); +} + void ClientThread::AddPacket(boost::shared_ptr packet) { @@ -434,21 +481,32 @@ ClientThread::AddPacket(boost::shared_ptr packet) } void -ClientThread::SendPacketLoop() +ClientThread::TimerSendPacketLoop(const boost::system::error_code &ec) { - boost::mutex::scoped_lock lock(m_outPacketListMutex); - - if (!m_outPacketList.empty()) + if (!ec) { - NetPacketList::iterator i = m_outPacketList.begin(); - NetPacketList::iterator end = m_outPacketList.end(); - - while (i != end) + if (IsSessionEstablished()) { - GetSender().Send(GetContext().GetSessionData(), *i); - ++i; + boost::mutex::scoped_lock lock(m_outPacketListMutex); + + if (!m_outPacketList.empty()) + { + NetPacketList::iterator i = m_outPacketList.begin(); + NetPacketList::iterator end = m_outPacketList.end(); + + while (i != end) + { + GetSender().Send(GetContext().GetSessionData(), *i); + ++i; + } + m_outPacketList.clear(); + } } - m_outPacketList.clear(); + m_sendTimer.expires_from_now( + boost::posix_time::milliseconds(CLIENT_SEND_LOOP_MSEC)); + m_sendTimer.async_wait( + boost::bind( + &ClientThread::TimerSendPacketLoop, shared_from_this(), boost::asio::placeholders::error)); } } @@ -668,15 +726,23 @@ ClientThread::SetUnknownAvatar(unsigned playerId) } void -ClientThread::CheckAvatarDownloads() +ClientThread::TimerCheckAvatarDownloads(const boost::system::error_code& ec) { - if (m_avatarDownloader && m_avatarDownloader->HasDownloadResult()) + if (!ec) { - unsigned playerId; - boost::shared_ptr tmpAvatar(new AvatarData); - m_avatarDownloader->GetDownloadResult(playerId, tmpAvatar->fileData); - tmpAvatar->reportedSize = tmpAvatar->fileData.size(); - PassAvatarDataToManager(playerId, tmpAvatar); + if (m_avatarDownloader && m_avatarDownloader->HasDownloadResult()) + { + unsigned playerId; + boost::shared_ptr tmpAvatar(new AvatarData); + m_avatarDownloader->GetDownloadResult(playerId, tmpAvatar->fileData); + tmpAvatar->reportedSize = tmpAvatar->fileData.size(); + PassAvatarDataToManager(playerId, tmpAvatar); + } + m_avatarTimer.expires_from_now( + boost::posix_time::milliseconds(CLIENT_AVATAR_LOOP_MSEC)); + m_avatarTimer.async_wait( + boost::bind( + &ClientThread::TimerCheckAvatarDownloads, shared_from_this(), boost::asio::placeholders::error)); } } @@ -724,10 +790,13 @@ void ClientThread::CreateContextSession() { bool validSocket = false; - // TODO ipv6 // TODO sctp try { - boost::shared_ptr newSock(new boost::asio::ip::tcp::socket(*m_ioService, tcp::v4())); + boost::shared_ptr newSock; + if (GetContext().GetAddrFamily() == AF_INET6) + newSock.reset(new boost::asio::ip::tcp::socket(*m_ioService, tcp::v6())); + else + newSock.reset(new boost::asio::ip::tcp::socket(*m_ioService, tcp::v4())); boost::asio::socket_base::non_blocking_io command(true); newSock->io_control(command); newSock->set_option(tcp::no_delay(true)); @@ -737,6 +806,8 @@ ClientThread::CreateContextSession() newSock, SESSION_ID_GENERIC, *m_senderCallback))); + GetContext().SetResolver(boost::shared_ptr( + new boost::asio::ip::tcp::resolver(*m_ioService))); validSocket = true; } catch (...) { @@ -755,7 +826,16 @@ ClientThread::GetState() void ClientThread::SetState(ClientState &newState) { + if (m_curState) + m_curState->Exit(shared_from_this()); m_curState = &newState; + m_curState->Enter(shared_from_this()); +} + +boost::asio::deadline_timer & +ClientThread::GetStateTimer() +{ + return m_stateTimer; } SenderHelper & diff --git a/src/net/common/servercontext.cpp b/src/net/common/servercontext.cpp deleted file mode 100644 index 44b4e35a..00000000 --- a/src/net/common/servercontext.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/*************************************************************************** - * 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 - -ServerContext::ServerContext() -: m_protocol(0), m_addrFamily(AF_INET), m_serverPort(0) -{ -} - -ServerContext::~ServerContext() -{ -} - -SOCKET -ServerContext::GetSocket() const -{ - return m_sock; -} - -void -ServerContext::SetSocket(SOCKET sock) -{ - m_sock = sock; -} - diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 196b2e8f..b7a1ed02 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -165,8 +165,8 @@ ServerLobbyThread::AddConnection(boost::shared_ptr sock) boost::bind( &ServerLobbyThread::HandleRead, this, - sessionData->GetId(), boost::asio::placeholders::error, + sessionData->GetId(), boost::asio::placeholders::bytes_transferred)); } } @@ -513,9 +513,10 @@ ServerLobbyThread::Main() RegisterTimers(); try { - m_work.reset(new boost::asio::io_service::work(*m_ioService)); - m_ioService->run(); // Will only be aborted asynchronously. - m_work.reset(); + { + boost::asio::io_service::work ioWork(*m_ioService); + m_ioService->run(); // Will only be aborted asynchronously. + } // Clear all sessions. m_sessionManager.Clear(); @@ -585,7 +586,7 @@ ServerLobbyThread::CancelTimers() } void -ServerLobbyThread::HandleRead(SessionId sessionId, const boost::system::error_code &error, size_t bytesRead) +ServerLobbyThread::HandleRead(const boost::system::error_code &ec, SessionId sessionId, size_t bytesRead) { // Find the session. SessionWrapper session = m_sessionManager.GetSessionById(sessionId); @@ -593,7 +594,7 @@ ServerLobbyThread::HandleRead(SessionId sessionId, const boost::system::error_co session = m_gameSessionManager.GetSessionById(sessionId); if (session.sessionData) { - if (!error) + if (!ec) { ReceiveBuffer &buf = session.sessionData->GetReceiveBuffer(); buf.recvBufUsed += bytesRead; @@ -625,8 +626,8 @@ ServerLobbyThread::HandleRead(SessionId sessionId, const boost::system::error_co boost::bind( &ServerLobbyThread::HandleRead, this, - sessionId, boost::asio::placeholders::error, + sessionId, boost::asio::placeholders::bytes_transferred)); } else diff --git a/src/net/common/servermanager.cpp b/src/net/common/servermanager.cpp index cdef59fb..42f9b9b1 100644 --- a/src/net/common/servermanager.cpp +++ b/src/net/common/servermanager.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -39,7 +38,7 @@ using namespace std; ServerManager::ServerManager(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager) : m_gui(gui), m_playerConfig(config), m_avatarManager(avatarManager) { - m_ioService.reset(new boost::asio::io_service()); + m_ioService.reset(new boost::asio::io_service); } ServerManager::~ServerManager() diff --git a/src/net/servercontext.h b/src/net/servercontext.h deleted file mode 100644 index 54071f88..00000000 --- a/src/net/servercontext.h +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -/* Context of network server. */ - -#ifndef _SERVERCONTEXT_H_ -#define _SERVERCONTEXT_H_ - -#include - - -class ServerContext : public NetContext -{ -public: - ServerContext(); - virtual ~ServerContext(); - - virtual SOCKET GetSocket() const; - - void SetSocket(SOCKET sock); - - int GetProtocol() const - {return m_protocol;} - void SetProtocol(int protocol) - {m_protocol = protocol;} - int GetAddrFamily() const - {return m_addrFamily;} - void SetAddrFamily(int addrFamily) - {m_addrFamily = addrFamily;} - unsigned GetServerPort() const - {return m_serverPort;} - void SetServerPort(unsigned serverPort) - {m_serverPort = serverPort;} - -private: - SOCKET m_sock; - int m_protocol; - int m_addrFamily; - unsigned m_serverPort; -}; - -#endif diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index 8943617e..8f85a277 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -115,7 +115,7 @@ protected: void RegisterTimers(); void CancelTimers(); - void HandleRead(SessionId sessionId, const boost::system::error_code &error, size_t bytesRead); + void HandleRead(const boost::system::error_code &ec, SessionId sessionId, size_t bytesRead); void HandlePacket(SessionWrapper session, boost::shared_ptr packet); void HandleNetPacketInit(SessionWrapper session, const NetPacketInit &tmpPacket); void HandleNetPacketAvatarHeader(SessionWrapper session, const NetPacketAvatarHeader &tmpPacket); @@ -173,7 +173,6 @@ protected: private: boost::shared_ptr m_ioService; - boost::shared_ptr m_work; boost::shared_ptr m_senderCallback; boost::shared_ptr m_sender; diff --git a/src/session.cpp b/src/session.cpp index 78504cbf..3fea6dc1 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -43,8 +43,7 @@ using namespace std; Session::Session(GuiInterface *g, ConfigFile *c) -: currentGameNum(0), myNetClient(NULL), myNetServer(NULL), myClientIrcThread(NULL), - myGui(g), myConfig(c), myGameType(GAME_TYPE_NONE) +: currentGameNum(0), myGui(g), myConfig(c), myGameType(GAME_TYPE_NONE) { myQtToolsInterface = CreateQtToolsWrapper(); } @@ -165,7 +164,7 @@ void Session::startInternetClient() if (myConfig->readConfigInt("UseIRCLobbyChat")) { - myClientIrcThread = new IrcThread(myGui); + myClientIrcThread.reset(new IrcThread(myGui)); myClientIrcThread->Init( myConfig->readConfigString("IRCServerAddress"), myConfig->readConfigInt("IRCServerPort"), @@ -180,7 +179,7 @@ void Session::startInternetClient() myClientIrcThread->Run(); } - myNetClient = new ClientThread(*myGui, *myAvatarManager); + myNetClient.reset(new ClientThread(*myGui, *myAvatarManager)); bool useAvatarServer = myConfig->readConfigInt("UseAvatarServer") != 0; myNetClient->Init( @@ -211,7 +210,7 @@ void Session::startNetworkClient(const string &serverAddress, unsigned serverPor } myGameType = GAME_TYPE_NETWORK; - myNetClient = new ClientThread(*myGui, *myAvatarManager); + myNetClient.reset(new ClientThread(*myGui, *myAvatarManager)); myNetClient->Init( serverAddress, "", @@ -237,7 +236,7 @@ void Session::startNetworkClientForLocalServer(const GameData &gameData) } myGameType = GAME_TYPE_NETWORK; - myNetClient = new ClientThread(*myGui, *myAvatarManager); + myNetClient.reset(new ClientThread(*myGui, *myAvatarManager)); bool useIpv6 = myConfig->readConfigInt("ServerUseIpv6") == 1; const char *loopbackAddr = useIpv6 ? "::1" : "127.0.0.1"; myNetClient->Init( @@ -265,13 +264,11 @@ void Session::terminateNetworkClient() myClientIrcThread->SignalTermination(); // Give the threads some time to terminate. if (myNetClient->Join(NET_CLIENT_TERMINATE_TIMEOUT_MSEC)) - delete myNetClient; + myNetClient.reset(); if (myClientIrcThread && myClientIrcThread->Join(NET_IRC_TERMINATE_TIMEOUT_MSEC)) - delete myClientIrcThread; + myClientIrcThread.reset(); // If termination fails, leave a memory leak to prevent a crash. - myNetClient = 0; - myClientIrcThread = 0; myGameType = GAME_TYPE_NONE; } @@ -297,12 +294,12 @@ void Session::startNetworkServer() return; } - myNetServer = new ServerManager(*myGui, myConfig, *myAvatarManager); + myNetServer.reset(new ServerManager(*myGui, myConfig, *myAvatarManager)); boost::shared_ptr tmpIrcThread; if (myConfig->readConfigInt("UseAdminIRC")) { - tmpIrcThread = boost::shared_ptr(new IrcThread(myNetServer)); + tmpIrcThread = boost::shared_ptr(new IrcThread(myNetServer.get())); tmpIrcThread->Init( myConfig->readConfigString("AdminIRCServerAddress"), @@ -332,9 +329,8 @@ void Session::terminateNetworkServer() myNetServer->SignalTerminationAll(); // Give the thread some time to terminate. if (myNetServer->JoinAll(true)) - delete myNetServer; + myNetServer.reset(); // If termination fails, leave a memory leak to prevent a crash. - myNetServer = 0; } bool Session::pollNetworkServerTerminated() @@ -433,13 +429,13 @@ void Session::voteKick(bool doKick) bool Session::isNetworkClientRunning() const { // This, and every place which calls this, is a HACK. - return myNetClient != NULL; + return myNetClient.get() != NULL; } bool Session::isNetworkServerRunning() const { // This, and every place which calls this, is a HACK. - return myNetServer != NULL; + return myNetServer.get() != NULL; } ServerInfo Session::getClientServerInfo(unsigned serverId) const diff --git a/src/session.h b/src/session.h index e31a7231..9767810a 100755 --- a/src/session.h +++ b/src/session.h @@ -106,9 +106,9 @@ private: std::string myIrcNick; - ClientThread *myNetClient; - ServerManager *myNetServer; - IrcThread *myClientIrcThread; + boost::shared_ptr myNetClient; + boost::shared_ptr myNetServer; + boost::shared_ptr myClientIrcThread; boost::shared_ptr myAvatarManager;