• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdegames API Reference
  • KDE Home
  • Contact Us
 

libkdegames/libkdegamesprivate/kgame

  • sources
  • kde-4.14
  • kdegames
  • libkdegames
  • libkdegamesprivate
  • kgame
kmessageserver.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the KDE games library
3  Copyright (C) 2001 Burkhard Lehner (Burkhard.Lehner@gmx.de)
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "kmessageserver.h"
21 #include "kmessageserver_p.h"
22 
23 #include <qiodevice.h>
24 #include <qbuffer.h>
25 #include <QList>
26 #include <QQueue>
27 #include <QTimer>
28 #include <QDataStream>
29 
30 #include <kdebug.h>
31 
32 #include "kmessageio.h"
33 
34 // --------------- internal class KMessageServerSocket
35 
36 KMessageServerSocket::KMessageServerSocket (quint16 port, QObject *parent)
37  : QTcpServer (parent)
38 {
39  listen ( QHostAddress::Any, port );
40  connect(this,SIGNAL(newConnection()),this,SLOT(slotNewConnection()));
41 }
42 
43 
44 KMessageServerSocket::~KMessageServerSocket ()
45 {
46 }
47 
48 void KMessageServerSocket::slotNewConnection ()
49 {
50  if (hasPendingConnections())
51  {
52  emit newClientConnected (new KMessageSocket (nextPendingConnection()));
53  }
54 }
55 
56 // ---------------- class for storing an incoming message
57 
58 class MessageBuffer
59 {
60  public:
61  MessageBuffer (quint32 clientID, const QByteArray &messageData)
62  : id (clientID), data (messageData) { }
63  ~MessageBuffer () {}
64  quint32 id;
65  QByteArray data;
66 };
67 
68 // ---------------- KMessageServer's private class
69 
70 class KMessageServerPrivate
71 {
72 public:
73  KMessageServerPrivate()
74  : mMaxClients (-1), mGameId (1), mUniqueClientNumber (1), mAdminID (0), mServerSocket (0) {}
75 
76  ~KMessageServerPrivate()
77  {
78  qDeleteAll(mClientList);
79  qDeleteAll(mMessageQueue);
80  }
81 
82  int mMaxClients;
83  int mGameId;
84  quint16 mCookie;
85  quint32 mUniqueClientNumber;
86  quint32 mAdminID;
87 
88  KMessageServerSocket* mServerSocket;
89 
90  QList<KMessageIO*> mClientList;
91  QQueue <MessageBuffer*> mMessageQueue;
92  QTimer mTimer;
93  bool mIsRecursive;
94 };
95 
96 
97 // ------------------ KMessageServer
98 
99 KMessageServer::KMessageServer (quint16 cookie,QObject* parent)
100  : QObject(parent)
101 {
102  d = new KMessageServerPrivate;
103  d->mIsRecursive=false;
104  d->mCookie=cookie;
105  connect (&(d->mTimer), SIGNAL (timeout()),
106  this, SLOT (processOneMessage()));
107  kDebug(11001) << "CREATE(KMessageServer="
108  << this
109  << ") cookie="
110  << d->mCookie
111  << "sizeof(this)="
112  << sizeof(KMessageServer);
113 }
114 
115 KMessageServer::~KMessageServer()
116 {
117  kDebug(11001) << "this=" << this;
118  Debug();
119  stopNetwork();
120  deleteClients();
121  delete d;
122  kDebug(11001) << "done";
123 }
124 
125 //------------------------------------- TCP/IP server stuff
126 
127 bool KMessageServer::initNetwork (quint16 port)
128 {
129  kDebug(11001) ;
130 
131  if (d->mServerSocket)
132  {
133  kDebug (11001) << ": We were already offering connections!";
134  delete d->mServerSocket;
135  }
136 
137  d->mServerSocket = new KMessageServerSocket (port);
138  d->mIsRecursive = false;
139 
140  if (!d->mServerSocket
141  || !d->mServerSocket->isListening())
142  {
143  kError(11001) << ": Serversocket::ok() == false";
144  delete d->mServerSocket;
145  d->mServerSocket=0;
146  return false;
147  }
148 
149  kDebug (11001) << ": Now listening to port "
150  << d->mServerSocket->serverPort();
151  connect (d->mServerSocket, SIGNAL (newClientConnected(KMessageIO*)),
152  this, SLOT (addClient(KMessageIO*)));
153  return true;
154 }
155 
156 quint16 KMessageServer::serverPort () const
157 {
158  if (d->mServerSocket)
159  return d->mServerSocket->serverPort();
160  else
161  return 0;
162 }
163 
164 void KMessageServer::stopNetwork()
165 {
166  if (d->mServerSocket)
167  {
168  delete d->mServerSocket;
169  d->mServerSocket = 0;
170  }
171 }
172 
173 bool KMessageServer::isOfferingConnections() const
174 {
175  return d->mServerSocket != 0;
176 }
177 
178 //----------------------------------------------- adding / removing clients
179 
180 void KMessageServer::addClient (KMessageIO* client)
181 {
182  QByteArray msg;
183 
184  // maximum number of clients reached?
185  if (d->mMaxClients >= 0 && d->mMaxClients <= clientCount())
186  {
187  kError (11001) << ": Maximum number of clients reached!";
188  return;
189  }
190 
191  // give it a unique ID
192  client->setId (uniqueClientNumber());
193  kDebug (11001) << ":" << client->id();
194 
195  // connect its signals
196  connect (client, SIGNAL (connectionBroken()),
197  this, SLOT (removeBrokenClient()));
198  connect (client, SIGNAL (received(QByteArray)),
199  this, SLOT (getReceivedMessage(QByteArray)));
200 
201  // Tell everyone about the new guest
202  // Note: The new client doesn't get this message!
203  QDataStream (&msg, QIODevice::WriteOnly) << quint32 (EVNT_CLIENT_CONNECTED) << client->id();
204  broadcastMessage (msg);
205 
206  // add to our list
207  d->mClientList.push_back(client);
208 
209  // tell it its ID
210  QDataStream (&msg, QIODevice::WriteOnly) << quint32 (ANS_CLIENT_ID) << client->id();
211  client->send (msg);
212 
213  // Give it the complete list of client IDs
214  QDataStream (&msg, QIODevice::WriteOnly) << quint32 (ANS_CLIENT_LIST) << clientIDs();
215  client->send (msg);
216 
217 
218  if (clientCount() == 1)
219  {
220  // if it is the first client, it becomes the admin
221  setAdmin (client->id());
222  }
223  else
224  {
225  // otherwise tell it who is the admin
226  QDataStream (&msg, QIODevice::WriteOnly) << quint32 (ANS_ADMIN_ID) << adminID();
227  client->send (msg);
228  }
229 
230  emit clientConnected (client);
231 }
232 
233 void KMessageServer::removeClient (KMessageIO* client, bool broken)
234 {
235  quint32 clientID = client->id();
236  if (!d->mClientList.removeAll(client))
237  {
238  kError(11001) << ": Deleting client that wasn't added before!";
239  return;
240  }
241 
242  // tell everyone about the removed client
243  QByteArray msg;
244  QDataStream (&msg, QIODevice::WriteOnly) << quint32 (EVNT_CLIENT_DISCONNECTED) << client->id() << (qint8)broken;
245  broadcastMessage (msg);
246 
247  // If it was the admin, select a new admin.
248  if (clientID == adminID())
249  {
250  if (!d->mClientList.isEmpty())
251  setAdmin (d->mClientList.front()->id());
252  else
253  setAdmin (0);
254  }
255 }
256 
257 void KMessageServer::deleteClients()
258 {
259  qDeleteAll(d->mClientList);
260  d->mClientList.clear();
261  d->mAdminID = 0;
262 }
263 
264 void KMessageServer::removeBrokenClient ()
265 {
266  KMessageIO *client = sender() ? qobject_cast<KMessageIO*>(sender()) : 0;
267  if (!client)
268  {
269  kError (11001) << ": sender of the signal was not a KMessageIO object!";
270  return;
271  }
272 
273  emit connectionLost (client);
274  removeClient (client, true);
275 }
276 
277 
278 void KMessageServer::setMaxClients(int c)
279 {
280  d->mMaxClients = c;
281 }
282 
283 int KMessageServer::maxClients() const
284 {
285  return d->mMaxClients;
286 }
287 
288 int KMessageServer::clientCount() const
289 {
290  return d->mClientList.count();
291 }
292 
293 QList <quint32> KMessageServer::clientIDs () const
294 {
295  QList <quint32> list;
296  for (QList<KMessageIO*>::iterator iter(d->mClientList.begin()); iter!=d->mClientList.end(); ++iter)
297  list.append ((*iter)->id());
298  return list;
299 }
300 
301 KMessageIO* KMessageServer::findClient (quint32 no) const
302 {
303  if (no == 0)
304  no = d->mAdminID;
305 
306  QList<KMessageIO*>::iterator iter = d->mClientList.begin();
307  while (iter!=d->mClientList.end())
308  {
309  if ((*iter)->id() == no)
310  return (*iter);
311  ++iter;
312  }
313  return 0;
314 }
315 
316 quint32 KMessageServer::adminID () const
317 {
318  return d->mAdminID;
319 }
320 
321 void KMessageServer::setAdmin (quint32 adminID)
322 {
323  // Trying to set the client that is already admin => nothing to do
324  if (adminID == d->mAdminID)
325  return;
326 
327  if (adminID > 0 && findClient (adminID) == 0)
328  {
329  kWarning (11001) << "Trying to set a new admin that doesn't exist!";
330  return;
331  }
332 
333  d->mAdminID = adminID;
334 
335  QByteArray msg;
336  QDataStream (&msg, QIODevice::WriteOnly) << quint32 (ANS_ADMIN_ID) << adminID;
337 
338  // Tell everyone about the new master
339  broadcastMessage (msg);
340 }
341 
342 
343 //------------------------------------------- ID stuff
344 
345 quint32 KMessageServer::uniqueClientNumber() const
346 {
347  return d->mUniqueClientNumber++;
348 }
349 
350 // --------------------- Messages ---------------------------
351 
352 void KMessageServer::broadcastMessage (const QByteArray &msg)
353 {
354  for (QList<KMessageIO*>::iterator iter (d->mClientList.begin()); iter!=d->mClientList.end(); ++iter)
355  (*iter)->send (msg);
356 }
357 
358 void KMessageServer::sendMessage (quint32 id, const QByteArray &msg)
359 {
360  KMessageIO *client = findClient (id);
361  if (client)
362  client->send (msg);
363 }
364 
365 void KMessageServer::sendMessage (const QList <quint32> &ids, const QByteArray &msg)
366 {
367  for (QList<quint32>::ConstIterator iter = ids.begin(); iter != ids.end(); ++iter)
368  sendMessage (*iter, msg);
369 }
370 
371 void KMessageServer::getReceivedMessage (const QByteArray &msg)
372 {
373  KMessageIO *client = sender() ? qobject_cast<KMessageIO*>(sender()) : 0;
374  if (!client)
375  {
376  kError (11001) << ": slot was not called from KMessageIO!";
377  return;
378  }
379  //kDebug(11001) << ": size=" << msg.size();
380  quint32 clientID = client->id();
381 
382  //QByteArray *ta=new QByteArray;
383  //ta->duplicate(msg);
384  //d->mMessageQueue.enqueue (new MessageBuffer (clientID, *ta));
385 
386 
387  d->mMessageQueue.enqueue (new MessageBuffer (clientID, msg));
388  if (!d->mTimer.isActive())
389  d->mTimer.start(0); // AB: should be , TRUE i guess
390 }
391 
392 void KMessageServer::processOneMessage ()
393 {
394  // This shouldn't happen, since the timer should be stopped before. But only to be sure!
395  if (d->mMessageQueue.isEmpty())
396  {
397  d->mTimer.stop();
398  return;
399  }
400  if (d->mIsRecursive)
401  {
402  return;
403  }
404  d->mIsRecursive = true;
405 
406  MessageBuffer *msg_buf = d->mMessageQueue.head();
407 
408  quint32 clientID = msg_buf->id;
409  QBuffer in_buffer (&msg_buf->data);
410  in_buffer.open (QIODevice::ReadOnly);
411  QDataStream in_stream (&in_buffer);
412 
413  QByteArray out_msg;
414  QBuffer out_buffer (&out_msg);
415  out_buffer.open (QIODevice::WriteOnly);
416  QDataStream out_stream (&out_buffer);
417 
418  bool unknown = false;
419 
420  QByteArray ttt=in_buffer.buffer();
421  quint32 messageID;
422  in_stream >> messageID;
423  //kDebug(11001) << ": got message with messageID=" << messageID;
424  switch (messageID)
425  {
426  case REQ_BROADCAST:
427  out_stream << quint32 (MSG_BROADCAST) << clientID;
428  // FIXME, compiler bug?
429  // this should be okay, since QBuffer is subclass of QIODevice! :
430  // out_buffer.write (in_buffer.readAll());
431  out_buffer.QIODevice::write (in_buffer.readAll());
432  broadcastMessage (out_msg);
433  break;
434 
435  case REQ_FORWARD:
436  {
437  QList <quint32> clients;
438  in_stream >> clients;
439  out_stream << quint32 (MSG_FORWARD) << clientID << clients;
440  // see above!
441  out_buffer.QIODevice::write (in_buffer.readAll());
442  sendMessage (clients, out_msg);
443  }
444  break;
445 
446  case REQ_CLIENT_ID:
447  out_stream << quint32 (ANS_CLIENT_ID) << clientID;
448  sendMessage (clientID, out_msg);
449  break;
450 
451  case REQ_ADMIN_ID:
452  out_stream << quint32 (ANS_ADMIN_ID) << d->mAdminID;
453  sendMessage (clientID, out_msg);
454  break;
455 
456  case REQ_ADMIN_CHANGE:
457  if (clientID == d->mAdminID)
458  {
459  quint32 newAdmin;
460  in_stream >> newAdmin;
461  setAdmin (newAdmin);
462  }
463  break;
464 
465  case REQ_REMOVE_CLIENT:
466  if (clientID == d->mAdminID)
467  {
468  QList <quint32> client_list;
469  in_stream >> client_list;
470  for (QList<quint32>::Iterator iter = client_list.begin(); iter != client_list.end(); ++iter)
471  {
472  KMessageIO *client = findClient (*iter);
473  if (client)
474  removeClient (client, false);
475  else
476  kWarning (11001) << ": removing non-existing clientID";
477  }
478  }
479  break;
480 
481  case REQ_MAX_NUM_CLIENTS:
482  if (clientID == d->mAdminID)
483  {
484  qint32 maximum_clients;
485  in_stream >> maximum_clients;
486  setMaxClients (maximum_clients);
487  }
488  break;
489 
490  case REQ_CLIENT_LIST:
491  {
492  out_stream << quint32 (ANS_CLIENT_LIST) << clientIDs();
493  sendMessage (clientID, out_msg);
494  }
495  break;
496 
497  default:
498  unknown = true;
499  }
500 
501  // check if all the data has been used
502  if (!unknown && !in_buffer.atEnd())
503  kWarning (11001) << ": Extra data received for message ID" << messageID;
504 
505  emit messageReceived (msg_buf->data, clientID, unknown);
506 
507  if (unknown)
508  kWarning (11001) << ": received unknown message ID" << messageID;
509 
510  // remove the message, since we are ready with it
511  d->mMessageQueue.dequeue();
512  if (d->mMessageQueue.isEmpty())
513  d->mTimer.stop();
514  d->mIsRecursive = false;
515 }
516 
517 void KMessageServer::Debug()
518 {
519  kDebug(11001) << "------------------ KMESSAGESERVER -----------------------";
520  kDebug(11001) << "MaxClients : " << maxClients();
521  kDebug(11001) << "NoOfClients : " << clientCount();
522  kDebug(11001) << "---------------------------------------------------";
523 }
524 
525 #include "kmessageserver.moc"
526 #include "kmessageserver_p.moc"
KMessageServer::uniqueClientNumber
quint32 uniqueClientNumber() const
Definition: kmessageserver.cpp:345
KMessageServer::REQ_FORWARD
Definition: kmessageserver.h:185
KMessageServer::EVNT_CLIENT_DISCONNECTED
Definition: kmessageserver.h:204
KMessageServer::ANS_ADMIN_ID
Definition: kmessageserver.h:201
QQueue< MessageBuffer * >
KMessageServer::findClient
KMessageIO * findClient(quint32 no) const
Find the KMessageIO object to the given client number.
Definition: kmessageserver.cpp:301
KMessageSocket
This class implements the message communication using a TCP/IP socket.
Definition: kmessageio.h:170
QByteArray
KMessageServer::Debug
virtual void Debug()
Gives debug output of the game status.
Definition: kmessageserver.cpp:517
KMessageServer::REQ_BROADCAST
Definition: kmessageserver.h:184
QDataStream
QObject::sender
QObject * sender() const
KMessageServer::EVNT_CLIENT_CONNECTED
Definition: kmessageserver.h:203
KMessageIO::setId
void setId(quint32 id)
Sets the ID number of this object.
Definition: kmessageio.cpp:39
QTcpServer::newConnection
void newConnection()
KMessageServer::adminID
quint32 adminID() const
Returns the clientID of the admin, if there is a admin, 0 otherwise.
Definition: kmessageserver.cpp:316
KMessageServer::ANS_CLIENT_ID
Definition: kmessageserver.h:200
QBuffer
KMessageServer::removeClient
void removeClient(KMessageIO *io, bool broken)
Removes the KMessageIO object from the client list and deletes it.
Definition: kmessageserver.cpp:233
KMessageServer::sendMessage
virtual void sendMessage(quint32 id, const QByteArray &msg)
Sends a message to a single client with the given ID.
Definition: kmessageserver.cpp:358
KMessageServer::serverPort
quint16 serverPort() const
Returns the TCP/IP port number we are listening to for incoming connections.
Definition: kmessageserver.cpp:156
KMessageServer::clientCount
int clientCount() const
returns the current number of connected clients.
Definition: kmessageserver.cpp:288
QBuffer::buffer
QByteArray & buffer()
kmessageserver.h
KMessageIO::id
quint32 id()
Queries the ID of this object.
Definition: kmessageio.cpp:44
KMessageServer::REQ_ADMIN_CHANGE
Definition: kmessageserver.h:188
QTcpServer::hasPendingConnections
virtual bool hasPendingConnections() const
KMessageServer::setAdmin
void setAdmin(quint32 adminID)
Sets the admin to a new client with the given ID.
Definition: kmessageserver.cpp:321
KMessageServerSocket
Internal class of KMessageServer.
Definition: kmessageserver_p.h:34
KMessageServer::addClient
void addClient(KMessageIO *)
Adds a new KMessageIO object to the communication server.
Definition: kmessageserver.cpp:180
KMessageServer::messageReceived
void messageReceived(const QByteArray &data, quint32 clientID, bool &unknown)
This signal is always emitted when a message from a client is received.
KMessageServer::clientConnected
void clientConnected(KMessageIO *client)
A new client connected to the game.
QBuffer::atEnd
virtual bool atEnd() const
kmessageserver_p.h
KMessageServerSocket::~KMessageServerSocket
~KMessageServerSocket()
Definition: kmessageserver.cpp:44
QList::append
void append(const T &value)
KMessageServer::clientIDs
QList< quint32 > clientIDs() const
returns a list of the unique IDs of all clients.
Definition: kmessageserver.cpp:293
KMessageServer::MSG_BROADCAST
Definition: kmessageserver.h:198
QTimer
KMessageServer::MSG_FORWARD
Definition: kmessageserver.h:199
KMessageServer::deleteClients
void deleteClients()
Deletes all connections to the clients.
Definition: kmessageserver.cpp:257
QObject
KMessageServer::REQ_ADMIN_ID
Definition: kmessageserver.h:187
QTcpServer::listen
bool listen(const QHostAddress &address, quint16 port)
KMessageServerSocket::KMessageServerSocket
KMessageServerSocket(quint16 port, QObject *parent=0)
Definition: kmessageserver.cpp:36
KMessageIO
This abstract base class represents one end of a message connections between two clients.
Definition: kmessageio.h:57
KMessageServer::~KMessageServer
~KMessageServer()
Definition: kmessageserver.cpp:115
QIODevice::readAll
QByteArray readAll()
KMessageServer::REQ_MAX_NUM_CLIENTS
Definition: kmessageserver.h:190
QBuffer::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > flags)
QList< KMessageIO * >
KMessageServer::REQ_CLIENT_ID
Definition: kmessageserver.h:186
QList::end
iterator end()
KMessageServer::getReceivedMessage
virtual void getReceivedMessage(const QByteArray &msg)
This slot receives all the messages from the KMessageIO::received signals.
Definition: kmessageserver.cpp:371
KMessageServer::ANS_CLIENT_LIST
Definition: kmessageserver.h:202
QTcpServer
QTcpServer::nextPendingConnection
virtual QTcpSocket * nextPendingConnection()
KMessageServer::broadcastMessage
virtual void broadcastMessage(const QByteArray &msg)
Sends a message to all connected clients.
Definition: kmessageserver.cpp:352
KMessageServer::processOneMessage
virtual void processOneMessage()
This slot is called whenever there are elements in the message queue.
Definition: kmessageserver.cpp:392
KMessageServer::REQ_CLIENT_LIST
Definition: kmessageserver.h:191
KMessageServer::REQ_REMOVE_CLIENT
Definition: kmessageserver.h:189
KMessageServerSocket::slotNewConnection
void slotNewConnection()
Definition: kmessageserver.cpp:48
KMessageServer::initNetwork
bool initNetwork(quint16 port=0)
Starts the Communication server to listen for incoming TCP/IP connections.
Definition: kmessageserver.cpp:127
KMessageServer::KMessageServer
KMessageServer(quint16 cookie=42, QObject *parent=0)
Create a KGameNetwork object.
Definition: kmessageserver.cpp:99
KMessageServer::maxClients
int maxClients() const
returns the maximum number of clients
Definition: kmessageserver.cpp:283
kmessageio.h
KMessageServer::isOfferingConnections
bool isOfferingConnections() const
Are we still offer offering server connections?
Definition: kmessageserver.cpp:173
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KMessageIO::send
virtual void send(const QByteArray &msg)=0
This slot sends the data block in /e msg to the connected object, that will emit /e received()...
KMessageServerSocket::newClientConnected
void newClientConnected(KMessageIO *client)
QList::begin
iterator begin()
KMessageServer::connectionLost
void connectionLost(KMessageIO *client)
A network connection got broken.
KMessageServer::setMaxClients
void setMaxClients(int maxnumber)
sets the maximum number of clients which can connect.
Definition: kmessageserver.cpp:278
KMessageServer::stopNetwork
void stopNetwork()
Stops listening for connections.
Definition: kmessageserver.cpp:164
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:18:54 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

libkdegames/libkdegamesprivate/kgame

Skip menu "libkdegames/libkdegamesprivate/kgame"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdegames API Reference

Skip menu "kdegames API Reference"
  • granatier
  • kapman
  • kblackbox
  • kgoldrunner
  • kigo
  • kmahjongg
  • KShisen
  • ksquares
  • libkdegames
  •   highscore
  •   libkdegamesprivate
  •     kgame
  • libkmahjongg
  • palapeli
  •   libpala

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal