You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/libtdegames/kgame/kmessageclient.cpp

374 lines
8.9 KiB

/*
This file is part of the TDE 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 <tqbuffer.h>
#include <tqtimer.h>
#include "kmessageio.h"
#include "kmessageserver.h"
#include "kmessageclient.h"
class KMessageClientPrivate
{
public:
KMessageClientPrivate ()
: adminID (0), connection (0)
{}
~KMessageClientPrivate ()
{
delete connection;
}
TQ_UINT32 adminID;
TQValueList <TQ_UINT32> clientList;
KMessageIO *connection;
bool isLocked;
TQValueList <TQByteArray> 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, TQ_SIGNAL (received(const TQByteArray &)),
this, TQ_SLOT (processIncomingMessage(const TQByteArray &)));
connect (connection, TQ_SIGNAL (connectionBroken()),
this, TQ_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 <TQ_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;
}
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<TQ_UINT32> ( KMessageServer::REQ_BROADCAST );
buffer.writeBlock (msg);
sendServerMessage (sendBuffer);
}
void KMessageClient::sendForward (const TQByteArray &msg, const TQValueList <TQ_UINT32> &clients)
{
TQByteArray sendBuffer;
TQBuffer buffer (sendBuffer);
buffer.open (IO_WriteOnly);
TQDataStream stream (&buffer);
stream << static_cast<TQ_UINT32>( KMessageServer::REQ_FORWARD ) << clients;
buffer.writeBlock (msg);
sendServerMessage (sendBuffer);
}
void KMessageClient::sendForward (const TQByteArray &msg, TQ_UINT32 client)
{
sendForward (msg, TQValueList <TQ_UINT32> () << 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 <TQ_UINT32> 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"<<this << endl;
// MH We cannot directly delete the socket. otherwise TQSocket crashes
TQTimer::singleShot( 0, this, TQ_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++)
{
TQTimer::singleShot(0, this, TQ_SLOT(processFirstMessage()));
}
}
unsigned int KMessageClient::delayedMessageCount() const
{
return d->delayedMessages.count();
}
#include "kmessageclient.moc"