Added loads of error handling to the new server list download code. Added several new error messages.

This commit is contained in:
lotodore
2008-05-10 18:07:46 +00:00
parent b5c2399603
commit 17d68255b6
5 changed files with 132 additions and 60 deletions
+38
View File
@@ -3148,6 +3148,44 @@ void gameTableImpl::networkError(int errorID, int /*osErrorID*/) {
tr("Internal state error.\nPlease make sure that all players use the same version of PokerTH."), tr("Internal state error.\nPlease make sure that all players use the same version of PokerTH."),
QMessageBox::Close); } QMessageBox::Close); }
break; break;
case ERR_SOCK_INVALID_SERVERLIST_URL:
case ERR_SOCK_DOWNLOAD_INVALID_URL:
{ QMessageBox::warning(this, tr("Network Error"),
tr("Invalid server list URL.\nPlease correct the address in the settings."),
QMessageBox::Close); }
break;
case ERR_SOCK_OPEN_MD5_FAILED:
{ QMessageBox::warning(this, tr("Network Error"),
tr("Could not open the server list MD5 file.\nPlease make sure that the server list URL is correct."),
QMessageBox::Close); }
break;
case ERR_SOCK_INVALID_SERVERLIST_MD5:
{ QMessageBox::warning(this, tr("Network Error"),
tr("Synchronization of the PokerTH internet server list has failed.\nPlease make sure that the server list URL is correct."),
QMessageBox::Close); }
break;
case ERR_SOCK_INVALID_SERVERLIST_XML:
{ QMessageBox::warning(this, tr("Network Error"),
tr("The PokerTH internet server list contains invalid data.\nIf you use a custom server list, please make sure its format is correct."),
QMessageBox::Close); }
break;
case ERR_SOCK_UNZIP_FAILED:
{ QMessageBox::warning(this, tr("Network Error"),
tr("Could not unzip the PokerTH internet server list."),
QMessageBox::Close); }
break;
case ERR_SOCK_DOWNLOAD_INIT_FAILED:
case ERR_SOCK_DOWNLOAD_SELECT_FAILED:
case ERR_SOCK_DOWNLOAD_FAILED:
{ QMessageBox::warning(this, tr("Network Error"),
tr("Could not download the PokerTH internet server list.\nPlease make sure you are directly connected to the internet."),
QMessageBox::Close); }
break;
case ERR_SOCK_DOWNLOAD_OPEN_FAILED:
{ QMessageBox::warning(this, tr("Network Error"),
tr("Could not open the target file when downloading the server list."),
QMessageBox::Close); }
break;
case ERR_NET_VERSION_NOT_SUPPORTED: case ERR_NET_VERSION_NOT_SUPPORTED:
{ QMessageBox msgBox(QMessageBox::Warning, tr("Network Error"), { QMessageBox msgBox(QMessageBox::Warning, tr("Network Error"),
tr("The PokerTH server does not support this version of the game.<br>Please go to <a href=\"http://www.pokerth.net/\" target=\"_blank\">http://www.pokerth.net</a> and download the latest version."), tr("The PokerTH server does not support this version of the game.<br>Please go to <a href=\"http://www.pokerth.net/\" target=\"_blank\">http://www.pokerth.net</a> and download the latest version."),
+2 -6
View File
@@ -143,11 +143,9 @@ protected:
// Protected constructor - this is a singleton. // Protected constructor - this is a singleton.
ClientStateSynchronizingServerList(); ClientStateSynchronizingServerList();
void Cleanup();
private: private:
DownloadHelper *m_downloadHelper; std::auto_ptr<DownloadHelper> m_downloadHelper;
}; };
// State: Downloading the server list. // State: Downloading the server list.
@@ -169,11 +167,9 @@ protected:
// Protected constructor - this is a singleton. // Protected constructor - this is a singleton.
ClientStateDownloadingServerList(); ClientStateDownloadingServerList();
void Cleanup();
private: private:
DownloadHelper *m_downloadHelper; std::auto_ptr<DownloadHelper> m_downloadHelper;
}; };
// State: Reading the server list. // State: Reading the server list.
+33 -44
View File
@@ -260,9 +260,9 @@ ClientStateStartServerListDownload::Process(ClientThread &client)
string serverListUrl(context.GetServerListUrl()); string serverListUrl(context.GetServerListUrl());
// Retrieve the file name from the URL. // Retrieve the file name from the URL.
size_t pos = serverListUrl.find_last_of('/'); size_t pos = serverListUrl.find_last_of('/');
if (pos == string::npos || ++pos >= serverListUrl.length()) if (serverListUrl.empty() || pos == string::npos || ++pos >= serverListUrl.length())
{ {
// TODO throw exception. throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_URL, 0);
} }
tmpServerListPath /= serverListUrl.substr(pos); tmpServerListPath /= serverListUrl.substr(pos);
if (exists(tmpServerListPath)) if (exists(tmpServerListPath))
@@ -296,20 +296,17 @@ ClientStateSynchronizingServerList::Instance()
} }
ClientStateSynchronizingServerList::ClientStateSynchronizingServerList() ClientStateSynchronizingServerList::ClientStateSynchronizingServerList()
: m_downloadHelper(NULL)
{ {
} }
ClientStateSynchronizingServerList::~ClientStateSynchronizingServerList() ClientStateSynchronizingServerList::~ClientStateSynchronizingServerList()
{ {
Cleanup();
} }
void void
ClientStateSynchronizingServerList::SetDownloadHelper(DownloadHelper *helper) ClientStateSynchronizingServerList::SetDownloadHelper(DownloadHelper *helper)
{ {
Cleanup(); m_downloadHelper.reset(helper);
m_downloadHelper = helper;
} }
int int
@@ -319,25 +316,28 @@ ClientStateSynchronizingServerList::Process(ClientThread &client)
if (m_downloadHelper->Process()) if (m_downloadHelper->Process())
{ {
Cleanup(); m_downloadHelper.reset(NULL);
ClientContext &context = client.GetContext(); ClientContext &context = client.GetContext();
path md5ServerListPath(context.GetCacheDir()); path md5ServerListPath(context.GetCacheDir());
// No more checking needed as this was done before. // No more checking needed as this was done before.
md5ServerListPath /= context.GetServerListUrl().substr(context.GetServerListUrl().find_last_of('/') + 1) + ".md5"; md5ServerListPath /= context.GetServerListUrl().substr(context.GetServerListUrl().find_last_of('/') + 1) + ".md5";
path zippedServerListPath = change_extension(md5ServerListPath, ""); path serverListPath = change_extension(md5ServerListPath, "");
// Compare the md5 sums. // Compare the md5 sums.
string tmpMd5; string tmpMd5;
{ {
ifstream inFile(md5ServerListPath.directory_string().c_str(), ios_base::in); 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; inFile >> tmpMd5;
// TODO error handling
} }
MD5Buf downloadedMd5; MD5Buf downloadedMd5;
downloadedMd5.FromString(tmpMd5); if (!downloadedMd5.FromString(tmpMd5))
throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_MD5, 0);
MD5Buf currentMd5; MD5Buf currentMd5;
CryptHelper::MD5Sum(zippedServerListPath.directory_string(), currentMd5); if (!CryptHelper::MD5Sum(serverListPath.directory_string(), currentMd5))
throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_MD5, 0);
if (downloadedMd5 == currentMd5) if (downloadedMd5 == currentMd5)
{ {
// Server list is still current. // Server list is still current.
@@ -346,7 +346,7 @@ ClientStateSynchronizingServerList::Process(ClientThread &client)
else else
{ {
// Download new server list. // Download new server list.
remove(zippedServerListPath); remove(serverListPath);
client.SetState(ClientStateStartServerListDownload::Instance()); client.SetState(ClientStateStartServerListDownload::Instance());
} }
} }
@@ -354,14 +354,6 @@ ClientStateSynchronizingServerList::Process(ClientThread &client)
return retVal; return retVal;
} }
void
ClientStateSynchronizingServerList::Cleanup()
{
delete m_downloadHelper;
m_downloadHelper = NULL;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ClientStateDownloadingServerList & ClientStateDownloadingServerList &
@@ -372,20 +364,17 @@ ClientStateDownloadingServerList::Instance()
} }
ClientStateDownloadingServerList::ClientStateDownloadingServerList() ClientStateDownloadingServerList::ClientStateDownloadingServerList()
: m_downloadHelper(NULL)
{ {
} }
ClientStateDownloadingServerList::~ClientStateDownloadingServerList() ClientStateDownloadingServerList::~ClientStateDownloadingServerList()
{ {
Cleanup();
} }
void void
ClientStateDownloadingServerList::SetDownloadHelper(DownloadHelper *helper) ClientStateDownloadingServerList::SetDownloadHelper(DownloadHelper *helper)
{ {
Cleanup(); m_downloadHelper.reset(helper);
m_downloadHelper = helper;
} }
int int
@@ -395,21 +384,13 @@ ClientStateDownloadingServerList::Process(ClientThread &client)
if (m_downloadHelper->Process()) if (m_downloadHelper->Process())
{ {
Cleanup(); m_downloadHelper.reset(NULL);
client.SetState(ClientStateReadingServerList::Instance()); client.SetState(ClientStateReadingServerList::Instance());
} }
return retVal; return retVal;
} }
void
ClientStateDownloadingServerList::Cleanup()
{
delete m_downloadHelper;
m_downloadHelper = NULL;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ClientStateReadingServerList & ClientStateReadingServerList &
@@ -441,13 +422,16 @@ ClientStateReadingServerList::Process(ClientThread &client)
xmlServerListPath = change_extension(zippedServerListPath, ""); xmlServerListPath = change_extension(zippedServerListPath, "");
// Unzip the file using zlib. // Unzip the file using zlib.
{ try {
ifstream inFile(zippedServerListPath.directory_string().c_str(), ios_base::in | ios_base::binary); ifstream inFile(zippedServerListPath.directory_string().c_str(), ios_base::in | ios_base::binary);
ofstream outFile(xmlServerListPath.directory_string().c_str(), ios_base::out); ofstream outFile(xmlServerListPath.directory_string().c_str(), ios_base::out);
boost::iostreams::filtering_streambuf<boost::iostreams::input> in; boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
in.push(boost::iostreams::zlib_decompressor()); in.push(boost::iostreams::zlib_decompressor());
in.push(inFile); in.push(inFile);
boost::iostreams::copy(in, outFile); boost::iostreams::copy(in, outFile);
} catch (...)
{
throw ClientException(__FILE__, __LINE__, ERR_SOCK_UNZIP_FAILED, 0);
} }
} }
else else
@@ -467,19 +451,24 @@ ClientStateReadingServerList::Process(ClientThread &client)
addrNode = firstServer->FirstChild("IPv6Address"); addrNode = firstServer->FirstChild("IPv6Address");
else else
addrNode = firstServer->FirstChild("IPv4Address"); addrNode = firstServer->FirstChild("IPv4Address");
if (addrNode && addrNode->ToElement())
context.SetServerAddr(addrNode->ToElement()->Attribute("value"));
const TiXmlNode *portNode = firstServer->FirstChild("Port"); const TiXmlNode *portNode = firstServer->FirstChild("Port");
if (portNode && portNode->ToElement())
{ if (!addrNode || !addrNode->ToElement() || !portNode || !portNode->ToElement())
int tmpPort = 0; throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_XML, 0);
portNode->ToElement()->QueryIntAttribute("value", &tmpPort);
context.SetServerPort((unsigned)tmpPort); context.SetServerAddr(addrNode->ToElement()->Attribute("value"));
retVal = MSG_SOCK_SERVER_LIST_DONE;
} int tmpPort = 0;
portNode->ToElement()->QueryIntAttribute("value", &tmpPort);
context.SetServerPort((unsigned)tmpPort);
retVal = MSG_SOCK_SERVER_LIST_DONE;
} }
else
throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_XML, 0);
} }
// TODO error handling else
throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_XML, 0);
client.SetState(ClientStateStartResolve::Instance()); client.SetState(ClientStateStartResolve::Instance());
return retVal; return retVal;
+48 -9
View File
@@ -19,6 +19,8 @@
#include <net/socket_helper.h> #include <net/socket_helper.h>
#include <net/downloadhelper.h> #include <net/downloadhelper.h>
#include <net/netexception.h>
#include <net/socket_msg.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <cstdio> #include <cstdio>
@@ -50,17 +52,30 @@ DownloadHelper::~DownloadHelper()
void void
DownloadHelper::Init(const string &url, const string &targetFileName) DownloadHelper::Init(const string &url, const string &targetFileName)
{ {
// Open target file for writing.
m_data->targetFile = fopen(targetFileName.c_str(), "wb"); m_data->targetFile = fopen(targetFileName.c_str(), "wb");
m_data->curlHandle = curl_easy_init(); if (!m_data->targetFile)
m_data->curlMultiHandle = curl_multi_init(); throw NetException(__FILE__, __LINE__, ERR_SOCK_DOWNLOAD_OPEN_FAILED, 0);
// TODO throw exception on error // Initialise curl.
m_data->curlHandle = curl_easy_init();
if (!m_data->curlHandle)
throw NetException(__FILE__, __LINE__, ERR_SOCK_DOWNLOAD_INIT_FAILED, 0);
m_data->curlMultiHandle = curl_multi_init();
if (!m_data->curlMultiHandle)
throw NetException(__FILE__, __LINE__, ERR_SOCK_DOWNLOAD_INIT_FAILED, 0);
// Use a copy of the url string, because some curl versions require a copy.
m_data->curlUrl = url; m_data->curlUrl = url;
curl_easy_setopt(m_data->curlHandle, CURLOPT_URL, m_data->curlUrl.c_str()); if (curl_easy_setopt(m_data->curlHandle, CURLOPT_URL, m_data->curlUrl.c_str()) != CURLE_OK)
throw NetException(__FILE__, __LINE__, ERR_SOCK_DOWNLOAD_INVALID_URL, 0);
// Assume that the following calls never fail.
curl_easy_setopt(m_data->curlHandle, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(m_data->curlHandle, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(m_data->curlHandle, CURLOPT_WRITEDATA, m_data->targetFile); curl_easy_setopt(m_data->curlHandle, CURLOPT_WRITEDATA, m_data->targetFile);
curl_multi_add_handle(m_data->curlMultiHandle, m_data->curlHandle); // Use the multi interface for better abort handling.
if (curl_multi_add_handle(m_data->curlMultiHandle, m_data->curlHandle) != CURLM_OK)
throw NetException(__FILE__, __LINE__, ERR_SOCK_DOWNLOAD_INIT_FAILED, 0);
} }
bool bool
@@ -74,13 +89,16 @@ DownloadHelper::Process()
curlResult = curl_multi_perform(m_data->curlMultiHandle, &runningHandles); curlResult = curl_multi_perform(m_data->curlMultiHandle, &runningHandles);
} while (curlResult == CURLM_CALL_MULTI_PERFORM); } while (curlResult == CURLM_CALL_MULTI_PERFORM);
if (curlResult != CURLM_OK)
throw NetException(__FILE__, __LINE__, ERR_SOCK_DOWNLOAD_FAILED, 0);
if (runningHandles) if (runningHandles)
{ {
struct timeval timeout; struct timeval timeout;
fd_set readSet; fd_set readSet;
fd_set writeSet; fd_set writeSet;
fd_set exceptSet; fd_set exceptSet;
int maxfd; int maxfd = -1;
FD_ZERO(&readSet); FD_ZERO(&readSet);
FD_ZERO(&writeSet); FD_ZERO(&writeSet);
@@ -92,15 +110,36 @@ DownloadHelper::Process()
curl_multi_fdset(m_data->curlMultiHandle, &readSet, &writeSet, &exceptSet, &maxfd); curl_multi_fdset(m_data->curlMultiHandle, &readSet, &writeSet, &exceptSet, &maxfd);
if (maxfd >= 0) if (maxfd >= 0)
{
int selectResult = select(maxfd+1, &readSet, &writeSet, &exceptSet, &timeout); int selectResult = select(maxfd+1, &readSet, &writeSet, &exceptSet, &timeout);
// TODO throw exception on error if (!IS_VALID_SELECT(selectResult))
throw NetException(__FILE__, __LINE__, ERR_SOCK_DOWNLOAD_SELECT_FAILED, SOCKET_ERRNO());
}
} }
else else
{ {
// Retrieve actual error code.
int numMsgs; int numMsgs;
CURLMsg *tmpMsg = curl_multi_info_read(m_data->curlMultiHandle, &numMsgs); CURLMsg *tmpMsg;
CURLcode code = tmpMsg->data.result; CURLcode code = CURLE_FAILED_INIT;
do {
tmpMsg = curl_multi_info_read(m_data->curlMultiHandle, &numMsgs);
if (tmpMsg)
code = tmpMsg->data.result;
} while (tmpMsg && tmpMsg->msg != CURLMSG_DONE);
// Clean up the curl handles.
Cleanup(); Cleanup();
// Throw exception if an error occured.
if (code != CURLE_OK)
{
if (code == CURLE_URL_MALFORMAT)
throw NetException(__FILE__, __LINE__, ERR_SOCK_DOWNLOAD_INVALID_URL, 0);
else
throw NetException(__FILE__, __LINE__, ERR_SOCK_DOWNLOAD_FAILED, 0);
}
retVal = true; retVal = true;
} }
return retVal; return retVal;
+11 -1
View File
@@ -20,7 +20,7 @@
#ifndef _SOCKET_MSG_H_ #ifndef _SOCKET_MSG_H_
#define _SOCKET_MSG_H_ #define _SOCKET_MSG_H_
// Socket or socket related errors. // Socket or connection related errors.
#define ERR_SOCK_INTERNAL 1 #define ERR_SOCK_INTERNAL 1
#define ERR_SOCK_SERVERADDR_NOT_SET 2 #define ERR_SOCK_SERVERADDR_NOT_SET 2
#define ERR_SOCK_INVALID_PORT 3 #define ERR_SOCK_INVALID_PORT 3
@@ -41,6 +41,16 @@
#define ERR_SOCK_INVALID_PACKET 18 #define ERR_SOCK_INVALID_PACKET 18
#define ERR_SOCK_INVALID_STATE 19 #define ERR_SOCK_INVALID_STATE 19
#define ERR_SOCK_INVALID_TYPE 20 #define ERR_SOCK_INVALID_TYPE 20
#define ERR_SOCK_INVALID_SERVERLIST_URL 21
#define ERR_SOCK_OPEN_MD5_FAILED 22
#define ERR_SOCK_INVALID_SERVERLIST_MD5 23
#define ERR_SOCK_INVALID_SERVERLIST_XML 24
#define ERR_SOCK_UNZIP_FAILED 25
#define ERR_SOCK_DOWNLOAD_INIT_FAILED 26
#define ERR_SOCK_DOWNLOAD_OPEN_FAILED 27
#define ERR_SOCK_DOWNLOAD_INVALID_URL 28
#define ERR_SOCK_DOWNLOAD_SELECT_FAILED 29
#define ERR_SOCK_DOWNLOAD_FAILED 30
// The following errors are game errors. // The following errors are game errors.
#define ERR_NET_VERSION_NOT_SUPPORTED 101 #define ERR_NET_VERSION_NOT_SUPPORTED 101
#define ERR_NET_SERVER_MAINTENANCE 102 #define ERR_NET_SERVER_MAINTENANCE 102