File indexing completed on 2024-12-22 03:52:57
0001 /* 0002 This file is part of the KDE games library 0003 SPDX-FileCopyrightText: 2001 Burkhard Lehner <Burkhard.Lehner@gmx.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "kmessageserver.h" 0009 #include "kmessageserver_p.h" 0010 0011 // own 0012 #include "kmessageio.h" 0013 #include <kdegamesprivate_kgame_logging.h> 0014 // Qt 0015 #include <QBuffer> 0016 #include <QDataStream> 0017 #include <QIODevice> 0018 #include <QList> 0019 #include <QQueue> 0020 #include <QTimer> 0021 0022 // --------------- internal class KMessageServerSocket 0023 0024 KMessageServerSocket::KMessageServerSocket(quint16 port, QObject *parent) 0025 : QTcpServer(parent) 0026 { 0027 listen(QHostAddress::Any, port); 0028 connect(this, &KMessageServerSocket::newConnection, this, &KMessageServerSocket::slotNewConnection); 0029 } 0030 0031 KMessageServerSocket::~KMessageServerSocket() 0032 { 0033 } 0034 0035 void KMessageServerSocket::slotNewConnection() 0036 { 0037 if (hasPendingConnections()) { 0038 Q_EMIT newClientConnected(new KMessageSocket(nextPendingConnection())); 0039 } 0040 } 0041 0042 // ---------------- class for storing an incoming message 0043 0044 class MessageBuffer 0045 { 0046 public: 0047 MessageBuffer(quint32 clientID, const QByteArray &messageData) 0048 : id(clientID) 0049 , data(messageData) 0050 { 0051 } 0052 ~MessageBuffer() 0053 { 0054 } 0055 quint32 id; 0056 QByteArray data; 0057 }; 0058 0059 // ---------------- KMessageServer's private class 0060 0061 class KMessageServerPrivate 0062 { 0063 public: 0064 KMessageServerPrivate() = default; 0065 0066 ~KMessageServerPrivate() 0067 { 0068 qDeleteAll(mClientList); 0069 qDeleteAll(mMessageQueue); 0070 } 0071 0072 public: 0073 int mMaxClients = -1; 0074 int mGameId = 1; 0075 quint16 mCookie; 0076 quint32 mUniqueClientNumber = 1; 0077 quint32 mAdminID = 0; 0078 0079 KMessageServerSocket *mServerSocket = nullptr; 0080 0081 QList<KMessageIO *> mClientList; 0082 QQueue<MessageBuffer *> mMessageQueue; 0083 QTimer mTimer; 0084 bool mIsRecursive = false; 0085 }; 0086 0087 // ------------------ KMessageServer 0088 0089 KMessageServer::KMessageServer(quint16 cookie, QObject *parent) 0090 : QObject(parent) 0091 , d(new KMessageServerPrivate) 0092 { 0093 d->mCookie = cookie; 0094 connect(&(d->mTimer), &QTimer::timeout, this, &KMessageServer::processOneMessage); 0095 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "CREATE(KMessageServer=" << this << ") cookie=" << d->mCookie << "sizeof(this)=" << sizeof(KMessageServer); 0096 } 0097 0098 KMessageServer::~KMessageServer() 0099 { 0100 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "this=" << this; 0101 Debug(); 0102 stopNetwork(); 0103 deleteClients(); 0104 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "done"; 0105 } 0106 0107 //------------------------------------- TCP/IP server stuff 0108 0109 bool KMessageServer::initNetwork(quint16 port) 0110 { 0111 qCDebug(KDEGAMESPRIVATE_KGAME_LOG); 0112 0113 if (d->mServerSocket) { 0114 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": We were already offering connections!"; 0115 delete d->mServerSocket; 0116 } 0117 0118 d->mServerSocket = new KMessageServerSocket(port); 0119 d->mIsRecursive = false; 0120 0121 if (!d->mServerSocket || !d->mServerSocket->isListening()) { 0122 qCCritical(KDEGAMESPRIVATE_KGAME_LOG) << ": Serversocket::ok() == false"; 0123 delete d->mServerSocket; 0124 d->mServerSocket = nullptr; 0125 return false; 0126 } 0127 0128 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": Now listening to port " << d->mServerSocket->serverPort(); 0129 connect(d->mServerSocket, &KMessageServerSocket::newClientConnected, this, &KMessageServer::addClient); 0130 return true; 0131 } 0132 0133 quint16 KMessageServer::serverPort() const 0134 { 0135 if (d->mServerSocket) 0136 return d->mServerSocket->serverPort(); 0137 else 0138 return 0; 0139 } 0140 0141 void KMessageServer::stopNetwork() 0142 { 0143 if (d->mServerSocket) { 0144 delete d->mServerSocket; 0145 d->mServerSocket = nullptr; 0146 } 0147 } 0148 0149 bool KMessageServer::isOfferingConnections() const 0150 { 0151 return d->mServerSocket != nullptr; 0152 } 0153 0154 //----------------------------------------------- adding / removing clients 0155 0156 void KMessageServer::addClient(KMessageIO *client) 0157 { 0158 QByteArray msg; 0159 0160 // maximum number of clients reached? 0161 if (d->mMaxClients >= 0 && d->mMaxClients <= clientCount()) { 0162 qCCritical(KDEGAMESPRIVATE_KGAME_LOG) << ": Maximum number of clients reached!"; 0163 return; 0164 } 0165 0166 // give it a unique ID 0167 client->setId(uniqueClientNumber()); 0168 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ":" << client->id(); 0169 0170 // connect its signals 0171 connect(client, &KMessageIO::connectionBroken, this, &KMessageServer::removeBrokenClient); 0172 connect(client, &KMessageIO::received, this, &KMessageServer::getReceivedMessage); 0173 0174 // Tell everyone about the new guest 0175 // Note: The new client doesn't get this message! 0176 QDataStream(&msg, QIODevice::WriteOnly) << quint32(EVNT_CLIENT_CONNECTED) << client->id(); 0177 broadcastMessage(msg); 0178 0179 // add to our list 0180 d->mClientList.push_back(client); 0181 0182 // tell it its ID 0183 QDataStream(&msg, QIODevice::WriteOnly) << quint32(ANS_CLIENT_ID) << client->id(); 0184 client->send(msg); 0185 0186 // Give it the complete list of client IDs 0187 QDataStream(&msg, QIODevice::WriteOnly) << quint32(ANS_CLIENT_LIST) << clientIDs(); 0188 client->send(msg); 0189 0190 if (clientCount() == 1) { 0191 // if it is the first client, it becomes the admin 0192 setAdmin(client->id()); 0193 } else { 0194 // otherwise tell it who is the admin 0195 QDataStream(&msg, QIODevice::WriteOnly) << quint32(ANS_ADMIN_ID) << adminID(); 0196 client->send(msg); 0197 } 0198 0199 Q_EMIT clientConnected(client); 0200 } 0201 0202 void KMessageServer::removeClient(KMessageIO *client, bool broken) 0203 { 0204 quint32 clientID = client->id(); 0205 if (!d->mClientList.removeAll(client)) { 0206 qCCritical(KDEGAMESPRIVATE_KGAME_LOG) << ": Deleting client that wasn't added before!"; 0207 return; 0208 } 0209 0210 // tell everyone about the removed client 0211 QByteArray msg; 0212 QDataStream(&msg, QIODevice::WriteOnly) << quint32(EVNT_CLIENT_DISCONNECTED) << client->id() << (qint8)broken; 0213 broadcastMessage(msg); 0214 0215 // If it was the admin, select a new admin. 0216 if (clientID == adminID()) { 0217 if (!d->mClientList.isEmpty()) 0218 setAdmin(d->mClientList.front()->id()); 0219 else 0220 setAdmin(0); 0221 } 0222 } 0223 0224 void KMessageServer::deleteClients() 0225 { 0226 qDeleteAll(d->mClientList); 0227 d->mClientList.clear(); 0228 d->mAdminID = 0; 0229 } 0230 0231 void KMessageServer::removeBrokenClient() 0232 { 0233 KMessageIO *client = sender() ? qobject_cast<KMessageIO *>(sender()) : nullptr; 0234 if (!client) { 0235 qCCritical(KDEGAMESPRIVATE_KGAME_LOG) << ": sender of the signal was not a KMessageIO object!"; 0236 return; 0237 } 0238 0239 Q_EMIT connectionLost(client); 0240 removeClient(client, true); 0241 } 0242 0243 void KMessageServer::setMaxClients(int c) 0244 { 0245 d->mMaxClients = c; 0246 } 0247 0248 int KMessageServer::maxClients() const 0249 { 0250 return d->mMaxClients; 0251 } 0252 0253 int KMessageServer::clientCount() const 0254 { 0255 return d->mClientList.count(); 0256 } 0257 0258 QList<quint32> KMessageServer::clientIDs() const 0259 { 0260 QList<quint32> list; 0261 list.reserve(d->mClientList.size()); 0262 for (QList<KMessageIO *>::iterator iter(d->mClientList.begin()); iter != d->mClientList.end(); ++iter) 0263 list.append((*iter)->id()); 0264 return list; 0265 } 0266 0267 KMessageIO *KMessageServer::findClient(quint32 no) const 0268 { 0269 if (no == 0) 0270 no = d->mAdminID; 0271 0272 QList<KMessageIO *>::iterator iter = d->mClientList.begin(); 0273 while (iter != d->mClientList.end()) { 0274 if ((*iter)->id() == no) 0275 return (*iter); 0276 ++iter; 0277 } 0278 return nullptr; 0279 } 0280 0281 quint32 KMessageServer::adminID() const 0282 { 0283 return d->mAdminID; 0284 } 0285 0286 void KMessageServer::setAdmin(quint32 adminID) 0287 { 0288 // Trying to set the client that is already admin => nothing to do 0289 if (adminID == d->mAdminID) 0290 return; 0291 0292 if (adminID > 0 && findClient(adminID) == nullptr) { 0293 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << "Trying to set a new admin that doesn't exist!"; 0294 return; 0295 } 0296 0297 d->mAdminID = adminID; 0298 0299 QByteArray msg; 0300 QDataStream(&msg, QIODevice::WriteOnly) << quint32(ANS_ADMIN_ID) << adminID; 0301 0302 // Tell everyone about the new master 0303 broadcastMessage(msg); 0304 } 0305 0306 //------------------------------------------- ID stuff 0307 0308 quint32 KMessageServer::uniqueClientNumber() const 0309 { 0310 return d->mUniqueClientNumber++; 0311 } 0312 0313 // --------------------- Messages --------------------------- 0314 0315 void KMessageServer::broadcastMessage(const QByteArray &msg) 0316 { 0317 for (QList<KMessageIO *>::iterator iter(d->mClientList.begin()); iter != d->mClientList.end(); ++iter) 0318 (*iter)->send(msg); 0319 } 0320 0321 void KMessageServer::sendMessage(quint32 id, const QByteArray &msg) 0322 { 0323 KMessageIO *client = findClient(id); 0324 if (client) 0325 client->send(msg); 0326 } 0327 0328 void KMessageServer::sendMessage(const QList<quint32> &ids, const QByteArray &msg) 0329 { 0330 for (quint32 id : ids) { 0331 sendMessage(id, msg); 0332 } 0333 } 0334 0335 void KMessageServer::getReceivedMessage(const QByteArray &msg) 0336 { 0337 KMessageIO *client = sender() ? qobject_cast<KMessageIO *>(sender()) : nullptr; 0338 if (!client) { 0339 qCCritical(KDEGAMESPRIVATE_KGAME_LOG) << ": slot was not called from KMessageIO!"; 0340 return; 0341 } 0342 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": size=" << msg.size(); 0343 quint32 clientID = client->id(); 0344 0345 // QByteArray *ta=new QByteArray; 0346 // ta->duplicate(msg); 0347 // d->mMessageQueue.enqueue (new MessageBuffer (clientID, *ta)); 0348 0349 d->mMessageQueue.enqueue(new MessageBuffer(clientID, msg)); 0350 if (!d->mTimer.isActive()) 0351 d->mTimer.start(0); // AB: should be , TRUE i guess 0352 } 0353 0354 void KMessageServer::processOneMessage() 0355 { 0356 // This shouldn't happen, since the timer should be stopped before. But only to be sure! 0357 if (d->mMessageQueue.isEmpty()) { 0358 d->mTimer.stop(); 0359 return; 0360 } 0361 if (d->mIsRecursive) { 0362 return; 0363 } 0364 d->mIsRecursive = true; 0365 0366 MessageBuffer *msg_buf = d->mMessageQueue.head(); 0367 0368 quint32 clientID = msg_buf->id; 0369 QBuffer in_buffer(&msg_buf->data); 0370 in_buffer.open(QIODevice::ReadOnly); 0371 QDataStream in_stream(&in_buffer); 0372 0373 QByteArray out_msg; 0374 QBuffer out_buffer(&out_msg); 0375 out_buffer.open(QIODevice::WriteOnly); 0376 QDataStream out_stream(&out_buffer); 0377 0378 bool unknown = false; 0379 0380 quint32 messageID; 0381 in_stream >> messageID; 0382 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": got message with messageID=" << messageID; 0383 switch (messageID) { 0384 case REQ_BROADCAST: 0385 out_stream << quint32(MSG_BROADCAST) << clientID; 0386 // FIXME, compiler bug? 0387 // this should be okay, since QBuffer is subclass of QIODevice! : 0388 // out_buffer.write (in_buffer.readAll()); 0389 out_buffer.QIODevice::write(in_buffer.readAll()); 0390 broadcastMessage(out_msg); 0391 break; 0392 0393 case REQ_FORWARD: { 0394 QList<quint32> clients; 0395 in_stream >> clients; 0396 out_stream << quint32(MSG_FORWARD) << clientID << clients; 0397 // see above! 0398 out_buffer.QIODevice::write(in_buffer.readAll()); 0399 sendMessage(clients, out_msg); 0400 } break; 0401 0402 case REQ_CLIENT_ID: 0403 out_stream << quint32(ANS_CLIENT_ID) << clientID; 0404 sendMessage(clientID, out_msg); 0405 break; 0406 0407 case REQ_ADMIN_ID: 0408 out_stream << quint32(ANS_ADMIN_ID) << d->mAdminID; 0409 sendMessage(clientID, out_msg); 0410 break; 0411 0412 case REQ_ADMIN_CHANGE: 0413 if (clientID == d->mAdminID) { 0414 quint32 newAdmin; 0415 in_stream >> newAdmin; 0416 setAdmin(newAdmin); 0417 } 0418 break; 0419 0420 case REQ_REMOVE_CLIENT: 0421 if (clientID == d->mAdminID) { 0422 QList<quint32> client_list; 0423 in_stream >> client_list; 0424 for (quint32 id : std::as_const(client_list)) { 0425 KMessageIO *client = findClient(id); 0426 if (client) 0427 removeClient(client, false); 0428 else 0429 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": removing non-existing clientID"; 0430 } 0431 } 0432 break; 0433 0434 case REQ_MAX_NUM_CLIENTS: 0435 if (clientID == d->mAdminID) { 0436 qint32 maximum_clients; 0437 in_stream >> maximum_clients; 0438 setMaxClients(maximum_clients); 0439 } 0440 break; 0441 0442 case REQ_CLIENT_LIST: { 0443 out_stream << quint32(ANS_CLIENT_LIST) << clientIDs(); 0444 sendMessage(clientID, out_msg); 0445 } break; 0446 0447 default: 0448 unknown = true; 0449 } 0450 0451 // check if all the data has been used 0452 if (!unknown && !in_buffer.atEnd()) 0453 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": Extra data received for message ID" << messageID; 0454 0455 Q_EMIT messageReceived(msg_buf->data, clientID, unknown); 0456 0457 if (unknown) 0458 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": received unknown message ID" << messageID; 0459 0460 // remove the message, since we are ready with it 0461 delete d->mMessageQueue.dequeue(); 0462 if (d->mMessageQueue.isEmpty()) 0463 d->mTimer.stop(); 0464 d->mIsRecursive = false; 0465 } 0466 0467 void KMessageServer::Debug() 0468 { 0469 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "------------------ KMESSAGESERVER -----------------------"; 0470 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "MaxClients : " << maxClients(); 0471 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "NoOfClients : " << clientCount(); 0472 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "---------------------------------------------------"; 0473 } 0474 0475 #include "moc_kmessageserver.cpp" 0476 #include "moc_kmessageserver_p.cpp"