summaryrefslogtreecommitdiffstats
path: root/libkdegames/kgame/kmessageclient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libkdegames/kgame/kmessageclient.cpp')
-rw-r--r--libkdegames/kgame/kmessageclient.cpp373
1 files changed, 373 insertions, 0 deletions
diff --git a/libkdegames/kgame/kmessageclient.cpp b/libkdegames/kgame/kmessageclient.cpp
new file mode 100644
index 00000000..ed9cc966
--- /dev/null
+++ b/libkdegames/kgame/kmessageclient.cpp
@@ -0,0 +1,373 @@
+/*
+ This file is part of the KDE games library
+ Copyright (C) 2001 Burkhard Lehner (Burkhard.Lehner@gmx.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <stdio.h>
+
+#include <qbuffer.h>
+#include <qtimer.h>
+
+#include "kmessageio.h"
+#include "kmessageserver.h"
+
+#include "kmessageclient.h"
+
+class KMessageClientPrivate
+{
+public:
+ KMessageClientPrivate ()
+ : adminID (0), connection (0)
+ {}
+
+ ~KMessageClientPrivate ()
+ {
+ delete connection;
+ }
+
+ Q_UINT32 adminID;
+ QValueList <Q_UINT32> clientList;
+ KMessageIO *connection;
+
+ bool isLocked;
+ QValueList <QByteArray> delayedMessages;
+};
+
+KMessageClient::KMessageClient (QObject *parent, const char *name)
+ : QObject (parent, name)
+{
+ d = new KMessageClientPrivate ();
+ d->isLocked = false;
+}
+
+KMessageClient::~KMessageClient ()
+{
+ d->delayedMessages.clear();
+ delete d;
+}
+
+// -- setServer stuff
+
+void KMessageClient::setServer (const QString &host, Q_UINT16 port)
+{
+ setServer (new KMessageSocket (host, port));
+}
+
+void KMessageClient::setServer (KMessageServer *server)
+{
+ KMessageDirect *serverIO = new KMessageDirect ();
+ setServer (new KMessageDirect (serverIO));
+ server->addClient (serverIO);
+}
+
+void KMessageClient::setServer (KMessageIO *connection)
+{
+ if (d->connection)
+ {
+ delete d->connection;
+ kdDebug (11001) << k_funcinfo << ": We are changing the server!" << endl;
+ }
+
+ d->connection = connection;
+ if (connection )
+ {
+ connect (connection, SIGNAL (received(const QByteArray &)),
+ this, SLOT (processIncomingMessage(const QByteArray &)));
+ connect (connection, SIGNAL (connectionBroken()),
+ this, SLOT (removeBrokenConnection ()));
+ }
+}
+
+// -- id stuff
+
+Q_UINT32 KMessageClient::id () const
+{
+ return (d->connection) ? d->connection->id () : 0;
+}
+
+bool KMessageClient::isAdmin () const
+{
+ return id() != 0 && id() == adminId();
+}
+
+Q_UINT32 KMessageClient::adminId () const
+{
+ return d->adminID;
+}
+
+const QValueList <Q_UINT32> &KMessageClient::clientList() const
+{
+ return d->clientList;
+}
+
+bool KMessageClient::isConnected () const
+{
+ return d->connection && d->connection->isConnected();
+}
+
+bool KMessageClient::isNetwork () const
+{
+ return isConnected() ? d->connection->isNetwork() : false;
+}
+
+Q_UINT16 KMessageClient::peerPort () const
+{
+ return d->connection ? d->connection->peerPort() : 0;
+}
+
+QString KMessageClient::peerName () const
+{
+ return d->connection ? d->connection->peerName() : QString::fromLatin1("localhost");
+}
+
+// --------------------- Sending messages
+
+void KMessageClient::sendServerMessage (const QByteArray &msg)
+{
+ if (!d->connection)
+ {
+ kdWarning (11001) << k_funcinfo << ": We have no connection yet!" << endl;
+ return;
+ }
+ d->connection->send (msg);
+}
+
+void KMessageClient::sendBroadcast (const QByteArray &msg)
+{
+ QByteArray sendBuffer;
+ QBuffer buffer (sendBuffer);
+ buffer.open (IO_WriteOnly);
+ QDataStream stream (&buffer);
+
+ stream << static_cast<Q_UINT32> ( KMessageServer::REQ_BROADCAST );
+ buffer.QIODevice::writeBlock (msg);
+ sendServerMessage (sendBuffer);
+}
+
+void KMessageClient::sendForward (const QByteArray &msg, const QValueList <Q_UINT32> &clients)
+{
+ QByteArray sendBuffer;
+ QBuffer buffer (sendBuffer);
+ buffer.open (IO_WriteOnly);
+ QDataStream stream (&buffer);
+
+ stream << static_cast<Q_UINT32>( KMessageServer::REQ_FORWARD ) << clients;
+ buffer.QIODevice::writeBlock (msg);
+ sendServerMessage (sendBuffer);
+}
+
+void KMessageClient::sendForward (const QByteArray &msg, Q_UINT32 client)
+{
+ sendForward (msg, QValueList <Q_UINT32> () << client);
+}
+
+
+// --------------------- Receiving and processing messages
+
+void KMessageClient::processIncomingMessage (const QByteArray &msg)
+{
+ if (d->isLocked)
+ {
+ d->delayedMessages.append(msg);
+ return;
+ }
+ if (d->delayedMessages.count() > 0)
+ {
+ d->delayedMessages.append (msg);
+ QByteArray first = d->delayedMessages.front();
+ d->delayedMessages.pop_front();
+ processMessage (first);
+ }
+ else
+ {
+ processMessage(msg);
+ }
+}
+
+void KMessageClient::processMessage (const QByteArray &msg)
+{
+ if (d->isLocked)
+ { // must NOT happen, since we check in processIncomingMessage as well as in processFirstMessage
+ d->delayedMessages.append(msg);
+ return;
+ }
+ QBuffer in_buffer (msg);
+ in_buffer.open (IO_ReadOnly);
+ QDataStream in_stream (&in_buffer);
+
+
+ bool unknown = false;
+
+ Q_UINT32 messageID;
+ in_stream >> messageID;
+ switch (messageID)
+ {
+ case KMessageServer::MSG_BROADCAST:
+ {
+ Q_UINT32 clientID;
+ in_stream >> clientID;
+ emit broadcastReceived (in_buffer.readAll(), clientID);
+ }
+ break;
+
+ case KMessageServer::MSG_FORWARD:
+ {
+ Q_UINT32 clientID;
+ QValueList <Q_UINT32> receivers;
+ in_stream >> clientID >> receivers;
+ emit forwardReceived (in_buffer.readAll(), clientID, receivers);
+ }
+ break;
+
+ case KMessageServer::ANS_CLIENT_ID:
+ {
+ bool old_admin = isAdmin();
+ Q_UINT32 clientID;
+ in_stream >> clientID;
+ d->connection->setId (clientID);
+ if (old_admin != isAdmin())
+ emit adminStatusChanged (isAdmin());
+ }
+ break;
+
+ case KMessageServer::ANS_ADMIN_ID:
+ {
+ bool old_admin = isAdmin();
+ in_stream >> d->adminID;
+ if (old_admin != isAdmin())
+ emit adminStatusChanged (isAdmin());
+ }
+ break;
+
+ case KMessageServer::ANS_CLIENT_LIST:
+ {
+ in_stream >> d->clientList;
+ }
+ break;
+
+ case KMessageServer::EVNT_CLIENT_CONNECTED:
+ {
+ Q_UINT32 id;
+ in_stream >> id;
+
+ if (d->clientList.contains (id))
+ kdWarning (11001) << k_funcinfo << ": Adding a client that already existed!" << endl;
+ else
+ d->clientList.append (id);
+
+ emit eventClientConnected (id);
+ }
+ break;
+
+ case KMessageServer::EVNT_CLIENT_DISCONNECTED:
+ {
+ Q_UINT32 id;
+ Q_INT8 broken;
+ in_stream >> id >> broken;
+
+ if (!d->clientList.contains (id))
+ kdWarning (11001) << k_funcinfo << ": Removing a client that doesn't exist!" << endl;
+ else
+ d->clientList.remove (id);
+
+ emit eventClientDisconnected (id, bool (broken));
+ }
+ break;
+
+ default:
+ unknown = true;
+ }
+
+ if (!unknown && !in_buffer.atEnd())
+ kdWarning (11001) << k_funcinfo << ": Extra data received for message ID " << messageID << endl;
+
+ emit serverMessageReceived (msg, unknown);
+
+ if (unknown)
+ kdWarning (11001) << k_funcinfo << ": received unknown message ID " << messageID << endl;
+}
+
+void KMessageClient::processFirstMessage()
+{
+ if (d->isLocked)
+ {
+ return;
+ }
+ if (d->delayedMessages.count() == 0)
+ {
+ kdDebug(11001) << k_funcinfo << ": no messages delayed" << endl;
+ return;
+ }
+ QByteArray first = d->delayedMessages.front();
+ d->delayedMessages.pop_front();
+ processMessage (first);
+}
+
+void KMessageClient::removeBrokenConnection ()
+{
+ kdDebug (11001) << k_funcinfo << ": timer single shot for removeBrokenConnection"<<this << endl;
+ // MH We cannot directly delete the socket. otherwise QSocket crashes
+ QTimer::singleShot( 0, this, SLOT(removeBrokenConnection2()) );
+ return;
+}
+
+
+void KMessageClient::removeBrokenConnection2 ()
+{
+ kdDebug (11001) << k_funcinfo << ": Broken:Deleting the connection object"<<this << endl;
+
+ emit aboutToDisconnect(id());
+ delete d->connection;
+ d->connection = 0;
+ d->adminID = 0;
+ emit connectionBroken();
+ kdDebug (11001) << k_funcinfo << ": Broken:Deleting the connection object DONE" << endl;
+}
+
+void KMessageClient::disconnect ()
+{
+ kdDebug (11001) << k_funcinfo << ": Disconnect:Deleting the connection object" << endl;
+
+ emit aboutToDisconnect(id());
+ delete d->connection;
+ d->connection = 0;
+ d->adminID = 0;
+ emit connectionBroken();
+ kdDebug (11001) << k_funcinfo << ": Disconnect:Deleting the connection object DONE" << endl;
+}
+
+void KMessageClient::lock ()
+{
+ d->isLocked = true;
+}
+
+void KMessageClient::unlock ()
+{
+ d->isLocked = false;
+ for (unsigned int i = 0; i < d->delayedMessages.count(); i++)
+ {
+ QTimer::singleShot(0, this, SLOT(processFirstMessage()));
+ }
+}
+
+unsigned int KMessageClient::delayedMessageCount() const
+{
+ return d->delayedMessages.count();
+}
+
+#include "kmessageclient.moc"