Code Search for Developers
 
 
  

kmessageserver.cpp from Boson at Krugle


Show kmessageserver.cpp syntax highlighted

/*
    This file is part of the KDE games library
    Copyright (C) 2001 Burkhard Lehner (Burkhard.Lehner@gmx.de)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qiodevice.h>
#include <qbuffer.h>
#include <qptrlist.h>
#include <qptrqueue.h>
#include <qtimer.h>
#include <qvaluelist.h>

#include <bodebug.h>

#include "kmessageio.h"
#include "kmessageserver.h"

// --------------- internal class KMessageServerSocket

KMessageServerSocket::KMessageServerSocket (Q_UINT16 port, QObject *parent)
  : QServerSocket (port, 0, parent)
{
}

KMessageServerSocket::~KMessageServerSocket ()
{
}

void KMessageServerSocket::newConnection (int socket)
{
  emit newClientConnected (new KMessageSocket (socket));
}

// ---------------- class for storing an incoming message

class MessageBuffer
{
  public:
    MessageBuffer (Q_UINT32 clientID, const QByteArray &messageData)
      : id (clientID), data (messageData) { }
    ~MessageBuffer () {}
    Q_UINT32 id;
    QByteArray data;
};

// ---------------- KMessageServer's private class

class KMessageServerPrivate
{
public:
  KMessageServerPrivate()
    : mMaxClients (-1), mGameId (1), mUniqueClientNumber (1), mAdminID (0), mServerSocket (0)
  {
    mClientList.setAutoDelete (true);
    mMessageQueue.setAutoDelete (true);
  }

  int mMaxClients;
  int mGameId;
  Q_UINT16 mCookie;
  Q_UINT32 mUniqueClientNumber;
  Q_UINT32 mAdminID;

  KMessageServerSocket* mServerSocket;

  QPtrList <KMessageIO> mClientList;
  QPtrQueue <MessageBuffer> mMessageQueue;
  QTimer mTimer;
  bool mIsRecursive;
};


// ------------------ KMessageServer

KMessageServer::KMessageServer (Q_UINT16 cookie,QObject* parent)
  : QObject(parent, 0)
{
  d = new KMessageServerPrivate;
  d->mIsRecursive=false;
  d->mCookie=cookie;
  connect (&(d->mTimer), SIGNAL (timeout()),
           this, SLOT (processOneMessage()));
  boDebug(11001) << "CREATE(KMessageServer="
		<< this
		<< ") cookie="
		<< d->mCookie
		<< " sizeof(this)="
		<< sizeof(KMessageServer)
		<< endl;
}

KMessageServer::~KMessageServer()
{
  boDebug(11001) << k_funcinfo << "this=" << this << endl;
  Debug();
  stopNetwork();
  deleteClients();
  delete d;
  boDebug(11001) << k_funcinfo << " done" << endl;
}

//------------------------------------- TCP/IP server stuff

bool KMessageServer::initNetwork (Q_UINT16 port)
{
  boDebug(11001) << k_funcinfo << endl;

  if (d->mServerSocket)
  {
    boDebug (11001) << k_funcinfo << ": We were already offering connections!" << endl;
    delete d->mServerSocket;
  }

  d->mServerSocket = new KMessageServerSocket (port);
  d->mIsRecursive = false;

  if (!d->mServerSocket || !d->mServerSocket->ok())
  {
    boError(11001) << k_funcinfo << ": Serversocket::ok() == false" << endl;
    delete d->mServerSocket;
    d->mServerSocket=0;
    return false;
  }

  boDebug (11001) << k_funcinfo << ": Now listening to port "
                  << d->mServerSocket->port() << endl;
  connect (d->mServerSocket, SIGNAL (newClientConnected (KMessageIO*)),
           this, SLOT (addClient (KMessageIO*)));
  return true;
}

Q_UINT16 KMessageServer::serverPort () const
{
  if (d->mServerSocket)
    return d->mServerSocket->port();
  else
    return 0;
}

void KMessageServer::stopNetwork()
{
  if (d->mServerSocket) 
  {
    delete d->mServerSocket;
    d->mServerSocket = 0;
  }
}

bool KMessageServer::isOfferingConnections() const
{
  return d->mServerSocket != 0;
}

//----------------------------------------------- adding / removing clients

void KMessageServer::addClient (KMessageIO* client)
{
  QByteArray msg;

  // maximum number of clients reached?
  if (d->mMaxClients >= 0 && d->mMaxClients <= clientCount())
  {
    boError (11001) << k_funcinfo << ": Maximum number of clients reached!" << endl;
    return;
  }

  // give it a unique ID
  client->setId (uniqueClientNumber());
  boDebug (11001) << k_funcinfo << ": " << client->id() << endl;

  // connect its signals
  connect (client, SIGNAL (connectionBroken()),
           this, SLOT (removeBrokenClient()));
  connect (client, SIGNAL (received (const QByteArray &)),
           this, SLOT (getReceivedMessage (const QByteArray &)));

  // Tell everyone about the new guest
  // Note: The new client doesn't get this message!
  QDataStream (msg, IO_WriteOnly) << Q_UINT32 (EVNT_CLIENT_CONNECTED) << client->id();
  broadcastMessage (msg);

  // add to our list
  d->mClientList.append (client);

  // tell it its ID
  QDataStream (msg, IO_WriteOnly) << Q_UINT32 (ANS_CLIENT_ID) << client->id();
  client->send (msg);

  // Give it the complete list of client IDs
  QDataStream (msg, IO_WriteOnly)  << Q_UINT32 (ANS_CLIENT_LIST) << clientIDs();
  client->send (msg);


  if (clientCount() == 1)
  {
    // if it is the first client, it becomes the admin
    setAdmin (client->id());
  }
  else
  {
    // otherwise tell it who is the admin
    QDataStream (msg, IO_WriteOnly) << Q_UINT32 (ANS_ADMIN_ID) << adminID();
    client->send (msg);
  }

  emit clientConnected (client);
}

void KMessageServer::removeClient (KMessageIO* client, bool broken)
{
  Q_UINT32 clientID = client->id();
  if (!d->mClientList.removeRef (client))
  {
    boError(11001) << k_funcinfo << ": Deleting client that wasn't added before!" << endl;
    return;
  }

  // tell everyone about the removed client
  QByteArray msg;
  QDataStream (msg, IO_WriteOnly) << Q_UINT32 (EVNT_CLIENT_DISCONNECTED) << client->id() << (Q_INT8)broken;
  broadcastMessage (msg);

  // If it was the admin, select a new admin.
  if (clientID == adminID())
  {
    if (!d->mClientList.isEmpty())
      setAdmin (d->mClientList.first()->id());
    else
      setAdmin (0);
  }
}

void KMessageServer::deleteClients()
{
  d->mClientList.clear();
  d->mAdminID = 0;
}

void KMessageServer::removeBrokenClient ()
{
  if (!sender()->inherits ("KMessageIO"))
  {
    boError (11001) << k_funcinfo << ": sender of the signal was not a KMessageIO object!" << endl;
    return;
  }

  KMessageIO *client = (KMessageIO *) sender();

  emit connectionLost (client);
  removeClient (client, true);
}


void KMessageServer::setMaxClients(int c)
{
  d->mMaxClients = c;
}

int KMessageServer::maxClients() const
{
  return d->mMaxClients;
}

int KMessageServer::clientCount() const
{
  return d->mClientList.count();
}

QValueList <Q_UINT32> KMessageServer::clientIDs () const
{
  QValueList <Q_UINT32> list;
  for (QPtrListIterator <KMessageIO> iter (d->mClientList); *iter; ++iter)
    list.append ((*iter)->id());
  return list;
}

KMessageIO* KMessageServer::findClient (Q_UINT32 no) const
{
  if (no == 0)
    no = d->mAdminID;

  QPtrListIterator <KMessageIO> iter (d->mClientList);
  while (*iter)
  {
    if ((*iter)->id() == no)
      return (*iter);
    ++iter;
  }
  return 0;
}

Q_UINT32 KMessageServer::adminID () const
{
  return d->mAdminID;
}

void KMessageServer::setAdmin (Q_UINT32 adminID)
{
  // Trying to set the the client that is already admin => nothing to do
  if (adminID == d->mAdminID)
    return;

  if (adminID > 0 && findClient (adminID) == 0)
  {
    boWarning (11001) << "Trying to set a new admin that doesn't exist!" << endl;
    return;
  }

  d->mAdminID = adminID;

  QByteArray msg;
  QDataStream (msg, IO_WriteOnly) << Q_UINT32 (ANS_ADMIN_ID) << adminID;

  // Tell everyone about the new master
  broadcastMessage (msg);
}


//------------------------------------------- ID stuff

Q_UINT32 KMessageServer::uniqueClientNumber() const
{
  return d->mUniqueClientNumber++;
}

// --------------------- Messages ---------------------------

void KMessageServer::broadcastMessage (const QByteArray &msg)
{
  for (QPtrListIterator <KMessageIO> iter (d->mClientList); *iter; ++iter)
    (*iter)->send (msg);
}

void KMessageServer::sendMessage (Q_UINT32 id, const QByteArray &msg)
{
  KMessageIO *client = findClient (id);
  if (client)
    client->send (msg);
}

void KMessageServer::sendMessage (const QValueList <Q_UINT32> &ids, const QByteArray &msg)
{
  for (QValueListConstIterator <Q_UINT32> iter = ids.begin(); iter != ids.end(); ++iter)
    sendMessage (*iter, msg);
}

void KMessageServer::getReceivedMessage (const QByteArray &msg)
{
  if (!sender() || !sender()->inherits("KMessageIO"))
  {
    boError (11001) << k_funcinfo << ": slot was not called from KMessageIO!" << endl;
    return;
  }
  //boDebug(11001) << k_funcinfo << ": size=" << msg.size() << endl;
  KMessageIO *client = (KMessageIO *) sender();
  Q_UINT32 clientID = client->id();

  //QByteArray *ta=new QByteArray;
  //ta->duplicate(msg);
  //d->mMessageQueue.enqueue (new MessageBuffer (clientID, *ta));

  
  d->mMessageQueue.enqueue (new MessageBuffer (clientID, msg));
  if (!d->mTimer.isActive())
    d->mTimer.start(0); // AB: should be , TRUE i guess
}

void KMessageServer::processOneMessage ()
{
  // This shouldn't happen, since the timer should be stopped before. But only to be sure!
  if (d->mMessageQueue.isEmpty())
  {
    d->mTimer.stop();
    return;
  }
  if (d->mIsRecursive)
  {
    return;
  }
  d->mIsRecursive = true;

  MessageBuffer *msg_buf = d->mMessageQueue.head();

  Q_UINT32 clientID = msg_buf->id;
  QBuffer in_buffer (msg_buf->data);
  in_buffer.open (IO_ReadOnly);
  QDataStream in_stream (&in_buffer);

  QByteArray out_msg;
  QBuffer out_buffer (out_msg);
  out_buffer.open (IO_WriteOnly);
  QDataStream out_stream (&out_buffer);

  bool unknown = false;

  QByteArray ttt=in_buffer.buffer();
  Q_UINT32 messageID;
  in_stream >> messageID;
  //boDebug(11001) << k_funcinfo << ": got message with messageID=" << messageID << endl;
  switch (messageID)
  {
    case REQ_BROADCAST:
      out_stream << Q_UINT32 (MSG_BROADCAST) << clientID;
      // FIXME, compiler bug?
      // this should be okay, since QBuffer is subclass of QIODevice! :
      // out_buffer.writeBlock (in_buffer.readAll());
      out_buffer.QIODevice::writeBlock (in_buffer.readAll());
      broadcastMessage (out_msg);
      break;

    case REQ_FORWARD:
      {
        QValueList <Q_UINT32> clients;
        in_stream >> clients;
        out_stream << Q_UINT32 (MSG_FORWARD) << clientID << clients;
        // see above!
        out_buffer.QIODevice::writeBlock (in_buffer.readAll());
        sendMessage (clients, out_msg);
      }
      break;

    case REQ_CLIENT_ID:
      out_stream << Q_UINT32 (ANS_CLIENT_ID) << clientID;
      sendMessage (clientID, out_msg);
      break;

    case REQ_ADMIN_ID:
      out_stream << Q_UINT32 (ANS_ADMIN_ID) << d->mAdminID;
      sendMessage (clientID, out_msg);
      break;

    case REQ_ADMIN_CHANGE:
      if (clientID == d->mAdminID)
      {
        Q_UINT32 newAdmin;
        in_stream >> newAdmin;
        setAdmin (newAdmin);
      }
      break;

    case REQ_REMOVE_CLIENT:
      if (clientID == d->mAdminID)
      {
        QValueList <Q_UINT32> client_list;
        in_stream >> client_list;
        for (QValueListIterator <Q_UINT32> iter = client_list.begin(); iter != client_list.end(); ++iter)
        {
          KMessageIO *client = findClient (*iter);
          if (client)
            removeClient (client, false);
          else
            boWarning (11001) << k_funcinfo << ": removing non-existing clientID" << endl;
        }
      }
      break;

    case REQ_MAX_NUM_CLIENTS:
      if (clientID == d->mAdminID)
      {
        Q_INT32 maximum_clients;
        in_stream >> maximum_clients;
        setMaxClients (maximum_clients);
      }
      break;

    case REQ_CLIENT_LIST:
      {
        out_stream << Q_UINT32 (ANS_CLIENT_LIST) << clientIDs();
        sendMessage (clientID, out_msg);
      }
      break;

    default:
      unknown = true;
  }

  // check if all the data has been used
  if (!unknown && !in_buffer.atEnd())
    boWarning (11001) << k_funcinfo << ": Extra data received for message ID " << messageID << endl;

  emit messageReceived (msg_buf->data, clientID, unknown);

  if (unknown)
    boWarning (11001) << k_funcinfo << ": received unknown message ID " << messageID << endl;

  // remove the message, since we are ready with it
  d->mMessageQueue.remove();
  if (d->mMessageQueue.isEmpty())
    d->mTimer.stop();
  d->mIsRecursive = false;
}

void KMessageServer::Debug()
{
   boDebug(11001) << "------------------ KMESSAGESERVER -----------------------" << endl;
   boDebug(11001) << "MaxClients :   " << maxClients() << endl;
   boDebug(11001) << "NoOfClients :  " << clientCount() << endl;
   boDebug(11001) << "---------------------------------------------------" << endl;
}

#include "kmessageserver.moc"




See more files for this project here

Boson

Boson is an OpenGL real-time strategy game. It is designed to run on Unix (Linux) computers, and is built on top of the KDE, Qt and kdegames libraries.

Project homepage: http://sourceforge.net/projects/boson
Programming language(s): C,C++
License: other

  CMakeLists.txt
  DESIGN
  kchatbase.cpp
  kchatbase.h
  kgame.cpp
  kgame.h
  kgamechat.cpp
  kgamechat.h
  kgamedebugdialog.cpp
  kgamedebugdialog.h
  kgameerror.cpp
  kgameerror.h
  kgameio.cpp
  kgameio.h
  kgamemessage.cpp
  kgamemessage.h
  kgamenetwork.cpp
  kgamenetwork.h
  kgameprocess.cpp
  kgameprocess.h
  kgameprogress.cpp
  kgameprogress.h
  kgameproperty.cpp
  kgameproperty.h
  kgamepropertyarray.h
  kgamepropertyhandler.cpp
  kgamepropertyhandler.h
  kgamepropertylist.h
  kgamesequence.cpp
  kgamesequence.h
  kgameversion.h
  kmessageclient.cpp
  kmessageclient.h
  kmessageio.cpp
  kmessageio.h
  kmessageserver.cpp
  kmessageserver.h
  kmessageserver.png
  kplayer.cpp
  kplayer.h
  kstdgameaction.cpp
  kstdgameaction.h
  libkdegames.html
  messages.txt
  scenario0.png
  scenario1.png
  scenario2.png