summaryrefslogtreecommitdiffstats
path: root/libtdegames/kgame/kgamenetwork.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libtdegames/kgame/kgamenetwork.cpp')
-rw-r--r--libtdegames/kgame/kgamenetwork.cpp516
1 files changed, 516 insertions, 0 deletions
diff --git a/libtdegames/kgame/kgamenetwork.cpp b/libtdegames/kgame/kgamenetwork.cpp
new file mode 100644
index 00000000..a3548579
--- /dev/null
+++ b/libtdegames/kgame/kgamenetwork.cpp
@@ -0,0 +1,516 @@
+/*
+ This file is part of the KDE games library
+ Copyright (C) 2001 Martin Heni ([email protected])
+ Copyright (C) 2001 Andreas Beckermann ([email protected])
+
+ 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.
+*/
+/*
+ $Id$
+*/
+
+#include "kgamenetwork.h"
+#include "kgamenetwork.moc"
+#include "kgamemessage.h"
+#include "kgameerror.h"
+
+#include "kmessageserver.h"
+#include "kmessageclient.h"
+#include "kmessageio.h"
+#include <dnssd/publicservice.h>
+
+#include <kdebug.h>
+
+#include <tqbuffer.h>
+
+
+class KGameNetworkPrivate
+{
+public:
+ KGameNetworkPrivate()
+ {
+ mMessageClient = 0;
+ mMessageServer = 0;
+ mDisconnectId = 0;
+ mService = 0;
+ }
+
+public:
+ KMessageClient* mMessageClient;
+ KMessageServer* mMessageServer;
+ TQ_UINT32 mDisconnectId; // Stores gameId() over a disconnect process
+ DNSSD::PublicService* mService;
+ TQString mType;
+ TQString mName;
+
+ int mCookie;
+};
+
+// ------------------- NETWORK GAME ------------------------
+KGameNetwork::KGameNetwork(int c, TQObject* parent) : TQObject(parent, 0)
+{
+ d = new KGameNetworkPrivate;
+ d->mCookie = (TQ_INT16)c;
+
+ // Init the game as a local game, i.e.
+ // create your own KMessageServer and a KMessageClient connected to it.
+ setMaster();
+
+ kdDebug(11001) << k_funcinfo << "this=" << this <<", cookie=" << cookie() << " sizeof(this)="<<sizeof(KGameNetwork) << endl;
+}
+
+KGameNetwork::~KGameNetwork()
+{
+ kdDebug(11001) << k_funcinfo << "this=" << this << endl;
+// Debug();
+ delete d->mService;
+ delete d;
+}
+
+// ----------------------------- status methods
+bool KGameNetwork::isNetwork() const
+{ return isOfferingConnections() || d->mMessageClient->isNetwork();}
+
+TQ_UINT32 KGameNetwork::gameId() const
+{
+ //return d->mMessageClient->id() ;
+ // Return stored id in the case of disconnect. In any other
+ // case the disconnect id is 0
+ if (d->mMessageClient->id()!=0 ) {
+ return d->mMessageClient->id() ;
+ } else {
+ return d->mDisconnectId;
+ }
+}
+
+int KGameNetwork::cookie() const
+{ return d->mCookie; }
+
+bool KGameNetwork::isMaster() const
+{ return (d->mMessageServer != 0); }
+
+bool KGameNetwork::isAdmin() const
+{ return (d->mMessageClient->isAdmin()); }
+
+KMessageClient* KGameNetwork::messageClient() const
+{ return d->mMessageClient; }
+
+KMessageServer* KGameNetwork::messageServer() const
+{ return d->mMessageServer; }
+
+// ----------------------- network init
+void KGameNetwork::setMaster()
+{
+ if (!d->mMessageServer) {
+ d->mMessageServer = new KMessageServer (cookie(), this);
+ } else {
+ kdWarning(11001) << k_funcinfo << "Server already running!!" << endl;
+ }
+ if (!d->mMessageClient) {
+ d->mMessageClient = new KMessageClient (this);
+ connect (d->mMessageClient, TQT_SIGNAL(broadcastReceived(const TQByteArray&, TQ_UINT32)),
+ this, TQT_SLOT(receiveNetworkTransmission(const TQByteArray&, TQ_UINT32)));
+ connect (d->mMessageClient, TQT_SIGNAL(connectionBroken()),
+ this, TQT_SIGNAL(signalConnectionBroken()));
+ connect (d->mMessageClient, TQT_SIGNAL(aboutToDisconnect(TQ_UINT32)),
+ this, TQT_SLOT(aboutToLoseConnection(TQ_UINT32)));
+ connect (d->mMessageClient, TQT_SIGNAL(connectionBroken()),
+ this, TQT_SLOT(slotResetConnection()));
+
+ connect (d->mMessageClient, TQT_SIGNAL(adminStatusChanged(bool)),
+ this, TQT_SLOT(slotAdminStatusChanged(bool)));
+ connect (d->mMessageClient, TQT_SIGNAL(eventClientConnected(TQ_UINT32)),
+ this, TQT_SIGNAL(signalClientConnected(TQ_UINT32)));
+ connect (d->mMessageClient, TQT_SIGNAL(eventClientDisconnected(TQ_UINT32, bool)),
+ this, TQT_SIGNAL(signalClientDisconnected(TQ_UINT32, bool)));
+
+ // broacast and direct messages are treated equally on receive.
+ connect (d->mMessageClient, TQT_SIGNAL(forwardReceived(const TQByteArray&, TQ_UINT32, const TQValueList<TQ_UINT32>&)),
+ d->mMessageClient, TQT_SIGNAL(broadcastReceived(const TQByteArray&, TQ_UINT32)));
+
+ } else {
+ // should be no problem but still has to be tested
+ kdDebug(11001) << k_funcinfo << "Client already exists!" << endl;
+ }
+ d->mMessageClient->setServer(d->mMessageServer);
+}
+
+void KGameNetwork::setDiscoveryInfo(const TQString& type, const TQString& name)
+{
+ kdDebug() << k_funcinfo << type << ":" << name << endl;
+ d->mType = type;
+ d->mName = name;
+ tryPublish();
+}
+
+void KGameNetwork::tryPublish()
+{
+ if (d->mType.isNull() || !isOfferingConnections()) return;
+ if (!d->mService) d->mService = new DNSSD::PublicService(d->mName,d->mType,port());
+ else {
+ if (d->mType!=d->mService->type()) d->mService->setType(d->mType);
+ if (d->mName!=d->mService->serviceName()) d->mService->setServiceName(d->mName);
+ }
+ if (!d->mService->isPublished()) d->mService->publishAsync();
+}
+
+void KGameNetwork::tryStopPublishing()
+{
+ if (d->mService) d->mService->stop();
+}
+
+bool KGameNetwork::offerConnections(TQ_UINT16 port)
+{
+ kdDebug (11001) << k_funcinfo << "on port " << port << endl;
+ if (!isMaster()) {
+ setMaster();
+ }
+
+ // Make sure this is 0
+ d->mDisconnectId = 0;
+
+ // FIXME: This debug message can be removed when the program is working correct.
+ if (d->mMessageServer && d->mMessageServer->isOfferingConnections()) {
+ kdDebug (11001) << k_funcinfo << "Already running as server! Changing the port now!" << endl;
+ }
+
+ tryStopPublishing();
+ kdDebug (11001) << k_funcinfo << "before Server->initNetwork" << endl;
+ if (!d->mMessageServer->initNetwork (port)) {
+ kdError (11001) << k_funcinfo << "Unable to bind to port " << port << "!" << endl;
+ // no need to delete - we just cannot listen to the port
+// delete d->mMessageServer;
+// d->mMessageServer = 0;
+// d->mMessageClient->setServer((KMessageServer*)0);
+ return false;
+ }
+ kdDebug (11001) << k_funcinfo << "after Server->initNetwork" << endl;
+ tryPublish();
+ return true;
+}
+
+bool KGameNetwork::connectToServer (const TQString& host, TQ_UINT16 port)
+{
+ if (host.isEmpty()) {
+ kdError(11001) << k_funcinfo << "No hostname given" << endl;
+ return false;
+ }
+
+ // Make sure this is 0
+ d->mDisconnectId = 0;
+
+// if (!d->mMessageServer) {
+// // FIXME: What shall we do here? Probably must stop a running game.
+// kdWarning (11001) << k_funcinfo << "We are already connected to another server!" << endl;
+/// }
+
+ if (d->mMessageServer) {
+ // FIXME: What shall we do here? Probably must stop a running game.
+ kdWarning(11001) << "we are server but we are trying to connect to another server! "
+ << "make sure that all clients connect to that server! "
+ << "quitting the local server now..." << endl;
+ stopServerConnection();
+ d->mMessageClient->setServer((KMessageIO*)0);
+ delete d->mMessageServer;
+ d->mMessageServer = 0;
+ }
+
+ kdDebug(11001) << " about to set server" << endl;
+ d->mMessageClient->setServer(host, port);
+ emit signalAdminStatusChanged(false); // as we delete the connection above isAdmin() is always false now!
+
+ // OK: We say that we already have connected, but this isn't so yet!
+ // If the connection cannot be established, it will look as being disconnected
+ // again ("slotConnectionLost" is called).
+ // Shall we differ between these?
+ kdDebug(11001) << "connected to " << host << ":" << port << endl;
+ return true;
+}
+
+TQ_UINT16 KGameNetwork::port() const
+{
+ if (isNetwork()) {
+ if (isOfferingConnections()) {
+ return d->mMessageServer->serverPort();
+ } else {
+ return d->mMessageClient->peerPort();
+ }
+ }
+ return 0;
+}
+
+TQString KGameNetwork::hostName() const
+{
+ return d->mMessageClient->peerName();
+}
+
+bool KGameNetwork::stopServerConnection()
+{
+ // We still are the Master, we just don't accept further connections!
+ tryStopPublishing();
+ if (d->mMessageServer) {
+ d->mMessageServer->stopNetwork();
+ return true;
+ }
+ return false;
+}
+
+bool KGameNetwork::isOfferingConnections() const
+{ return (d->mMessageServer && d->mMessageServer->isOfferingConnections()); }
+
+void KGameNetwork::disconnect()
+{
+ // TODO MH
+ kdDebug(11001) << k_funcinfo << endl;
+ stopServerConnection();
+ if (d->mMessageServer) {
+ TQValueList <TQ_UINT32> list=d->mMessageServer->clientIDs();
+ TQValueList<TQ_UINT32>::Iterator it;
+ for( it = list.begin(); it != list.end(); ++it )
+ {
+ kdDebug(11001) << "Client id=" << (*it) << endl;
+ KMessageIO *client=d->mMessageServer->findClient(*it);
+ if (!client)
+ {
+ continue;
+ }
+ kdDebug(11001) << " rtti=" << client->rtti() << endl;
+ if (client->rtti()==2)
+ {
+ kdDebug(11001) << "DIRECT IO " << endl;
+ }
+ else
+ {
+ d->mMessageServer->removeClient(client,false);
+ }
+ }
+ }
+ else
+ {
+ kdDebug(11001) << k_funcinfo << "before client->disconnect() id="<<gameId()<< endl;
+ //d->mMessageClient->setServer((KMessageIO*)0);
+ kdDebug(11001) << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++"<<endl;
+ d->mMessageClient->disconnect();
+
+ kdDebug(11001) << "++++++--------------------------------------------+++++"<<endl;
+ }
+ //setMaster();
+ /*
+ if (d->mMessageServer) {
+ //delete d->mMessageServer;
+ //d->mMessageServer=0;
+ server=true;
+ kdDebug(11001) << " server true" << endl;
+ d->mMessageServer->deleteClients();
+ kdDebug(11001) << " server deleteClients" << endl;
+ }
+ */
+ kdDebug(11001) << k_funcinfo << "DONE" << endl;
+}
+
+void KGameNetwork::aboutToLoseConnection(TQ_UINT32 clientID)
+{
+ kdDebug(11001) << "Storing client id of connection "<<clientID<<endl;
+ d->mDisconnectId = clientID;
+}
+
+void KGameNetwork::slotResetConnection()
+{
+ kdDebug(11001) << "Resseting client disconnect id"<<endl;
+ d->mDisconnectId = 0;
+}
+
+void KGameNetwork::electAdmin(TQ_UINT32 clientID)
+{
+ if (!isAdmin()) {
+ kdWarning(11001) << k_funcinfo << "only ADMIN is allowed to call this!" << endl;
+ return;
+ }
+ TQByteArray buffer;
+ TQDataStream stream(buffer,IO_WriteOnly);
+ stream << static_cast<TQ_UINT32>( KMessageServer::RETQ_ADMIN_CHANGE );
+ stream << clientID;
+ d->mMessageClient->sendServerMessage(buffer);
+}
+
+void KGameNetwork::setMaxClients(int max)
+{
+ if (!isAdmin()) {
+ kdWarning(11001) << k_funcinfo << "only ADMIN is allowed to call this!" << endl;
+ return;
+ }
+ TQByteArray buffer;
+ TQDataStream stream(buffer,IO_WriteOnly);
+ stream << static_cast<TQ_UINT32>( KMessageServer::RETQ_MAX_NUM_CLIENTS );
+ stream << (TQ_INT32)max;
+ d->mMessageClient->sendServerMessage(buffer);
+}
+
+void KGameNetwork::lock()
+{
+ if (messageClient()) {
+ messageClient()->lock();
+ }
+}
+
+void KGameNetwork::unlock()
+{
+ if (messageClient()) {
+ messageClient()->unlock();
+ }
+}
+
+// --------------------- send messages ---------------------------
+
+bool KGameNetwork::sendSystemMessage(int data, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender)
+{
+ TQByteArray buffer;
+ TQDataStream stream(buffer,IO_WriteOnly);
+ stream << data;
+ return sendSystemMessage(buffer,msgid,receiver,sender);
+}
+
+bool KGameNetwork::sendSystemMessage(const TQString &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender)
+{
+ TQByteArray buffer;
+ TQDataStream stream(buffer, IO_WriteOnly);
+ stream << msg;
+ return sendSystemMessage(buffer, msgid, receiver, sender);
+}
+
+bool KGameNetwork::sendSystemMessage(const TQDataStream &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender)
+{ return sendSystemMessage(((TQBuffer*)msg.device())->buffer(), msgid, receiver, sender); }
+
+bool KGameNetwork::sendSystemMessage(const TQByteArray& data, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender)
+{
+ TQByteArray buffer;
+ TQDataStream stream(buffer,IO_WriteOnly);
+ if (!sender) {
+ sender = gameId();
+ }
+
+ TQ_UINT32 receiverClient = KGameMessage::rawGameId(receiver); // KGame::gameId()
+ int receiverPlayer = KGameMessage::rawPlayerId(receiver); // KPlayer::id()
+
+ KGameMessage::createHeader(stream, sender, receiver, msgid);
+ stream.writeRawBytes(data.data(), data.size());
+
+ /*
+ kdDebug(11001) << "transmitGameClientMessage msgid=" << msgid << " recv="
+ << receiver << " sender=" << sender << " Buffersize="
+ << buffer.size() << endl;
+ */
+
+ if (!d->mMessageClient) {
+ // No client created, this should never happen!
+ // Having a local game means we have our own
+ // KMessageServer and we are the only client.
+ kdWarning (11001) << k_funcinfo << "We don't have a client! Should never happen!" << endl;
+ return false;
+ }
+
+ if (receiverClient == 0 || receiverPlayer != 0)
+ {
+ // if receiverClient == 0 this is a broadcast message. if it is != 0 but
+ // receiverPlayer is also != 0 we have to send broadcast anyway, because the
+ // KPlayer object on all clients needs to receive the message.
+ d->mMessageClient->sendBroadcast(buffer);
+ }
+ else
+ {
+ d->mMessageClient->sendForward(buffer, receiverClient);
+ }
+ return true;
+}
+
+bool KGameNetwork::sendMessage(int data, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender)
+{ return sendSystemMessage(data,msgid+KGameMessage::IdUser,receiver,sender); }
+
+bool KGameNetwork::sendMessage(const TQString &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender)
+{ return sendSystemMessage(msg,msgid+KGameMessage::IdUser,receiver,sender); }
+
+bool KGameNetwork::sendMessage(const TQDataStream &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender)
+{ return sendSystemMessage(msg, msgid+KGameMessage::IdUser, receiver, sender); }
+
+bool KGameNetwork::sendMessage(const TQByteArray &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender)
+{ return sendSystemMessage(msg, msgid+KGameMessage::IdUser, receiver, sender); }
+
+void KGameNetwork::sendError(int error,const TQByteArray& message, TQ_UINT32 receiver, TQ_UINT32 sender)
+{
+ TQByteArray buffer;
+ TQDataStream stream(buffer,IO_WriteOnly);
+ stream << (TQ_INT32) error;
+ stream.writeRawBytes(message.data(), message.size());
+ sendSystemMessage(stream,KGameMessage::IdError,receiver,sender);
+}
+
+
+// ----------------- receive messages from the network
+void KGameNetwork::receiveNetworkTransmission(const TQByteArray& receiveBuffer, TQ_UINT32 clientID)
+{
+ TQDataStream stream(receiveBuffer, IO_ReadOnly);
+ int msgid;
+ TQ_UINT32 sender; // the id of the KGame/KPlayer who sent the message
+ TQ_UINT32 receiver; // the id of the KGame/KPlayer the message is for
+ KGameMessage::extractHeader(stream, sender, receiver, msgid);
+// kdDebug(11001) << k_funcinfo << "id=" << msgid << " sender=" << sender << " recv=" << receiver << endl;
+
+ // No broadcast : receiver==0
+ // No player isPlayer(receiver)
+ // Different game gameId()!=receiver
+ if (receiver && receiver!=gameId() && !KGameMessage::isPlayer(receiver) )
+ {
+ // receiver=0 is broadcast or player message
+ kdDebug(11001) << k_funcinfo << "Message not meant for us "
+ << gameId() << "!=" << receiver << " rawid="
+ << KGameMessage::rawGameId(receiver) << endl;
+ return;
+ }
+ else if (msgid==KGameMessage::IdError)
+ {
+ TQString text;
+ TQ_INT32 error;
+ stream >> error;
+ kdDebug(11001) << k_funcinfo << "Got IdError " << error << endl;
+ text = KGameError::errorText(error, stream);
+ kdDebug(11001) << "Error text: " << text.latin1() << endl;
+ emit signalNetworkErrorMessage((int)error,text);
+ }
+ else
+ {
+ networkTransmission(stream, msgid, receiver, sender, clientID);
+ }
+}
+
+// -------------- slots for the signals of the client
+void KGameNetwork::slotAdminStatusChanged(bool isAdmin)
+{
+ emit signalAdminStatusChanged(isAdmin);
+
+// TODO: I'm pretty sure there are a lot of things that should be done here...
+}
+
+void KGameNetwork::Debug()
+{
+ kdDebug(11001) << "------------------- KNETWORKGAME -------------------------" << endl;
+ kdDebug(11001) << "gameId " << gameId() << endl;
+ kdDebug(11001) << "gameMaster " << isMaster() << endl;
+ kdDebug(11001) << "gameAdmin " << isAdmin() << endl;
+ kdDebug(11001) << "---------------------------------------------------" << endl;
+}
+
+/*
+ * vim: et sw=2
+ */