diff --git a/docs/net_protocol.txt b/docs/net_protocol.txt
index e2bfa138..2060f3e3 100644
--- a/docs/net_protocol.txt
+++ b/docs/net_protocol.txt
@@ -385,6 +385,7 @@ Error Reason:
0x0006 - Join Game - Invalid Player Name
0xFF01 - General Error - Invalid packet
0xFF02 - General Error - Invalid state
+ 0xFF03 - General Error - Kicked from the server
0xFFFF - Other reason
diff --git a/src/gui/qt/mainwindow/log/log.cpp b/src/gui/qt/mainwindow/log/log.cpp
index a05fea17..1e67c840 100644
--- a/src/gui/qt/mainwindow/log/log.cpp
+++ b/src/gui/qt/mainwindow/log/log.cpp
@@ -444,8 +444,6 @@ void Log::logFlipHoleCardsMsg(QString playerName, int card1, int card2, int card
void Log::logPlayerLeftMsg(QString playerName) {
- HandInterface *currentHand = myW->getSession().getCurrentGame()->getCurrentHand();
-
myW->textBrowser_Log->append( ""+playerName+" has left the game!");
if(myConfig->readConfigInt("LogOnOff")) {
diff --git a/src/gui/qt/mainwindow/mainwindowimpl.cpp b/src/gui/qt/mainwindow/mainwindowimpl.cpp
index d4696ee1..38594f1a 100755
--- a/src/gui/qt/mainwindow/mainwindowimpl.cpp
+++ b/src/gui/qt/mainwindow/mainwindowimpl.cpp
@@ -720,6 +720,7 @@ void mainWindowImpl::callCreateNetworkGameDialog() {
// gameData.guiSpeed = myCreateNetworkGameDialog->spinBox_gameSpeed->value();
gameData.guiSpeed = 4;
+ myStartNetworkGameDialog->setSession(&myServerGuiInterface->getSession());
myStartNetworkGameDialog->treeWidget->clear();
myServerGuiInterface->getSession().startNetworkServer(gameData);
@@ -2482,6 +2483,11 @@ void mainWindowImpl::networkError(int errorID, int osErrorID) {
tr("The server referred to an unknown player. Aborting."),
QMessageBox::Close); }
break;
+ case ERR_NET_PLAYER_KICKED:
+ { QMessageBox::warning(this, tr("Network Error"),
+ tr("You were kicked from the server."),
+ QMessageBox::Close); }
+ break;
default: { QMessageBox::warning(this, tr("Network Error"),
tr("An internal error occured."),
QMessageBox::Close); }
diff --git a/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp b/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp
index 4d671f71..53eeb495 100644
--- a/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp
+++ b/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp
@@ -21,12 +21,10 @@
#include "session.h"
#include "configfile.h"
-startNetworkGameDialogImpl::startNetworkGameDialogImpl(QWidget *parent, ConfigFile *config, Session *session)
- : QDialog(parent), myConfig(config), mySession(session)
+startNetworkGameDialogImpl::startNetworkGameDialogImpl(QWidget *parent, ConfigFile *config)
+ : QDialog(parent), myConfig(config)
{
- assert(mySession);
-
- setupUi(this);
+ setupUi(this);
connect( pushButton_cancel, SIGNAL( clicked() ), this, SLOT( cancel() ) );
connect( pushButton_startGame, SIGNAL( clicked() ), this, SLOT( startGame() ) );
@@ -81,7 +79,8 @@ void startNetworkGameDialogImpl::kickPlayer() {
QMessageBox::Close); }
}
else {
- // kickplayerFunktion(playerName.toStdString());
+ assert(mySession);
+ mySession->kickPlayer(playerName.toUtf8().constData());
}
}
pushButton_Kick->setEnabled(FALSE);
@@ -94,6 +93,11 @@ void startNetworkGameDialogImpl::checkPlayerQuantity() {
}
+void startNetworkGameDialogImpl::setSession(Session *session)
+{
+ mySession = session;
+}
+
void startNetworkGameDialogImpl::keyPressEvent ( QKeyEvent * event ) {
diff --git a/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.h b/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.h
index a93516e5..956ba630 100644
--- a/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.h
+++ b/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.h
@@ -31,7 +31,7 @@ class ConfigFile;
class startNetworkGameDialogImpl: public QDialog, public Ui::startNetworkGameDialog {
Q_OBJECT
public:
- startNetworkGameDialogImpl(QWidget *parent = 0, ConfigFile *config = 0, Session *session = 0);
+ startNetworkGameDialogImpl(QWidget *parent = 0, ConfigFile *config = 0);
public slots:
@@ -43,6 +43,8 @@ public slots:
void kickPlayer();
void checkPlayerQuantity();
+ void setSession(Session *session);
+
void keyPressEvent ( QKeyEvent*);
void setMaxPlayerNumber ( int theValue ) { maxPlayerNumber = theValue; label_maxPlayerNumber->setText(QString::number(theValue,10)); }
diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp
index ac4d7551..85a94637 100644
--- a/src/net/common/clientstate.cpp
+++ b/src/net/common/clientstate.cpp
@@ -379,7 +379,15 @@ AbstractClientStateReceiving::Process(ClientThread &client)
if (tmpPacket.get())
{
- if (tmpPacket->ToNetPacketChatText())
+ if (tmpPacket->ToNetPacketError())
+ {
+ // Server reported an error.
+ NetPacketError::Data errorData;
+ tmpPacket->ToNetPacketError()->GetData(errorData);
+ // Show the error.
+ throw ClientException(errorData.errorCode, 0);
+ }
+ else if (tmpPacket->ToNetPacketChatText())
{
// Chat message - display it in the GUI.
NetPacketChatText::Data chatData;
@@ -464,14 +472,6 @@ ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr<
client.SetState(ClientStateWaitGame::Instance());
retVal = MSG_SOCK_SESSION_DONE;
}
- else if (packet->ToNetPacketError())
- {
- // Server reported an error.
- NetPacketError::Data errorData;
- packet->ToNetPacketError()->GetData(errorData);
- // Show the error.
- throw ClientException(errorData.errorCode, 0);
- }
return retVal;
}
diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp
index 1b26b4dd..b1b83c94 100644
--- a/src/net/common/netpacket.cpp
+++ b/src/net/common/netpacket.cpp
@@ -59,6 +59,7 @@ using namespace std;
#define NET_ERR_JOIN_GAME_INVALID_PLAYER_NAME 0x0006
#define NET_ERR_GENERAL_INVALID_PACKET 0xFF01
#define NET_ERR_GENERAL_INVALID_STATE 0xFF02
+#define NET_ERR_GENERAL_PLAYER_KICKED 0xFF03
#define NET_ERR_OTHER 0xFFFF
#ifdef _MSC_VER
@@ -2111,6 +2112,9 @@ NetPacketError::SetData(const NetPacketError::Data &inData)
case ERR_SOCK_INVALID_STATE :
tmpData->reason = htons(NET_ERR_GENERAL_INVALID_STATE);
break;
+ case ERR_NET_PLAYER_KICKED :
+ tmpData->reason = htons(NET_ERR_GENERAL_PLAYER_KICKED);
+ break;
default :
tmpData->reason = htons(NET_ERR_OTHER);
break;
@@ -2151,6 +2155,9 @@ NetPacketError::GetData(NetPacketError::Data &outData) const
case NET_ERR_GENERAL_INVALID_STATE :
outData.errorCode = ERR_SOCK_INVALID_STATE;
break;
+ case NET_ERR_GENERAL_PLAYER_KICKED :
+ outData.errorCode = ERR_NET_PLAYER_KICKED;
+ break;
default :
outData.errorCode = ERR_SOCK_INTERNAL;
break;
diff --git a/src/net/common/serverrecvthread.cpp b/src/net/common/serverrecvthread.cpp
index c9f99a38..ae9f5cbb 100644
--- a/src/net/common/serverrecvthread.cpp
+++ b/src/net/common/serverrecvthread.cpp
@@ -82,10 +82,10 @@ ServerRecvThread::AddConnection(boost::shared_ptr data)
}
void
-ServerRecvThread::AddNotification(unsigned message, unsigned param1, unsigned param2)
+ServerRecvThread::AddNotification(unsigned message, const string ¶m)
{
boost::mutex::scoped_lock lock(m_notificationQueueMutex);
- m_notificationQueue.push_back(Notification(message, param1, param2));
+ m_notificationQueue.push_back(Notification(message, param));
}
void
@@ -145,6 +145,9 @@ ServerRecvThread::NotificationLoop()
case NOTIFY_GAME_START:
InternalStartGame();
break;
+ case NOTIFY_KICK_PLAYER:
+ InternalKickPlayer(notification.param);
+ break;
}
}
}
@@ -287,13 +290,24 @@ ServerRecvThread::InternalStartGame()
m_game.reset(new Game(&gui, factory, playerData, GetGameData(), GetStartData(), m_curGameId++));
}
+void
+ServerRecvThread::InternalKickPlayer(const string playerName)
+{
+ if (!playerName.empty())
+ {
+ SessionWrapper tmpSession = GetSession(playerName);
+
+ SessionError(tmpSession, ERR_NET_PLAYER_KICKED);
+ }
+}
+
SessionWrapper
-ServerRecvThread::GetSession(SOCKET sock)
+ServerRecvThread::GetSession(SOCKET sock) const
{
SessionWrapper tmpSession;
boost::mutex::scoped_lock lock(m_sessionMapMutex);
- SocketSessionMap::iterator pos = m_sessionMap.find(sock);
+ SocketSessionMap::const_iterator pos = m_sessionMap.find(sock);
if (pos != m_sessionMap.end())
{
tmpSession = pos->second;
@@ -301,6 +315,34 @@ ServerRecvThread::GetSession(SOCKET sock)
return tmpSession;
}
+SessionWrapper
+ServerRecvThread::GetSession(const string playerName) const
+{
+ SessionWrapper tmpSession;
+ boost::mutex::scoped_lock lock(m_sessionMapMutex);
+
+ SocketSessionMap::const_iterator session_i = m_sessionMap.begin();
+ SocketSessionMap::const_iterator session_end = m_sessionMap.end();
+
+ while (session_i != session_end)
+ {
+ // Check all players which are fully connected.
+ if (session_i->second.sessionData->GetState() == SessionData::Established)
+ {
+ boost::shared_ptr tmpPlayer(session_i->second.playerData);
+ assert(tmpPlayer.get());
+ if (tmpPlayer->GetName() == playerName)
+ {
+ tmpSession = session_i->second;
+ break;
+ }
+ }
+
+ ++session_i;
+ }
+ return tmpSession;
+}
+
void
ServerRecvThread::AddSession(boost::shared_ptr sessionData)
{
@@ -415,25 +457,15 @@ ServerRecvThread::GetCurNumberOfPlayers() const
}
bool
-ServerRecvThread::IsPlayerConnected(const std::string &playerName) const
+ServerRecvThread::IsPlayerConnected(const string &playerName) const
{
bool retVal = false;
- PlayerDataList playerList = GetPlayerDataList();
- PlayerDataList::const_iterator player_i = playerList.begin();
- PlayerDataList::const_iterator player_end = playerList.end();
+ SessionWrapper tmpSession = GetSession(playerName);
- // Check by name - the name is unique.
- while (player_i != player_end)
- {
- if ((*player_i)->GetName() == playerName)
- {
- retVal = true;
- break;
- }
+ if (tmpSession.sessionData.get() && tmpSession.playerData.get())
+ retVal = true;
- ++player_i;
- }
return retVal;
}
@@ -612,7 +644,7 @@ ServerRecvThread::SetStartData(const StartData &startData)
}
bool
-ServerRecvThread::CheckPassword(const std::string &password) const
+ServerRecvThread::CheckPassword(const string &password) const
{
return (password == m_password);
}
diff --git a/src/net/common/serverthread.cpp b/src/net/common/serverthread.cpp
index d20a50b7..e150a2ac 100644
--- a/src/net/common/serverthread.cpp
+++ b/src/net/common/serverthread.cpp
@@ -28,6 +28,7 @@
#define ACCEPT_TIMEOUT_MSEC 50
#define NET_SERVER_LISTEN_BACKLOG 5
+using namespace std;
ServerThread::ServerThread(GuiInterface &gui, ConfigFile *config)
: m_gui(gui)
@@ -63,7 +64,17 @@ ServerThread::StartGame()
return; // TODO: throw exception
// Thread-safe notification.
- GetRecvThread().AddNotification(NOTIFY_GAME_START, 0, 0);
+ GetRecvThread().AddNotification(NOTIFY_GAME_START, "");
+}
+
+void
+ServerThread::KickPlayer(const string &playerName)
+{
+ if (!IsRunning())
+ return; // TODO: throw exception
+
+ // Thread-safe notification.
+ GetRecvThread().AddNotification(NOTIFY_KICK_PLAYER, playerName);
}
ServerCallback &
diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h
index 6d34cc6e..90cf52ff 100644
--- a/src/net/serverrecvthread.h
+++ b/src/net/serverrecvthread.h
@@ -38,6 +38,7 @@
// Notifications
#define NOTIFY_GAME_START 1
+#define NOTIFY_KICK_PLAYER 2
class ServerRecvState;
class SenderThread;
@@ -66,7 +67,7 @@ public:
void Init(const std::string &pwd, const GameData &gameData);
void AddConnection(boost::shared_ptr data);
- void AddNotification(unsigned message, unsigned param1, unsigned param2);
+ void AddNotification(unsigned message, const std::string ¶m);
ServerCallback &GetCallback();
@@ -78,11 +79,10 @@ protected:
struct Notification
{
- Notification(unsigned m, unsigned p1, unsigned p2)
- : message(m), param1(p1), param2(p2) {}
+ Notification(unsigned m, std::string p)
+ : message(m), param(p) {}
unsigned message;
- unsigned param1;
- unsigned param2;
+ std::string param;
};
typedef std::deque > ConnectQueue;
@@ -103,8 +103,10 @@ protected:
void CleanupSessionMap();
void InternalStartGame();
+ void InternalKickPlayer(const std::string playerName);
- SessionWrapper GetSession(SOCKET sock);
+ SessionWrapper GetSession(SOCKET sock) const;
+ SessionWrapper GetSession(const std::string playerName) const;
void AddSession(boost::shared_ptr sessionData); // new Sessions have no player data
void SessionError(SessionWrapper session, int errorCode);
void RejectNewConnection(boost::shared_ptr connData);
diff --git a/src/net/serverthread.h b/src/net/serverthread.h
index 7f556bec..3a9ec85c 100644
--- a/src/net/serverthread.h
+++ b/src/net/serverthread.h
@@ -44,6 +44,7 @@ public:
void Init(unsigned serverPort, bool ipv6, bool sctp, const std::string &pwd,
const GameData &gameData);
void StartGame();
+ void KickPlayer(const std::string &playerName);
ServerCallback &GetCallback();
GuiInterface &GetGui();
diff --git a/src/net/socket_msg.h b/src/net/socket_msg.h
index 07ad017d..53a4c8c9 100644
--- a/src/net/socket_msg.h
+++ b/src/net/socket_msg.h
@@ -53,6 +53,7 @@
#define ERR_NET_INVALID_CHAT_TEXT 110
#define ERR_NET_UNKNOWN_PLAYER_ID 111
#define ERR_NET_INVALID_ROUND 112
+#define ERR_NET_PLAYER_KICKED 113
// This is an internal message which is not reported.
#define MSG_SOCK_INTERNAL_PENDING 0
diff --git a/src/session.cpp b/src/session.cpp
index 12010120..d5ab10f9 100755
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -203,12 +203,23 @@ void Session::sendClientPlayerAction()
myNetClient->SendPlayerAction();
}
-void Session::sendChatMessage(const std::string &message) {
+void Session::sendChatMessage(const std::string &message)
+{
if (!myNetClient)
return; // only act if client is running.
myNetClient->SendChatMessage(message);
}
+void Session::kickPlayer(const std::string &playerName)
+{
+ if (!myNetServer)
+ {
+ assert(false);
+ return;
+ }
+ myNetServer->KickPlayer(playerName);
+}
+
bool Session::isNetworkClientRunning() const
{
// This, and every place which calls this, is a HACK.
diff --git a/src/session.h b/src/session.h
index 86617cfe..21fe595b 100755
--- a/src/session.h
+++ b/src/session.h
@@ -59,6 +59,7 @@ public:
int getCurrentGameID() const { return currentGameID; }
void sendChatMessage(const std::string &message);
+ void kickPlayer(const std::string &playerName);
bool isNetworkClientRunning() const; // TODO hack