File indexing completed on 2024-06-16 03:57:56
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 "kmessageclient.h" 0009 0010 // own 0011 #include "kmessageio.h" 0012 #include "kmessageserver.h" 0013 #include <kdegamesprivate_kgame_logging.h> 0014 // Qt 0015 #include <QBuffer> 0016 #include <QDataStream> 0017 #include <QList> 0018 #include <QTimer> 0019 // Std 0020 #include <cstdio> 0021 0022 class KMessageClientPrivate 0023 { 0024 public: 0025 KMessageClientPrivate() = default; 0026 0027 ~KMessageClientPrivate() 0028 { 0029 delete connection; 0030 } 0031 0032 public: 0033 quint32 adminID = 0; 0034 QList<quint32> clientList; 0035 KMessageIO *connection = nullptr; 0036 0037 bool isLocked = false; 0038 QList<QByteArray> delayedMessages; 0039 }; 0040 0041 KMessageClient::KMessageClient(QObject *parent) 0042 : QObject(parent) 0043 , d(new KMessageClientPrivate) 0044 { 0045 } 0046 0047 KMessageClient::~KMessageClient() 0048 { 0049 d->delayedMessages.clear(); 0050 } 0051 0052 // -- setServer stuff 0053 0054 void KMessageClient::setServer(const QString &host, quint16 port) 0055 { 0056 setServer(new KMessageSocket(host, port)); 0057 } 0058 0059 void KMessageClient::setServer(KMessageServer *server) 0060 { 0061 KMessageDirect *serverIO = new KMessageDirect(); 0062 setServer(new KMessageDirect(serverIO)); 0063 server->addClient(serverIO); 0064 } 0065 0066 void KMessageClient::setServer(KMessageIO *connection) 0067 { 0068 if (d->connection) { 0069 delete d->connection; 0070 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": We are changing the server!"; 0071 } 0072 0073 d->connection = connection; 0074 if (connection) { 0075 connect(connection, &KMessageIO::received, this, &KMessageClient::processIncomingMessage); 0076 connect(connection, &KMessageIO::connectionBroken, this, &KMessageClient::removeBrokenConnection); 0077 } 0078 } 0079 0080 // -- id stuff 0081 0082 quint32 KMessageClient::id() const 0083 { 0084 return (d->connection) ? d->connection->id() : 0; 0085 } 0086 0087 bool KMessageClient::isAdmin() const 0088 { 0089 return id() != 0 && id() == adminId(); 0090 } 0091 0092 quint32 KMessageClient::adminId() const 0093 { 0094 return d->adminID; 0095 } 0096 0097 QList<quint32> KMessageClient::clientList() const 0098 { 0099 return d->clientList; 0100 } 0101 0102 bool KMessageClient::isConnected() const 0103 { 0104 return d->connection && d->connection->isConnected(); 0105 } 0106 0107 bool KMessageClient::isNetwork() const 0108 { 0109 return isConnected() ? d->connection->isNetwork() : false; 0110 } 0111 0112 quint16 KMessageClient::peerPort() const 0113 { 0114 return d->connection ? d->connection->peerPort() : 0; 0115 } 0116 0117 QString KMessageClient::peerName() const 0118 { 0119 return d->connection ? d->connection->peerName() : QStringLiteral("localhost"); 0120 } 0121 0122 // --------------------- Sending messages 0123 0124 void KMessageClient::sendServerMessage(const QByteArray &msg) 0125 { 0126 if (!d->connection) { 0127 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": We have no connection yet!"; 0128 return; 0129 } 0130 d->connection->send(msg); 0131 } 0132 0133 void KMessageClient::sendBroadcast(const QByteArray &msg) 0134 { 0135 QByteArray sendBuffer; 0136 QBuffer buffer(&sendBuffer); 0137 buffer.open(QIODevice::WriteOnly); 0138 QDataStream stream(&buffer); 0139 0140 stream << static_cast<quint32>(KMessageServer::REQ_BROADCAST); 0141 buffer.QIODevice::write(msg); 0142 sendServerMessage(sendBuffer); 0143 } 0144 0145 void KMessageClient::sendForward(const QByteArray &msg, const QList<quint32> &clients) 0146 { 0147 QByteArray sendBuffer; 0148 QBuffer buffer(&sendBuffer); 0149 buffer.open(QIODevice::WriteOnly); 0150 QDataStream stream(&buffer); 0151 0152 stream << static_cast<quint32>(KMessageServer::REQ_FORWARD) << clients; 0153 buffer.QIODevice::write(msg); 0154 sendServerMessage(sendBuffer); 0155 } 0156 0157 void KMessageClient::sendForward(const QByteArray &msg, quint32 client) 0158 { 0159 sendForward(msg, QList<quint32>{client}); 0160 } 0161 0162 // --------------------- Receiving and processing messages 0163 0164 void KMessageClient::processIncomingMessage(const QByteArray &msg) 0165 { 0166 if (d->isLocked) { 0167 d->delayedMessages.append(msg); 0168 return; 0169 } 0170 if (!d->delayedMessages.isEmpty()) { 0171 d->delayedMessages.append(msg); 0172 QByteArray first = d->delayedMessages.front(); 0173 d->delayedMessages.pop_front(); 0174 processMessage(first); 0175 } else { 0176 processMessage(msg); 0177 } 0178 } 0179 0180 void KMessageClient::processMessage(const QByteArray &msg) 0181 { 0182 if (d->isLocked) { // must NOT happen, since we check in processIncomingMessage as well as in processFirstMessage 0183 d->delayedMessages.append(msg); 0184 return; 0185 } 0186 QBuffer in_buffer; 0187 in_buffer.setData(msg); 0188 in_buffer.open(QIODevice::ReadOnly); 0189 QDataStream in_stream(&in_buffer); 0190 0191 bool unknown = false; 0192 0193 quint32 messageID; 0194 in_stream >> messageID; 0195 switch (messageID) { 0196 case KMessageServer::MSG_BROADCAST: { 0197 quint32 clientID; 0198 in_stream >> clientID; 0199 Q_EMIT broadcastReceived(in_buffer.readAll(), clientID); 0200 } break; 0201 0202 case KMessageServer::MSG_FORWARD: { 0203 quint32 clientID; 0204 QList<quint32> receivers; 0205 in_stream >> clientID >> receivers; 0206 Q_EMIT forwardReceived(in_buffer.readAll(), clientID, receivers); 0207 } break; 0208 0209 case KMessageServer::ANS_CLIENT_ID: { 0210 bool old_admin = isAdmin(); 0211 quint32 clientID; 0212 in_stream >> clientID; 0213 d->connection->setId(clientID); 0214 if (old_admin != isAdmin()) 0215 Q_EMIT adminStatusChanged(isAdmin()); 0216 } break; 0217 0218 case KMessageServer::ANS_ADMIN_ID: { 0219 bool old_admin = isAdmin(); 0220 in_stream >> d->adminID; 0221 if (old_admin != isAdmin()) 0222 Q_EMIT adminStatusChanged(isAdmin()); 0223 } break; 0224 0225 case KMessageServer::ANS_CLIENT_LIST: { 0226 in_stream >> d->clientList; 0227 } break; 0228 0229 case KMessageServer::EVNT_CLIENT_CONNECTED: { 0230 quint32 id; 0231 in_stream >> id; 0232 0233 if (d->clientList.contains(id)) 0234 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": Adding a client that already existed!"; 0235 else 0236 d->clientList.append(id); 0237 0238 Q_EMIT eventClientConnected(id); 0239 } break; 0240 0241 case KMessageServer::EVNT_CLIENT_DISCONNECTED: { 0242 quint32 id; 0243 qint8 broken; 0244 in_stream >> id >> broken; 0245 0246 if (!d->clientList.contains(id)) 0247 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": Removing a client that doesn't exist!"; 0248 else 0249 d->clientList.removeAll(id); 0250 0251 Q_EMIT eventClientDisconnected(id, bool(broken)); 0252 } break; 0253 0254 default: 0255 unknown = true; 0256 } 0257 0258 if (!unknown && !in_buffer.atEnd()) 0259 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": Extra data received for message ID" << messageID; 0260 0261 Q_EMIT serverMessageReceived(msg, unknown); 0262 0263 if (unknown) 0264 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": received unknown message ID" << messageID; 0265 } 0266 0267 void KMessageClient::processFirstMessage() 0268 { 0269 if (d->isLocked) { 0270 return; 0271 } 0272 if (d->delayedMessages.count() == 0) { 0273 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": no messages delayed"; 0274 return; 0275 } 0276 QByteArray first = d->delayedMessages.front(); 0277 d->delayedMessages.pop_front(); 0278 processMessage(first); 0279 } 0280 0281 void KMessageClient::removeBrokenConnection() 0282 { 0283 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": timer single shot for removeBrokenConnection" << this; 0284 // MH We cannot directly delete the socket. otherwise QSocket crashes 0285 QTimer::singleShot(0, this, &KMessageClient::removeBrokenConnection2); 0286 return; 0287 } 0288 0289 void KMessageClient::removeBrokenConnection2() 0290 { 0291 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": Broken:Deleting the connection object" << this; 0292 0293 Q_EMIT aboutToDisconnect(id()); 0294 delete d->connection; 0295 d->connection = nullptr; 0296 d->adminID = 0; 0297 Q_EMIT connectionBroken(); 0298 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": Broken:Deleting the connection object DONE"; 0299 } 0300 0301 void KMessageClient::disconnect() 0302 { 0303 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": Disconnect:Deleting the connection object"; 0304 0305 Q_EMIT aboutToDisconnect(id()); 0306 delete d->connection; 0307 d->connection = nullptr; 0308 d->adminID = 0; 0309 Q_EMIT connectionBroken(); 0310 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": Disconnect:Deleting the connection object DONE"; 0311 } 0312 0313 void KMessageClient::lock() 0314 { 0315 d->isLocked = true; 0316 } 0317 0318 void KMessageClient::unlock() 0319 { 0320 d->isLocked = false; 0321 for (int i = 0; i < d->delayedMessages.count(); i++) { 0322 QTimer::singleShot(0, this, &KMessageClient::processFirstMessage); 0323 } 0324 } 0325 0326 unsigned int KMessageClient::delayedMessageCount() const 0327 { 0328 return d->delayedMessages.count(); 0329 } 0330 0331 #include "moc_kmessageclient.cpp"