kmessageserver.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00017     Boston, MA 02110-1301, 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"

Generated on Wed Aug 23 18:04:18 2006 for libkdegames by  doxygen 1.4.6