/* 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 #include #include #include #include "kmessageio.h" #include "kmessageserver.h" #include "kmessageclient.h" class KMessageClientPrivate { public: KMessageClientPrivate () : adminID (0), connection (0) {} ~KMessageClientPrivate () { delete connection; } TQ_UINT32 adminID; TQValueList clientList; KMessageIO *connection; bool isLocked; TQValueList delayedMessages; }; KMessageClient::KMessageClient (TQObject *parent, const char *name) : TQObject (parent, name) { d = new KMessageClientPrivate (); d->isLocked = false; } KMessageClient::~KMessageClient () { d->delayedMessages.clear(); delete d; } // -- setServer stuff void KMessageClient::setServer (const TQString &host, TQ_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, TQT_SIGNAL (received(const TQByteArray &)), this, TQT_SLOT (processIncomingMessage(const TQByteArray &))); connect (connection, TQT_SIGNAL (connectionBroken()), this, TQT_SLOT (removeBrokenConnection ())); } } // -- id stuff TQ_UINT32 KMessageClient::id () const { return (d->connection) ? d->connection->id () : 0; } bool KMessageClient::isAdmin () const { return id() != 0 && id() == adminId(); } TQ_UINT32 KMessageClient::adminId () const { return d->adminID; } const TQValueList &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; } TQ_UINT16 KMessageClient::peerPort () const { return d->connection ? d->connection->peerPort() : 0; } TQString KMessageClient::peerName () const { return d->connection ? d->connection->peerName() : TQString::fromLatin1("localhost"); } // --------------------- Sending messages void KMessageClient::sendServerMessage (const TQByteArray &msg) { if (!d->connection) { kdWarning (11001) << k_funcinfo << ": We have no connection yet!" << endl; return; } d->connection->send (msg); } void KMessageClient::sendBroadcast (const TQByteArray &msg) { TQByteArray sendBuffer; TQBuffer buffer (sendBuffer); buffer.open (IO_WriteOnly); TQDataStream stream (&buffer); stream << static_cast ( KMessageServer::RETQ_BROADCAST ); TQT_TQIODEVICE(&buffer)->writeBlock (msg); sendServerMessage (sendBuffer); } void KMessageClient::sendForward (const TQByteArray &msg, const TQValueList &clients) { TQByteArray sendBuffer; TQBuffer buffer (sendBuffer); buffer.open (IO_WriteOnly); TQDataStream stream (&buffer); stream << static_cast( KMessageServer::RETQ_FORWARD ) << clients; TQT_TQIODEVICE(&buffer)->writeBlock (msg); sendServerMessage (sendBuffer); } void KMessageClient::sendForward (const TQByteArray &msg, TQ_UINT32 client) { sendForward (msg, TQValueList () << client); } // --------------------- Receiving and processing messages void KMessageClient::processIncomingMessage (const TQByteArray &msg) { if (d->isLocked) { d->delayedMessages.append(msg); return; } if (d->delayedMessages.count() > 0) { d->delayedMessages.append (msg); TQByteArray first = d->delayedMessages.front(); d->delayedMessages.pop_front(); processMessage (first); } else { processMessage(msg); } } void KMessageClient::processMessage (const TQByteArray &msg) { if (d->isLocked) { // must NOT happen, since we check in processIncomingMessage as well as in processFirstMessage d->delayedMessages.append(msg); return; } TQBuffer in_buffer (msg); in_buffer.open (IO_ReadOnly); TQDataStream in_stream (&in_buffer); bool unknown = false; TQ_UINT32 messageID; in_stream >> messageID; switch (messageID) { case KMessageServer::MSG_BROADCAST: { TQ_UINT32 clientID; in_stream >> clientID; emit broadcastReceived (in_buffer.readAll(), clientID); } break; case KMessageServer::MSG_FORWARD: { TQ_UINT32 clientID; TQValueList receivers; in_stream >> clientID >> receivers; emit forwardReceived (in_buffer.readAll(), clientID, receivers); } break; case KMessageServer::ANS_CLIENT_ID: { bool old_admin = isAdmin(); TQ_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: { TQ_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: { TQ_UINT32 id; TQ_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; } TQByteArray first = d->delayedMessages.front(); d->delayedMessages.pop_front(); processMessage (first); } void KMessageClient::removeBrokenConnection () { kdDebug (11001) << k_funcinfo << ": timer single shot for removeBrokenConnection"<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++) { TQTimer::singleShot(0, this, TQT_SLOT(processFirstMessage())); } } unsigned int KMessageClient::delayedMessageCount() const { return d->delayedMessages.count(); } #include "kmessageclient.moc"