From 4b04aedc3fe78c1272aa7cedc7ff0dfb879bf70a Mon Sep 17 00:00:00 2001 From: lotodore Date: Tue, 29 Apr 2008 22:46:27 +0000 Subject: [PATCH] Download only md5 of the server list if the list is still in the cache. --- src/net/clientstate.h | 42 +++++++ src/net/clientthread.h | 2 + src/net/common/clientstate.cpp | 202 +++++++++++++++++++++++++-------- 3 files changed, 201 insertions(+), 45 deletions(-) diff --git a/src/net/clientstate.h b/src/net/clientstate.h index e1b17b97..9936c953 100644 --- a/src/net/clientstate.h +++ b/src/net/clientstate.h @@ -124,6 +124,32 @@ protected: ClientStateStartServerListDownload(); }; +// State: Synchronizing server list. +class ClientStateSynchronizingServerList : public ClientState +{ +public: + // Access the state singleton. + static ClientStateSynchronizingServerList &Instance(); + + virtual ~ClientStateSynchronizingServerList(); + + void SetDownloadHelper(DownloadHelper *helper); + + // Poll for the completion of the download. + virtual int Process(ClientThread &client); + +protected: + + // Protected constructor - this is a singleton. + ClientStateSynchronizingServerList(); + + void Cleanup(); + +private: + + DownloadHelper *m_downloadHelper; +}; + // State: Downloading the server list. class ClientStateDownloadingServerList : public ClientState { @@ -150,6 +176,22 @@ private: DownloadHelper *m_downloadHelper; }; +// State: Reading the server list. +class ClientStateReadingServerList : public ClientState +{ +public: + static ClientStateReadingServerList &Instance(); + + virtual ~ClientStateReadingServerList(); + + virtual int Process(ClientThread &client); + +protected: + + // Protected constructor - this is a singleton. + ClientStateReadingServerList(); +}; + // State: Initiate server connection. class ClientStateStartConnect : public ClientState { diff --git a/src/net/clientthread.h b/src/net/clientthread.h index 1b5cae3f..9003a2dc 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -198,7 +198,9 @@ friend class ClientStateInit; friend class ClientStateStartResolve; friend class ClientStateResolving; friend class ClientStateStartServerListDownload; +friend class ClientStateSynchronizingServerList; friend class ClientStateDownloadingServerList; +friend class ClientStateReadingServerList; friend class ClientStateStartConnect; friend class ClientStateConnecting; friend class ClientStateStartSession; diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 32f5f4b0..c90813b5 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -257,16 +258,102 @@ ClientStateStartServerListDownload::Process(ClientThread &client) path tmpServerListPath(context.GetCacheDir()); tmpServerListPath /= "serverlist.xml.z"; - std::auto_ptr downloader(new DownloadHelper); - downloader->Init("pokerth.net/serverlist.xml.z", tmpServerListPath.directory_string()); - ClientStateDownloadingServerList::Instance().SetDownloadHelper(downloader.release()); - client.SetState(ClientStateDownloadingServerList::Instance()); + if (exists(tmpServerListPath)) + { + // Download and compare md5. + tmpServerListPath = change_extension(tmpServerListPath, extension(tmpServerListPath) + ".md5"); + std::auto_ptr downloader(new DownloadHelper); + downloader->Init("pokerth.net/serverlist.xml.z.md5", tmpServerListPath.directory_string()); + ClientStateSynchronizingServerList::Instance().SetDownloadHelper(downloader.release()); + client.SetState(ClientStateSynchronizingServerList::Instance()); + } + else + { + // Download server list. + std::auto_ptr downloader(new DownloadHelper); + downloader->Init("pokerth.net/serverlist.xml.z", tmpServerListPath.directory_string()); + ClientStateDownloadingServerList::Instance().SetDownloadHelper(downloader.release()); + client.SetState(ClientStateDownloadingServerList::Instance()); + } return retVal; } //----------------------------------------------------------------------------- +ClientStateSynchronizingServerList & +ClientStateSynchronizingServerList::Instance() +{ + static ClientStateSynchronizingServerList state; + return state; +} + +ClientStateSynchronizingServerList::ClientStateSynchronizingServerList() +: m_downloadHelper(NULL) +{ +} + +ClientStateSynchronizingServerList::~ClientStateSynchronizingServerList() +{ + Cleanup(); +} + +void +ClientStateSynchronizingServerList::SetDownloadHelper(DownloadHelper *helper) +{ + Cleanup(); + m_downloadHelper = helper; +} + +int +ClientStateSynchronizingServerList::Process(ClientThread &client) +{ + int retVal = MSG_SOCK_INTERNAL_PENDING; + + if (m_downloadHelper->Process()) + { + Cleanup(); + ClientContext &context = client.GetContext(); + path md5ServerListPath(context.GetCacheDir()); + md5ServerListPath /= "serverlist.xml.z.md5"; + path zippedServerListPath = change_extension(md5ServerListPath, ""); + // Compare the md5 sums. + string tmpMd5; + { + ifstream inFile(md5ServerListPath.directory_string().c_str(), ios_base::in); + inFile >> tmpMd5; + // TODO error handling + } + MD5Buf downloadedMd5; + downloadedMd5.FromString(tmpMd5); + MD5Buf currentMd5; + CryptHelper::MD5Sum(zippedServerListPath.directory_string(), currentMd5); + if (downloadedMd5 == currentMd5) + { + // Server list is still current. + client.SetState(ClientStateReadingServerList::Instance()); + } + else + { + // Download new server list. + remove(zippedServerListPath); + client.SetState(ClientStateStartServerListDownload::Instance()); + } + } + + return retVal; +} + + +void +ClientStateSynchronizingServerList::Cleanup() +{ + delete m_downloadHelper; + m_downloadHelper = NULL; +} + +//----------------------------------------------------------------------------- + ClientStateDownloadingServerList & ClientStateDownloadingServerList::Instance() { @@ -296,49 +383,10 @@ ClientStateDownloadingServerList::Process(ClientThread &client) { int retVal = MSG_SOCK_INTERNAL_PENDING; - // TODO -// if (!m_resolver) -// throw ClientException(__FILE__, __LINE__, ERR_SOCK_RESOLVE_FAILED, 0); - if (m_downloadHelper->Process()) { - ClientContext &context = client.GetContext(); - path zippedServerListPath(context.GetCacheDir()); - zippedServerListPath /= "serverlist.xml.z"; - path xmlServerListPath = change_extension(zippedServerListPath, ""); - // Unzip the file. - { - ifstream inFile(zippedServerListPath.directory_string().c_str(), ios_base::in | ios_base::binary); - ofstream outFile(xmlServerListPath.directory_string().c_str(), ios_base::out); - boost::iostreams::filtering_streambuf in; - in.push(boost::iostreams::zlib_decompressor()); - in.push(inFile); - boost::iostreams::copy(in, outFile); - } - // Parse the server address. - TiXmlDocument doc(xmlServerListPath.directory_string()); - - if (doc.LoadFile()) - { - TiXmlHandle docHandle(&doc); - const TiXmlElement *firstServer = docHandle.FirstChild("ServerList" ).FirstChild("Server").ToElement(); - if (firstServer) - { - ClientContext &context = client.GetContext(); - const TiXmlNode *addrNode = firstServer->FirstChild("IPv4Address"); - if (addrNode && addrNode->ToElement()) - context.SetServerAddr(addrNode->ToElement()->Attribute("value")); - const TiXmlNode *portNode = firstServer->FirstChild("Port"); - if (portNode && portNode->ToElement()) - { - int tmpPort = 0; - portNode->ToElement()->QueryIntAttribute("value", &tmpPort); - context.SetServerPort((unsigned)tmpPort); - } - } - } - - client.SetState(ClientStateStartResolve::Instance()); + Cleanup(); + client.SetState(ClientStateReadingServerList::Instance()); } return retVal; @@ -354,6 +402,70 @@ ClientStateDownloadingServerList::Cleanup() //----------------------------------------------------------------------------- +ClientStateReadingServerList & +ClientStateReadingServerList::Instance() +{ + static ClientStateReadingServerList state; + return state; +} + +ClientStateReadingServerList::ClientStateReadingServerList() +{ +} + +ClientStateReadingServerList::~ClientStateReadingServerList() +{ +} + +int +ClientStateReadingServerList::Process(ClientThread &client) +{ + int retVal = MSG_SOCK_INTERNAL_PENDING; + + ClientContext &context = client.GetContext(); + path zippedServerListPath(context.GetCacheDir()); + zippedServerListPath /= "serverlist.xml.z"; + path xmlServerListPath = change_extension(zippedServerListPath, ""); + + // Unzip the file. + { + ifstream inFile(zippedServerListPath.directory_string().c_str(), ios_base::in | ios_base::binary); + ofstream outFile(xmlServerListPath.directory_string().c_str(), ios_base::out); + boost::iostreams::filtering_streambuf in; + in.push(boost::iostreams::zlib_decompressor()); + in.push(inFile); + boost::iostreams::copy(in, outFile); + } + + // Parse the server address. + TiXmlDocument doc(xmlServerListPath.directory_string()); + + if (doc.LoadFile()) + { + TiXmlHandle docHandle(&doc); + const TiXmlElement *firstServer = docHandle.FirstChild("ServerList" ).FirstChild("Server").ToElement(); + if (firstServer) + { + const TiXmlNode *addrNode = firstServer->FirstChild("IPv4Address"); + if (addrNode && addrNode->ToElement()) + context.SetServerAddr(addrNode->ToElement()->Attribute("value")); + const TiXmlNode *portNode = firstServer->FirstChild("Port"); + if (portNode && portNode->ToElement()) + { + int tmpPort = 0; + portNode->ToElement()->QueryIntAttribute("value", &tmpPort); + context.SetServerPort((unsigned)tmpPort); + } + } + } + // TODO error handling + client.SetState(ClientStateStartResolve::Instance()); + + return retVal; +} + +//----------------------------------------------------------------------------- + ClientStateStartConnect & ClientStateStartConnect::Instance() {