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:
lotodore
2007-03-20 14:05:16 +00:00
parent 7a704c2995
commit 62e72617ba
9 changed files with 172 additions and 100 deletions
@@ -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
+110 -4
View File
@@ -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;
+1
View File
@@ -180,6 +180,7 @@ public slots:
void paintStartSplash();
void networkError(int errorID, int osErrorID);
private:
+31 -8
View File
@@ -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;
}
+2 -2
View File
@@ -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 &
+12 -2
View File
@@ -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
View File
@@ -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();
}
+1
View File
@@ -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();