libkdegames Library API Documentation

kmessageserver.cpp

00001 /* 00002 This file is part of the KDE games library 00003 Copyright (C) 2001 Burkhard Lehner (Burkhard.Lehner@gmx.de) 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License version 2 as published by the Free Software Foundation. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include <qiodevice.h> 00021 #include <qbuffer.h> 00022 #include <qptrlist.h> 00023 #include <qptrqueue.h> 00024 #include <qtimer.h> 00025 #include <qvaluelist.h> 00026 00027 #include <kdebug.h> 00028 00029 #include "kmessageio.h" 00030 #include "kmessageserver.h" 00031 00032 // --------------- internal class KMessageServerSocket 00033 00034 KMessageServerSocket::KMessageServerSocket (Q_UINT16 port, QObject *parent) 00035 : QServerSocket (port, 0, parent) 00036 { 00037 } 00038 00039 KMessageServerSocket::~KMessageServerSocket () 00040 { 00041 } 00042 00043 void KMessageServerSocket::newConnection (int socket) 00044 { 00045 emit newClientConnected (new KMessageSocket (socket)); 00046 } 00047 00048 // ---------------- class for storing an incoming message 00049 00050 class MessageBuffer 00051 { 00052 public: 00053 MessageBuffer (Q_UINT32 clientID, const QByteArray &messageData) 00054 : id (clientID), data (messageData) { } 00055 ~MessageBuffer () {} 00056 Q_UINT32 id; 00057 QByteArray data; 00058 }; 00059 00060 // ---------------- KMessageServer's private class 00061 00062 class KMessageServerPrivate 00063 { 00064 public: 00065 KMessageServerPrivate() 00066 : mMaxClients (-1), mGameId (1), mUniqueClientNumber (1), mAdminID (0), mServerSocket (0) 00067 { 00068 mClientList.setAutoDelete (true); 00069 mMessageQueue.setAutoDelete (true); 00070 } 00071 00072 int mMaxClients; 00073 int mGameId; 00074 Q_UINT16 mCookie; 00075 Q_UINT32 mUniqueClientNumber; 00076 Q_UINT32 mAdminID; 00077 00078 KMessageServerSocket* mServerSocket; 00079 00080 QPtrList <KMessageIO> mClientList; 00081 QPtrQueue <MessageBuffer> mMessageQueue; 00082 QTimer mTimer; 00083 bool mIsRecursive; 00084 }; 00085 00086 00087 // ------------------ KMessageServer 00088 00089 KMessageServer::KMessageServer (Q_UINT16 cookie,QObject* parent) 00090 : QObject(parent, 0) 00091 { 00092 d = new KMessageServerPrivate; 00093 d->mIsRecursive=false; 00094 d->mCookie=cookie; 00095 connect (&(d->mTimer), SIGNAL (timeout()), 00096 this, SLOT (processOneMessage())); 00097 kdDebug(11001) << "CREATE(KMessageServer=" 00098 << this 00099 << ") cookie=" 00100 << d->mCookie 00101 << " sizeof(this)=" 00102 << sizeof(KMessageServer) 00103 << endl; 00104 } 00105 00106 KMessageServer::~KMessageServer() 00107 { 00108 kdDebug(11001) << k_funcinfo << "this=" << this << endl; 00109 Debug(); 00110 stopNetwork(); 00111 deleteClients(); 00112 delete d; 00113 kdDebug(11001) << k_funcinfo << " done" << endl; 00114 } 00115 00116 //------------------------------------- TCP/IP server stuff 00117 00118 bool KMessageServer::initNetwork (Q_UINT16 port) 00119 { 00120 kdDebug(11001) << k_funcinfo << endl; 00121 00122 if (d->mServerSocket) 00123 { 00124 kdDebug (11001) << k_funcinfo << ": We were already offering connections!" << endl; 00125 delete d->mServerSocket; 00126 } 00127 00128 d->mServerSocket = new KMessageServerSocket (port); 00129 d->mIsRecursive = false; 00130 00131 if (!d->mServerSocket || !d->mServerSocket->ok()) 00132 { 00133 kdError(11001) << k_funcinfo << ": Serversocket::ok() == false" << endl; 00134 delete d->mServerSocket; 00135 d->mServerSocket=0; 00136 return false; 00137 } 00138 00139 kdDebug (11001) << k_funcinfo << ": Now listening to port " 00140 << d->mServerSocket->port() << endl; 00141 connect (d->mServerSocket, SIGNAL (newClientConnected (KMessageIO*)), 00142 this, SLOT (addClient (KMessageIO*))); 00143 return true; 00144 } 00145 00146 Q_UINT16 KMessageServer::serverPort () const 00147 { 00148 if (d->mServerSocket) 00149 return d->mServerSocket->port(); 00150 else 00151 return 0; 00152 } 00153 00154 void KMessageServer::stopNetwork() 00155 { 00156 if (d->mServerSocket) 00157 { 00158 delete d->mServerSocket; 00159 d->mServerSocket = 0; 00160 } 00161 } 00162 00163 bool KMessageServer::isOfferingConnections() const 00164 { 00165 return d->mServerSocket != 0; 00166 } 00167 00168 //----------------------------------------------- adding / removing clients 00169 00170 void KMessageServer::addClient (KMessageIO* client) 00171 { 00172 QByteArray msg; 00173 00174 // maximum number of clients reached? 00175 if (d->mMaxClients >= 0 && d->mMaxClients <= clientCount()) 00176 { 00177 kdError (11001) << k_funcinfo << ": Maximum number of clients reached!" << endl; 00178 return; 00179 } 00180 00181 // give it a unique ID 00182 client->setId (uniqueClientNumber()); 00183 kdDebug (11001) << k_funcinfo << ": " << client->id() << endl; 00184 00185 // connect its signals 00186 connect (client, SIGNAL (connectionBroken()), 00187 this, SLOT (removeBrokenClient())); 00188 connect (client, SIGNAL (received (const QByteArray &)), 00189 this, SLOT (getReceivedMessage (const QByteArray &))); 00190 00191 // Tell everyone about the new guest 00192 // Note: The new client doesn't get this message! 00193 QDataStream (msg, IO_WriteOnly) << Q_UINT32 (EVNT_CLIENT_CONNECTED) << client->id(); 00194 broadcastMessage (msg); 00195 00196 // add to our list 00197 d->mClientList.append (client); 00198 00199 // tell it its ID 00200 QDataStream (msg, IO_WriteOnly) << Q_UINT32 (ANS_CLIENT_ID) << client->id(); 00201 client->send (msg); 00202 00203 // Give it the complete list of client IDs 00204 QDataStream (msg, IO_WriteOnly) << Q_UINT32 (ANS_CLIENT_LIST) << clientIDs(); 00205 client->send (msg); 00206 00207 00208 if (clientCount() == 1) 00209 { 00210 // if it is the first client, it becomes the admin 00211 setAdmin (client->id()); 00212 } 00213 else 00214 { 00215 // otherwise tell it who is the admin 00216 QDataStream (msg, IO_WriteOnly) << Q_UINT32 (ANS_ADMIN_ID) << adminID(); 00217 client->send (msg); 00218 } 00219 00220 emit clientConnected (client); 00221 } 00222 00223 void KMessageServer::removeClient (KMessageIO* client, bool broken) 00224 { 00225 Q_UINT32 clientID = client->id(); 00226 if (!d->mClientList.removeRef (client)) 00227 { 00228 kdError(11001) << k_funcinfo << ": Deleting client that wasn't added before!" << endl; 00229 return; 00230 } 00231 00232 // tell everyone about the removed client 00233 QByteArray msg; 00234 QDataStream (msg, IO_WriteOnly) << Q_UINT32 (EVNT_CLIENT_DISCONNECTED) << client->id() << (Q_INT8)broken; 00235 broadcastMessage (msg); 00236 00237 // If it was the admin, select a new admin. 00238 if (clientID == adminID()) 00239 { 00240 if (!d->mClientList.isEmpty()) 00241 setAdmin (d->mClientList.first()->id()); 00242 else 00243 setAdmin (0); 00244 } 00245 } 00246 00247 void KMessageServer::deleteClients() 00248 { 00249 d->mClientList.clear(); 00250 d->mAdminID = 0; 00251 } 00252 00253 void KMessageServer::removeBrokenClient () 00254 { 00255 if (!sender()->inherits ("KMessageIO")) 00256 { 00257 kdError (11001) << k_funcinfo << ": sender of the signal was not a KMessageIO object!" << endl; 00258 return; 00259 } 00260 00261 KMessageIO *client = (KMessageIO *) sender(); 00262 00263 emit connectionLost (client); 00264 removeClient (client, true); 00265 } 00266 00267 00268 void KMessageServer::setMaxClients(int c) 00269 { 00270 d->mMaxClients = c; 00271 } 00272 00273 int KMessageServer::maxClients() const 00274 { 00275 return d->mMaxClients; 00276 } 00277 00278 int KMessageServer::clientCount() const 00279 { 00280 return d->mClientList.count(); 00281 } 00282 00283 QValueList <Q_UINT32> KMessageServer::clientIDs () const 00284 { 00285 QValueList <Q_UINT32> list; 00286 for (QPtrListIterator <KMessageIO> iter (d->mClientList); *iter; ++iter) 00287 list.append ((*iter)->id()); 00288 return list; 00289 } 00290 00291 KMessageIO* KMessageServer::findClient (Q_UINT32 no) const 00292 { 00293 if (no == 0) 00294 no = d->mAdminID; 00295 00296 QPtrListIterator <KMessageIO> iter (d->mClientList); 00297 while (*iter) 00298 { 00299 if ((*iter)->id() == no) 00300 return (*iter); 00301 ++iter; 00302 } 00303 return 0; 00304 } 00305 00306 Q_UINT32 KMessageServer::adminID () const 00307 { 00308 return d->mAdminID; 00309 } 00310 00311 void KMessageServer::setAdmin (Q_UINT32 adminID) 00312 { 00313 // Trying to set the the client that is already admin => nothing to do 00314 if (adminID == d->mAdminID) 00315 return; 00316 00317 if (adminID > 0 && findClient (adminID) == 0) 00318 { 00319 kdWarning (11001) << "Trying to set a new admin that doesn't exist!" << endl; 00320 return; 00321 } 00322 00323 d->mAdminID = adminID; 00324 00325 QByteArray msg; 00326 QDataStream (msg, IO_WriteOnly) << Q_UINT32 (ANS_ADMIN_ID) << adminID; 00327 00328 // Tell everyone about the new master 00329 broadcastMessage (msg); 00330 } 00331 00332 00333 //------------------------------------------- ID stuff 00334 00335 Q_UINT32 KMessageServer::uniqueClientNumber() const 00336 { 00337 return d->mUniqueClientNumber++; 00338 } 00339 00340 // --------------------- Messages --------------------------- 00341 00342 void KMessageServer::broadcastMessage (const QByteArray &msg) 00343 { 00344 for (QPtrListIterator <KMessageIO> iter (d->mClientList); *iter; ++iter) 00345 (*iter)->send (msg); 00346 } 00347 00348 void KMessageServer::sendMessage (Q_UINT32 id, const QByteArray &msg) 00349 { 00350 KMessageIO *client = findClient (id); 00351 if (client) 00352 client->send (msg); 00353 } 00354 00355 void KMessageServer::sendMessage (const QValueList <Q_UINT32> &ids, const QByteArray &msg) 00356 { 00357 for (QValueListConstIterator <Q_UINT32> iter = ids.begin(); iter != ids.end(); ++iter) 00358 sendMessage (*iter, msg); 00359 } 00360 00361 void KMessageServer::getReceivedMessage (const QByteArray &msg) 00362 { 00363 if (!sender() || !sender()->inherits("KMessageIO")) 00364 { 00365 kdError (11001) << k_funcinfo << ": slot was not called from KMessageIO!" << endl; 00366 return; 00367 } 00368 //kdDebug(11001) << k_funcinfo << ": size=" << msg.size() << endl; 00369 KMessageIO *client = (KMessageIO *) sender(); 00370 Q_UINT32 clientID = client->id(); 00371 00372 //QByteArray *ta=new QByteArray; 00373 //ta->duplicate(msg); 00374 //d->mMessageQueue.enqueue (new MessageBuffer (clientID, *ta)); 00375 00376 00377 d->mMessageQueue.enqueue (new MessageBuffer (clientID, msg)); 00378 if (!d->mTimer.isActive()) 00379 d->mTimer.start(0); // AB: should be , TRUE i guess 00380 } 00381 00382 void KMessageServer::processOneMessage () 00383 { 00384 // This shouldn't happen, since the timer should be stopped before. But only to be sure! 00385 if (d->mMessageQueue.isEmpty()) 00386 { 00387 d->mTimer.stop(); 00388 return; 00389 } 00390 if (d->mIsRecursive) 00391 { 00392 return; 00393 } 00394 d->mIsRecursive = true; 00395 00396 MessageBuffer *msg_buf = d->mMessageQueue.head(); 00397 00398 Q_UINT32 clientID = msg_buf->id; 00399 QBuffer in_buffer (msg_buf->data); 00400 in_buffer.open (IO_ReadOnly); 00401 QDataStream in_stream (&in_buffer); 00402 00403 QByteArray out_msg; 00404 QBuffer out_buffer (out_msg); 00405 out_buffer.open (IO_WriteOnly); 00406 QDataStream out_stream (&out_buffer); 00407 00408 bool unknown = false; 00409 00410 QByteArray ttt=in_buffer.buffer(); 00411 Q_UINT32 messageID; 00412 in_stream >> messageID; 00413 //kdDebug(11001) << k_funcinfo << ": got message with messageID=" << messageID << endl; 00414 switch (messageID) 00415 { 00416 case REQ_BROADCAST: 00417 out_stream << Q_UINT32 (MSG_BROADCAST) << clientID; 00418 // FIXME, compiler bug? 00419 // this should be okay, since QBuffer is subclass of QIODevice! : 00420 // out_buffer.writeBlock (in_buffer.readAll()); 00421 out_buffer.QIODevice::writeBlock (in_buffer.readAll()); 00422 broadcastMessage (out_msg); 00423 break; 00424 00425 case REQ_FORWARD: 00426 { 00427 QValueList <Q_UINT32> clients; 00428 in_stream >> clients; 00429 out_stream << Q_UINT32 (MSG_FORWARD) << clientID << clients; 00430 // see above! 00431 out_buffer.QIODevice::writeBlock (in_buffer.readAll()); 00432 sendMessage (clients, out_msg); 00433 } 00434 break; 00435 00436 case REQ_CLIENT_ID: 00437 out_stream << Q_UINT32 (ANS_CLIENT_ID) << clientID; 00438 sendMessage (clientID, out_msg); 00439 break; 00440 00441 case REQ_ADMIN_ID: 00442 out_stream << Q_UINT32 (ANS_ADMIN_ID) << d->mAdminID; 00443 sendMessage (clientID, out_msg); 00444 break; 00445 00446 case REQ_ADMIN_CHANGE: 00447 if (clientID == d->mAdminID) 00448 { 00449 Q_UINT32 newAdmin; 00450 in_stream >> newAdmin; 00451 setAdmin (newAdmin); 00452 } 00453 break; 00454 00455 case REQ_REMOVE_CLIENT: 00456 if (clientID == d->mAdminID) 00457 { 00458 QValueList <Q_UINT32> client_list; 00459 in_stream >> client_list; 00460 for (QValueListIterator <Q_UINT32> iter = client_list.begin(); iter != client_list.end(); ++iter) 00461 { 00462 KMessageIO *client = findClient (*iter); 00463 if (client) 00464 removeClient (client, false); 00465 else 00466 kdWarning (11001) << k_funcinfo << ": removing non-existing clientID" << endl; 00467 } 00468 } 00469 break; 00470 00471 case REQ_MAX_NUM_CLIENTS: 00472 if (clientID == d->mAdminID) 00473 { 00474 Q_INT32 maximum_clients; 00475 in_stream >> maximum_clients; 00476 setMaxClients (maximum_clients); 00477 } 00478 break; 00479 00480 case REQ_CLIENT_LIST: 00481 { 00482 out_stream << Q_UINT32 (ANS_CLIENT_LIST) << clientIDs(); 00483 sendMessage (clientID, out_msg); 00484 } 00485 break; 00486 00487 default: 00488 unknown = true; 00489 } 00490 00491 // check if all the data has been used 00492 if (!unknown && !in_buffer.atEnd()) 00493 kdWarning (11001) << k_funcinfo << ": Extra data received for message ID " << messageID << endl; 00494 00495 emit messageReceived (msg_buf->data, clientID, unknown); 00496 00497 if (unknown) 00498 kdWarning (11001) << k_funcinfo << ": received unknown message ID " << messageID << endl; 00499 00500 // remove the message, since we are ready with it 00501 d->mMessageQueue.remove(); 00502 if (d->mMessageQueue.isEmpty()) 00503 d->mTimer.stop(); 00504 d->mIsRecursive = false; 00505 } 00506 00507 void KMessageServer::Debug() 00508 { 00509 kdDebug(11001) << "------------------ KMESSAGESERVER -----------------------" << endl; 00510 kdDebug(11001) << "MaxClients : " << maxClients() << endl; 00511 kdDebug(11001) << "NoOfClients : " << clientCount() << endl; 00512 kdDebug(11001) << "---------------------------------------------------" << endl; 00513 } 00514 00515 #include "kmessageserver.moc"
KDE Logo
This file is part of the documentation for libkdegames Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 13 12:48:56 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003