File indexing completed on 2024-06-16 03:57:55

0001 /*
0002     This file is part of the KDE games library
0003     SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de>
0004     SPDX-FileCopyrightText: 2001 Andreas Beckermann <b_mann@gmx.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #include "kgamenetwork.h"
0010 
0011 // own
0012 #include "kgameerror.h"
0013 #include "kgamemessage.h"
0014 #include "kmessageclient.h"
0015 #include "kmessageio.h"
0016 #include "kmessageserver.h"
0017 #include <kdegamesprivate_kgame_logging.h>
0018 // KF
0019 #include <KDNSSD/PublicService>
0020 // Qt
0021 #include <QBuffer>
0022 #include <QList>
0023 
0024 class KGameNetworkPrivate
0025 {
0026 public:
0027     KGameNetworkPrivate() = default;
0028 
0029 public:
0030     KMessageClient *mMessageClient = nullptr;
0031     KMessageServer *mMessageServer = nullptr;
0032     quint32 mDisconnectId = 0; // Stores gameId() over a disconnect process
0033     KDNSSD::PublicService *mService = nullptr;
0034     QString mType;
0035     QString mName;
0036 
0037     int mCookie;
0038 };
0039 
0040 // ------------------- NETWORK GAME ------------------------
0041 KGameNetwork::KGameNetwork(int c, QObject *parent)
0042     : QObject(parent)
0043     , d(new KGameNetworkPrivate)
0044 {
0045     d->mCookie = (qint16)c;
0046 
0047     // Init the game as a local game, i.e.
0048     // create your own KMessageServer and a KMessageClient connected to it.
0049     setMaster();
0050 
0051     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "this=" << this << ", cookie=" << cookie() << "sizeof(this)=" << sizeof(KGameNetwork);
0052 }
0053 
0054 KGameNetwork::~KGameNetwork()
0055 {
0056     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "this=" << this;
0057     // Debug();
0058     delete d->mService;
0059 }
0060 
0061 // ----------------------------- status methods
0062 bool KGameNetwork::isNetwork() const
0063 {
0064     return isOfferingConnections() || d->mMessageClient->isNetwork();
0065 }
0066 
0067 quint32 KGameNetwork::gameId() const
0068 {
0069     // return d->mMessageClient->id() ;
0070     //  Return stored id in the case of disconnect. In any other
0071     //  case the disconnect id is 0
0072     if (d->mMessageClient->id() != 0) {
0073         return d->mMessageClient->id();
0074     } else {
0075         return d->mDisconnectId;
0076     }
0077 }
0078 
0079 int KGameNetwork::cookie() const
0080 {
0081     return d->mCookie;
0082 }
0083 
0084 bool KGameNetwork::isMaster() const
0085 {
0086     return (d->mMessageServer != nullptr);
0087 }
0088 
0089 bool KGameNetwork::isAdmin() const
0090 {
0091     return (d->mMessageClient->isAdmin());
0092 }
0093 
0094 KMessageClient *KGameNetwork::messageClient() const
0095 {
0096     return d->mMessageClient;
0097 }
0098 
0099 KMessageServer *KGameNetwork::messageServer() const
0100 {
0101     return d->mMessageServer;
0102 }
0103 
0104 // ----------------------- network init
0105 void KGameNetwork::setMaster()
0106 {
0107     if (!d->mMessageServer) {
0108         d->mMessageServer = new KMessageServer(cookie(), this);
0109     } else {
0110         qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << "Server already running!!";
0111     }
0112     if (!d->mMessageClient) {
0113         d->mMessageClient = new KMessageClient(this);
0114         connect(d->mMessageClient, &KMessageClient::broadcastReceived, this, &KGameNetwork::receiveNetworkTransmission);
0115         connect(d->mMessageClient, &KMessageClient::connectionBroken, this, &KGameNetwork::signalConnectionBroken);
0116         connect(d->mMessageClient, &KMessageClient::aboutToDisconnect, this, &KGameNetwork::aboutToLoseConnection);
0117         connect(d->mMessageClient, &KMessageClient::connectionBroken, this, &KGameNetwork::slotResetConnection);
0118 
0119         connect(d->mMessageClient, &KMessageClient::adminStatusChanged, this, &KGameNetwork::slotAdminStatusChanged);
0120         connect(d->mMessageClient, &KMessageClient::eventClientConnected, this, &KGameNetwork::signalClientConnected);
0121         connect(d->mMessageClient, &KMessageClient::eventClientDisconnected, this, &KGameNetwork::signalClientDisconnected);
0122 
0123         // broacast and direct messages are treated equally on receive.
0124         connect(d->mMessageClient, &KMessageClient::forwardReceived, d->mMessageClient, &KMessageClient::broadcastReceived);
0125 
0126     } else {
0127         // should be no problem but still has to be tested
0128         qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Client already exists!";
0129     }
0130     d->mMessageClient->setServer(d->mMessageServer);
0131 }
0132 
0133 void KGameNetwork::setDiscoveryInfo(const QString &type, const QString &name)
0134 {
0135     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << type << ":" << name;
0136     d->mType = type;
0137     d->mName = name;
0138     tryPublish();
0139 }
0140 
0141 void KGameNetwork::tryPublish()
0142 {
0143     if (d->mType.isEmpty() || !isOfferingConnections())
0144         return;
0145     if (!d->mService)
0146         d->mService = new KDNSSD::PublicService(d->mName, d->mType, port());
0147     else {
0148         if (d->mType != d->mService->type())
0149             d->mService->setType(d->mType);
0150         if (d->mName != d->mService->serviceName())
0151             d->mService->setServiceName(d->mName);
0152     }
0153     if (!d->mService->isPublished())
0154         d->mService->publishAsync();
0155 }
0156 
0157 void KGameNetwork::tryStopPublishing()
0158 {
0159     if (d->mService)
0160         d->mService->stop();
0161 }
0162 
0163 bool KGameNetwork::offerConnections(quint16 port)
0164 {
0165     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "on port" << port;
0166     if (!isMaster()) {
0167         setMaster();
0168     }
0169 
0170     // Make sure this is 0
0171     d->mDisconnectId = 0;
0172 
0173     // FIXME: This debug message can be removed when the program is working correct.
0174     if (d->mMessageServer && d->mMessageServer->isOfferingConnections()) {
0175         qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Already running as server! Changing the port now!";
0176     }
0177 
0178     tryStopPublishing();
0179     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "before Server->initNetwork";
0180     if (!d->mMessageServer->initNetwork(port)) {
0181         qCCritical(KDEGAMESPRIVATE_KGAME_LOG) << "Unable to bind to port" << port << "!";
0182         // no need to delete - we just cannot listen to the port
0183         //   delete d->mMessageServer;
0184         //   d->mMessageServer = 0;
0185         //   d->mMessageClient->setServer((KMessageServer*)0);
0186         return false;
0187     }
0188     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "after Server->initNetwork";
0189     tryPublish();
0190     return true;
0191 }
0192 
0193 bool KGameNetwork::connectToServer(const QString &host, quint16 port)
0194 {
0195     if (host.isEmpty()) {
0196         qCCritical(KDEGAMESPRIVATE_KGAME_LOG) << "No hostname given";
0197         return false;
0198     }
0199     if (connectToServer(new KMessageSocket(host, port))) {
0200         qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "connected to" << host << ":" << port;
0201         return true;
0202     } else {
0203         return false;
0204     }
0205 }
0206 
0207 bool KGameNetwork::connectToServer(KMessageIO *connection)
0208 {
0209     // Make sure this is 0
0210     d->mDisconnectId = 0;
0211 
0212     // if (!d->mMessageServer) {
0213     //   // FIXME: What shall we do here? Probably must stop a running game.
0214     //   qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << "We are already connected to another server!";
0215     /// }
0216 
0217     if (d->mMessageServer) {
0218         // FIXME: What shall we do here? Probably must stop a running game.
0219         qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << "we are server but we are trying to connect to another server! "
0220                                              << "make sure that all clients connect to that server! "
0221                                              << "quitting the local server now...";
0222         stopServerConnection();
0223         d->mMessageClient->setServer((KMessageIO *)nullptr);
0224         delete d->mMessageServer;
0225         d->mMessageServer = nullptr;
0226     }
0227 
0228     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "    about to set server";
0229     d->mMessageClient->setServer(connection);
0230     Q_EMIT signalAdminStatusChanged(false); // as we delete the connection above isAdmin() is always false now!
0231 
0232     // OK: We say that we already have connected, but this isn't so yet!
0233     // If the connection cannot be established, it will look as being disconnected
0234     // again ("slotConnectionLost" is called).
0235     // Shall we differ between these?
0236     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "connected";
0237     return true;
0238 }
0239 
0240 quint16 KGameNetwork::port() const
0241 {
0242     if (isNetwork()) {
0243         if (isOfferingConnections()) {
0244             return d->mMessageServer->serverPort();
0245         } else {
0246             return d->mMessageClient->peerPort();
0247         }
0248     }
0249     return 0;
0250 }
0251 
0252 QString KGameNetwork::hostName() const
0253 {
0254     return d->mMessageClient->peerName();
0255 }
0256 
0257 bool KGameNetwork::stopServerConnection()
0258 {
0259     // We still are the Master, we just don't accept further connections!
0260     tryStopPublishing();
0261     if (d->mMessageServer) {
0262         d->mMessageServer->stopNetwork();
0263         return true;
0264     }
0265     return false;
0266 }
0267 
0268 bool KGameNetwork::isOfferingConnections() const
0269 {
0270     return (d->mMessageServer && d->mMessageServer->isOfferingConnections());
0271 }
0272 
0273 void KGameNetwork::disconnect()
0274 {
0275     // TODO MH
0276     qCDebug(KDEGAMESPRIVATE_KGAME_LOG);
0277     stopServerConnection();
0278     if (d->mMessageServer) {
0279         const QList<quint32> list = d->mMessageServer->clientIDs();
0280         for (quint32 id : list) {
0281             qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Client id=" << id;
0282             KMessageIO *client = d->mMessageServer->findClient(id);
0283             if (!client) {
0284                 continue;
0285             }
0286             qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "   rtti=" << client->rtti();
0287             if (client->rtti() == 2) {
0288                 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "DIRECT IO";
0289             } else {
0290                 d->mMessageServer->removeClient(client, false);
0291             }
0292         }
0293     } else {
0294         qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "before client->disconnect() id=" << gameId();
0295         // d->mMessageClient->setServer((KMessageIO*)0);
0296         qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++";
0297         d->mMessageClient->disconnect();
0298 
0299         qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "++++++--------------------------------------------+++++";
0300     }
0301     // setMaster();
0302     /*
0303     if (d->mMessageServer) {
0304      //delete d->mMessageServer;
0305      //d->mMessageServer=0;
0306      server=true;
0307      qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "  server true";
0308      d->mMessageServer->deleteClients();
0309      qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "  server deleteClients";
0310     }
0311     */
0312     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "DONE";
0313 }
0314 
0315 void KGameNetwork::aboutToLoseConnection(quint32 clientID)
0316 {
0317     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Storing client id of connection " << clientID;
0318     d->mDisconnectId = clientID;
0319 }
0320 
0321 void KGameNetwork::slotResetConnection()
0322 {
0323     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Resseting client disconnect id";
0324     d->mDisconnectId = 0;
0325 }
0326 
0327 void KGameNetwork::electAdmin(quint32 clientID)
0328 {
0329     if (!isAdmin()) {
0330         qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << "only ADMIN is allowed to call this!";
0331         return;
0332     }
0333     QByteArray buffer;
0334     QDataStream stream(&buffer, QIODevice::WriteOnly);
0335     stream << static_cast<quint32>(KMessageServer::REQ_ADMIN_CHANGE);
0336     stream << clientID;
0337     d->mMessageClient->sendServerMessage(buffer);
0338 }
0339 
0340 void KGameNetwork::setMaxClients(int max)
0341 {
0342     if (!isAdmin()) {
0343         qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << "only ADMIN is allowed to call this!";
0344         return;
0345     }
0346     QByteArray buffer;
0347     QDataStream stream(&buffer, QIODevice::WriteOnly);
0348     stream << static_cast<quint32>(KMessageServer::REQ_MAX_NUM_CLIENTS);
0349     stream << (qint32)max;
0350     d->mMessageClient->sendServerMessage(buffer);
0351 }
0352 
0353 void KGameNetwork::lock()
0354 {
0355     if (messageClient()) {
0356         messageClient()->lock();
0357     }
0358 }
0359 
0360 void KGameNetwork::unlock()
0361 {
0362     if (messageClient()) {
0363         messageClient()->unlock();
0364     }
0365 }
0366 
0367 // --------------------- send messages ---------------------------
0368 
0369 bool KGameNetwork::sendSystemMessage(int data, int msgid, quint32 receiver, quint32 sender)
0370 {
0371     QByteArray buffer;
0372     QDataStream stream(&buffer, QIODevice::WriteOnly);
0373     stream << data;
0374     return sendSystemMessage(buffer, msgid, receiver, sender);
0375 }
0376 
0377 bool KGameNetwork::sendSystemMessage(const QString &msg, int msgid, quint32 receiver, quint32 sender)
0378 {
0379     QByteArray buffer;
0380     QDataStream stream(&buffer, QIODevice::WriteOnly);
0381     stream << msg;
0382     return sendSystemMessage(buffer, msgid, receiver, sender);
0383 }
0384 
0385 bool KGameNetwork::sendSystemMessage(const QDataStream &msg, int msgid, quint32 receiver, quint32 sender)
0386 {
0387     return sendSystemMessage(((QBuffer *)msg.device())->buffer(), msgid, receiver, sender);
0388 }
0389 
0390 bool KGameNetwork::sendSystemMessage(const QByteArray &data, int msgid, quint32 receiver, quint32 sender)
0391 {
0392     QByteArray buffer;
0393     QDataStream stream(&buffer, QIODevice::WriteOnly);
0394     if (!sender) {
0395         sender = gameId();
0396     }
0397 
0398     quint32 receiverClient = KGameMessage::rawGameId(receiver); // KGame::gameId()
0399     int receiverPlayer = KGameMessage::rawPlayerId(receiver); // KPlayer::id()
0400 
0401     KGameMessage::createHeader(stream, sender, receiver, msgid);
0402     stream.writeRawData(data.data(), data.size());
0403 
0404     /*
0405     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "transmitGameClientMessage msgid=" << msgid << "recv="
0406                    << receiver << "sender=" << sender << "Buffersize="
0407                    << buffer.size();
0408      */
0409 
0410     if (!d->mMessageClient) {
0411         // No client created, this should never happen!
0412         // Having a local game means we have our own
0413         // KMessageServer and we are the only client.
0414         qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << "We don't have a client! Should never happen!";
0415         return false;
0416     }
0417 
0418     if (receiverClient == 0 || receiverPlayer != 0) {
0419         // if receiverClient == 0 this is a broadcast message. if it is != 0 but
0420         // receiverPlayer is also != 0 we have to send broadcast anyway, because the
0421         // KPlayer object on all clients needs to receive the message.
0422         d->mMessageClient->sendBroadcast(buffer);
0423     } else {
0424         d->mMessageClient->sendForward(buffer, receiverClient);
0425     }
0426     return true;
0427 }
0428 
0429 bool KGameNetwork::sendMessage(int data, int msgid, quint32 receiver, quint32 sender)
0430 {
0431     return sendSystemMessage(data, msgid + KGameMessage::IdUser, receiver, sender);
0432 }
0433 
0434 bool KGameNetwork::sendMessage(const QString &msg, int msgid, quint32 receiver, quint32 sender)
0435 {
0436     return sendSystemMessage(msg, msgid + KGameMessage::IdUser, receiver, sender);
0437 }
0438 
0439 bool KGameNetwork::sendMessage(const QDataStream &msg, int msgid, quint32 receiver, quint32 sender)
0440 {
0441     return sendSystemMessage(msg, msgid + KGameMessage::IdUser, receiver, sender);
0442 }
0443 
0444 bool KGameNetwork::sendMessage(const QByteArray &msg, int msgid, quint32 receiver, quint32 sender)
0445 {
0446     return sendSystemMessage(msg, msgid + KGameMessage::IdUser, receiver, sender);
0447 }
0448 
0449 void KGameNetwork::sendError(int error, const QByteArray &message, quint32 receiver, quint32 sender)
0450 {
0451     QByteArray buffer;
0452     QDataStream stream(&buffer, QIODevice::WriteOnly);
0453     stream << (qint32)error;
0454     stream.writeRawData(message.data(), message.size());
0455     sendSystemMessage(stream, KGameMessage::IdError, receiver, sender);
0456 }
0457 
0458 // ----------------- receive messages from the network
0459 void KGameNetwork::receiveNetworkTransmission(const QByteArray &receiveBuffer, quint32 clientID)
0460 {
0461     QDataStream stream(receiveBuffer);
0462     int msgid;
0463     quint32 sender; // the id of the KGame/KPlayer who sent the message
0464     quint32 receiver; // the id of the KGame/KPlayer the message is for
0465     KGameMessage::extractHeader(stream, sender, receiver, msgid);
0466     // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "id=" << msgid << "sender=" << sender << "recv=" << receiver;
0467 
0468     // No broadcast : receiver==0
0469     // No player isPlayer(receiver)
0470     // Different game gameId()!=receiver
0471     if (receiver && receiver != gameId() && !KGameMessage::isPlayer(receiver)) {
0472         // receiver=0 is broadcast or player message
0473         qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Message not meant for us " << gameId() << "!=" << receiver << "rawid=" << KGameMessage::rawGameId(receiver);
0474         return;
0475     } else if (msgid == KGameMessage::IdError) {
0476         QString text;
0477         qint32 error;
0478         stream >> error;
0479         qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Got IdError" << error;
0480         text = KGameError::errorText(error, stream);
0481         qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Error text:" << text.toLatin1();
0482         Q_EMIT signalNetworkErrorMessage((int)error, text);
0483     } else {
0484         networkTransmission(stream, msgid, receiver, sender, clientID);
0485     }
0486 }
0487 
0488 // -------------- slots for the signals of the client
0489 void KGameNetwork::slotAdminStatusChanged(bool isAdmin)
0490 {
0491     Q_EMIT signalAdminStatusChanged(isAdmin);
0492 
0493     // TODO: I'm pretty sure there are a lot of things that should be done here...
0494 }
0495 
0496 void KGameNetwork::Debug()
0497 {
0498     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "------------------- KNETWORKGAME -------------------------";
0499     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "gameId         " << gameId();
0500     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "gameMaster     " << isMaster();
0501     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "gameAdmin      " << isAdmin();
0502     qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "---------------------------------------------------";
0503 }
0504 
0505 #include "moc_kgamenetwork.cpp"
0506 
0507 /*
0508  * vim: et sw=2
0509  */