From 62e72617ba5eafe98094a3a14e1b5816e8e36987 Mon Sep 17 00:00:00 2001 From: lotodore Date: Tue, 20 Mar 2007 14:05:16 +0000 Subject: [PATCH] When creating a network game, a client is also started. Network errors are handled globally. Fixed last network thread issue by using a notification queue, should work fine now. --- .../connecttoserverdialogimpl.cpp | 82 ------------- .../connecttoserverdialogimpl.h | 1 - src/gui/qt/mainwindow/mainwindowimpl.cpp | 114 +++++++++++++++++- src/gui/qt/mainwindow/mainwindowimpl.h | 1 + src/net/common/serverrecvthread.cpp | 39 ++++-- src/net/common/serverthread.cpp | 4 +- src/net/serverrecvthread.h | 14 ++- src/session.cpp | 16 ++- src/session.h | 1 + 9 files changed, 172 insertions(+), 100 deletions(-) diff --git a/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.cpp b/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.cpp index 2af08169..21a51801 100644 --- a/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.cpp +++ b/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.cpp @@ -50,85 +50,3 @@ void connectToServerDialogImpl::refresh(int actionID) { QTimer::singleShot(1000, this, SLOT(accept())); } -void connectToServerDialogImpl::error(int errorID, int osErrorID) { - - switch (errorID) { - - case ERR_SOCK_SERVERADDR_NOT_SET: - {QMessageBox::warning(this, tr("Network Error"), - tr("Server address was not set."), - QMessageBox::Close); } - break; - case ERR_SOCK_INVALID_PORT: - { QMessageBox::warning(this, tr("Network Error"), - tr("An invalid port was set (ports 0-1023 are not allowed)."), - QMessageBox::Close); } - break; - case ERR_SOCK_CREATION_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Could not create a socket for TCP communication."), - QMessageBox::Close); } - break; - case ERR_SOCK_SET_ADDR_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Could not set the IP address."), - QMessageBox::Close); } - break; - case ERR_SOCK_SET_PORT_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Could not set the port for this type of address."), - QMessageBox::Close); } - break; - case ERR_SOCK_RESOLVE_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("The server name could not be resolved."), - QMessageBox::Close); } - break; - case ERR_SOCK_BIND_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Bind failed - please choose a different port."), - QMessageBox::Close); } - break; - case ERR_SOCK_LISTEN_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Internal network error: \"listen\" failed."), - QMessageBox::Close); } - break; - case ERR_SOCK_ACCEPT_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Server execution was terminated."), - QMessageBox::Close); } - break; - case ERR_SOCK_CONNECT_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Could not connect to the server."), - QMessageBox::Close); } - break; - case ERR_SOCK_SELECT_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Internal network error: \"select\" failed."), - QMessageBox::Close); } - break; - case ERR_SOCK_RECV_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Internal network error: \"recv\" failed."), - QMessageBox::Close); } - break; - case ERR_SOCK_SEND_FAILED: - { QMessageBox::warning(this, tr("Network Error"), - tr("Internal network error: \"send\" failed."), - QMessageBox::Close); } - break; - case ERR_SOCK_CONN_RESET: - { QMessageBox::warning(this, tr("Network Error"), - tr("Connection was closed by server."), - QMessageBox::Close); } - break; - default: { QMessageBox::warning(this, tr("Network Error"), - tr("DEFAULT ERROR"), - QMessageBox::Close); } - } - - this->reject(); - -} diff --git a/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.h b/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.h index df72a425..5ba3c0e3 100644 --- a/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.h +++ b/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.h @@ -36,7 +36,6 @@ public: public slots: void refresh(int actionID); - void error(int errorID, int osErrorID); }; #endif diff --git a/src/gui/qt/mainwindow/mainwindowimpl.cpp b/src/gui/qt/mainwindow/mainwindowimpl.cpp index 2394eab7..1b672b2a 100755 --- a/src/gui/qt/mainwindow/mainwindowimpl.cpp +++ b/src/gui/qt/mainwindow/mainwindowimpl.cpp @@ -40,6 +40,8 @@ #include "log.h" #include "configfile.h" +#include + #define FORMATLEFT(X) "

(X)" #define FORMATRIGHT(X) "(X)

" @@ -484,8 +486,8 @@ mainWindowImpl::mainWindowImpl(QMainWindow *parent) //Nachrichten Thread-Save connect(this, SIGNAL(SignalNetClientConnect(int)), myConnectToServerDialog, SLOT(refresh(int))); connect(this, SIGNAL(SignalNetClientGameInfo(int)), myWaitingForServerGameDialog, SLOT(refresh(int))); - // TODO Fix, errors MUST be global, not within one dialog. - connect(this, SIGNAL(SignalNetClientError(int, int)), myConnectToServerDialog, SLOT(error(int, int))); + // Errors are handled globally, not within one dialog. + connect(this, SIGNAL(SignalNetClientError(int, int)), this, SLOT(networkError(int, int))); // textBrowser_Log->append(QString::number(this->pos().x(),10)+" "+QString::number(this->pos().y(),10)); // textBrowser_Log->append(QString::number(this->x(),10)+" "+QString::number(this->y(),10)); @@ -507,7 +509,10 @@ void mainWindowImpl::callNewGameDialog() { if (v->result() == QDialog::Accepted ) { - + // Start new local game - terminate existing network game. + mySession->terminateNetworkClient(); + mySession->terminateNetworkServer(); + if(actualGame) { mySession->deleteGame(); actualGame = 0; @@ -543,7 +548,13 @@ void mainWindowImpl::callNewGameDialog() { } // sonst mit gespeicherten Werten starten else { - + + // COPY AND PASTE WARNING, see above!!! + // TODO + // Start new local game - terminate existing network game. + mySession->terminateNetworkClient(); + mySession->terminateNetworkServer(); + if(actualGame) { mySession->deleteGame(); actualGame = 0; @@ -593,14 +604,21 @@ void mainWindowImpl::callCreateNetworkGameDialog() { // if (myCreateNetworkGameDialog->result() == QDialog::Accepted ) { + mySession->terminateNetworkClient(); mySession->terminateNetworkServer(); + mySession->startNetworkServer(); + mySession->startNetworkClientForLocalServer(); myStartNetworkGameDialog->exec(); if (myStartNetworkGameDialog->result() == QDialog::Accepted ) { mySession->initiateNetworkServerGame(); } + else { + mySession->terminateNetworkClient(); + mySession->terminateNetworkServer(); + } } } @@ -612,6 +630,7 @@ void mainWindowImpl::callJoinNetworkGameDialog() { if (myJoinNetworkGameDialog->result() == QDialog::Accepted ) { mySession->terminateNetworkClient(); + mySession->terminateNetworkServer(); // Maybe use QUrl::toPunycode. mySession->startNetworkClient( @@ -629,6 +648,10 @@ void mainWindowImpl::callJoinNetworkGameDialog() { } else { myWaitingForServerGameDialog->exec(); + + if (myWaitingForServerGameDialog->result() == QDialog::Rejected) { + mySession->terminateNetworkClient(); + } } } @@ -2001,6 +2024,89 @@ void mainWindowImpl::paintStartSplash() { mySplash->show(); } +void mainWindowImpl::networkError(int errorID, int osErrorID) { + + switch (errorID) { + + case ERR_SOCK_SERVERADDR_NOT_SET: + {QMessageBox::warning(this, tr("Network Error"), + tr("Server address was not set."), + QMessageBox::Close); } + break; + case ERR_SOCK_INVALID_PORT: + { QMessageBox::warning(this, tr("Network Error"), + tr("An invalid port was set (ports 0-1023 are not allowed)."), + QMessageBox::Close); } + break; + case ERR_SOCK_CREATION_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Could not create a socket for TCP communication."), + QMessageBox::Close); } + break; + case ERR_SOCK_SET_ADDR_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Could not set the IP address."), + QMessageBox::Close); } + break; + case ERR_SOCK_SET_PORT_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Could not set the port for this type of address."), + QMessageBox::Close); } + break; + case ERR_SOCK_RESOLVE_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("The server name could not be resolved."), + QMessageBox::Close); } + break; + case ERR_SOCK_BIND_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Bind failed - please choose a different port."), + QMessageBox::Close); } + break; + case ERR_SOCK_LISTEN_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Internal network error: \"listen\" failed."), + QMessageBox::Close); } + break; + case ERR_SOCK_ACCEPT_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Server execution was terminated."), + QMessageBox::Close); } + break; + case ERR_SOCK_CONNECT_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Could not connect to the server."), + QMessageBox::Close); } + break; + case ERR_SOCK_SELECT_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Internal network error: \"select\" failed."), + QMessageBox::Close); } + break; + case ERR_SOCK_RECV_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Internal network error: \"recv\" failed."), + QMessageBox::Close); } + break; + case ERR_SOCK_SEND_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Internal network error: \"send\" failed."), + QMessageBox::Close); } + break; + case ERR_SOCK_CONN_RESET: + { QMessageBox::warning(this, tr("Network Error"), + tr("Connection was closed by server."), + QMessageBox::Close); } + break; + default: { QMessageBox::warning(this, tr("Network Error"), + tr("DEFAULT ERROR"), + QMessageBox::Close); } + } + // close dialogs + myConnectToServerDialog->reject(); + myWaitingForServerGameDialog->reject(); +} + void mainWindowImpl::keyPressEvent ( QKeyEvent * event ) { // cout << event->key() << endl; diff --git a/src/gui/qt/mainwindow/mainwindowimpl.h b/src/gui/qt/mainwindow/mainwindowimpl.h index 28a45ca8..7169fbb2 100755 --- a/src/gui/qt/mainwindow/mainwindowimpl.h +++ b/src/gui/qt/mainwindow/mainwindowimpl.h @@ -180,6 +180,7 @@ public slots: void paintStartSplash(); + void networkError(int errorID, int osErrorID); private: diff --git a/src/net/common/serverrecvthread.cpp b/src/net/common/serverrecvthread.cpp index 2f1fae18..41c63deb 100644 --- a/src/net/common/serverrecvthread.cpp +++ b/src/net/common/serverrecvthread.cpp @@ -54,13 +54,6 @@ ServerRecvThread::~ServerRecvThread() CleanupSessionMap(); } -void -ServerRecvThread::StartGame() -{ - // TODO: not thread safe. use flag or something. - SetState(SERVER_START_GAME_STATE::Instance()); -} - void ServerRecvThread::SendToAllPlayers(boost::shared_ptr packet) { @@ -85,6 +78,13 @@ ServerRecvThread::AddConnection(boost::shared_ptr data) m_connectQueue.push_back(data); } +void +ServerRecvThread::AddNotification(unsigned notification) +{ + boost::mutex::scoped_lock lock(m_notificationQueueMutex); + m_notificationQueue.push_back(notification); +} + void ServerRecvThread::Main() { @@ -96,6 +96,7 @@ ServerRecvThread::Main() while (!ShouldTerminate()) { { + // Handle one incoming connection at a time. boost::shared_ptr tmpData; { boost::mutex::scoped_lock lock(m_connectQueueMutex); @@ -108,7 +109,10 @@ ServerRecvThread::Main() if (tmpData.get()) GetState().HandleNewConnection(*this, tmpData); } + // Process current state. GetState().Process(*this); + // Process thread-safe notifications. + NotificationLoop(); } } catch (const NetException &) { @@ -121,6 +125,25 @@ ServerRecvThread::Main() CleanupSessionMap(); } +void +ServerRecvThread::NotificationLoop() +{ + boost::mutex::scoped_lock lock(m_notificationQueueMutex); + // Process all notifications. + while (!m_notificationQueue.empty()) + { + unsigned notification = m_notificationQueue.front(); + m_notificationQueue.pop_front(); + + switch(notification) + { + case NOTIFY_GAME_START: + SetState(SERVER_START_GAME_STATE::Instance()); + break; + } + } +} + SOCKET ServerRecvThread::Select() { @@ -139,7 +162,7 @@ ServerRecvThread::Select() { SOCKET tmpSock = i->first; FD_SET(tmpSock, &rdset); - if (tmpSock > maxSock) + if (tmpSock > maxSock || maxSock == INVALID_SOCKET) maxSock = tmpSock; ++i; } diff --git a/src/net/common/serverthread.cpp b/src/net/common/serverthread.cpp index 7e479818..f8859e11 100644 --- a/src/net/common/serverthread.cpp +++ b/src/net/common/serverthread.cpp @@ -59,8 +59,8 @@ ServerThread::StartGame() if (!IsRunning()) return; // TODO: throw exception - // TODO: possible race condition - GetRecvThread().StartGame(); + // Thread-safe notification. + GetRecvThread().AddNotification(NOTIFY_GAME_START); } ServerCallback & diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h index b3dce6c4..cb848709 100644 --- a/src/net/serverrecvthread.h +++ b/src/net/serverrecvthread.h @@ -31,6 +31,9 @@ #define RECEIVER_THREAD_TERMINATE_TIMEOUT 200 +// Notifications +#define NOTIFY_GAME_START 1 + class ServerRecvState; class SenderThread; class ReceiverHelper; @@ -43,17 +46,21 @@ public: ServerRecvThread(); virtual ~ServerRecvThread(); - void StartGame(); void SendToAllPlayers(boost::shared_ptr packet); void AddConnection(boost::shared_ptr data); + void AddNotification(unsigned notification); protected: + typedef std::deque > ConnectQueue; typedef std::map > SocketSessionMap; + typedef std::deque NotificationQueue; // Main function of the thread. virtual void Main(); + void NotificationLoop(); + SOCKET Select(); void CleanupConnectQueue(); @@ -72,10 +79,13 @@ protected: private: - std::deque > m_connectQueue; + ConnectQueue m_connectQueue; mutable boost::mutex m_connectQueueMutex; ServerRecvState *m_curState; + NotificationQueue m_notificationQueue; + mutable boost::mutex m_notificationQueueMutex; + SocketSessionMap m_sessionMap; mutable boost::mutex m_sessionMapMutex; diff --git a/src/session.cpp b/src/session.cpp index 32179238..34678357 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -39,6 +39,7 @@ Session::Session(GuiInterface *g) Session::~Session() { terminateNetworkClient(); + terminateNetworkServer(); deleteGame(); delete myConfig; } @@ -67,6 +68,19 @@ void Session::startNetworkClient(const string &serverAddress, unsigned serverPor myNetClient->Run(); } +void Session::startNetworkClientForLocalServer() +{ + if (myNetClient || !myGui) + return; // TODO: throw exception + myNetClient = new ClientThread(*myGui); + myNetClient->Init( + "localhost", + myConfig->readConfigInt("ServerPort"), + myConfig->readConfigInt("ServerUseIpv6") == 1, + myConfig->readConfigString("ServerPassword")); + myNetClient->Run(); +} + void Session::terminateNetworkClient() { if (!myNetClient) @@ -89,7 +103,7 @@ void Session::startNetworkServer() myNetServer->Init( myConfig->readConfigInt("ServerPort"), myConfig->readConfigInt("ServerUseIpv6") == 1, - ""); // TODO: use pwd + myConfig->readConfigString("ServerPassword")); myNetServer->Run(); } diff --git a/src/session.h b/src/session.h index b9bcb23b..cce53793 100755 --- a/src/session.h +++ b/src/session.h @@ -38,6 +38,7 @@ public: void deleteGame(); void startNetworkClient(const std::string &serverAddress, unsigned serverPort, bool ipv6, const std::string &pwd); + void startNetworkClientForLocalServer(); void terminateNetworkClient(); void startNetworkServer();