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.
This commit is contained in:
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ public:
|
||||
public slots:
|
||||
|
||||
void refresh(int actionID);
|
||||
void error(int errorID, int osErrorID);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include "log.h"
|
||||
#include "configfile.h"
|
||||
|
||||
#include <net/socket_msg.h>
|
||||
|
||||
#define FORMATLEFT(X) "<p align='center'>(X)"
|
||||
#define FORMATRIGHT(X) "(X)</p>"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -180,6 +180,7 @@ public slots:
|
||||
|
||||
void paintStartSplash();
|
||||
|
||||
void networkError(int errorID, int osErrorID);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -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<NetPacket> packet)
|
||||
{
|
||||
@@ -85,6 +78,13 @@ ServerRecvThread::AddConnection(boost::shared_ptr<ConnectData> 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<ConnectData> 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;
|
||||
}
|
||||
|
||||
@@ -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 &
|
||||
|
||||
@@ -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<NetPacket> packet);
|
||||
void AddConnection(boost::shared_ptr<ConnectData> data);
|
||||
void AddNotification(unsigned notification);
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::deque<boost::shared_ptr<ConnectData> > ConnectQueue;
|
||||
typedef std::map<SOCKET, boost::shared_ptr<SessionData> > SocketSessionMap;
|
||||
typedef std::deque<unsigned> NotificationQueue;
|
||||
|
||||
// Main function of the thread.
|
||||
virtual void Main();
|
||||
|
||||
void NotificationLoop();
|
||||
|
||||
SOCKET Select();
|
||||
|
||||
void CleanupConnectQueue();
|
||||
@@ -72,10 +79,13 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
std::deque<boost::shared_ptr<ConnectData> > 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;
|
||||
|
||||
|
||||
+15
-1
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user