libkdegames Library API Documentation

kgamenetwork.cpp

00001 /*
00002     This file is part of the KDE games library
00003     Copyright (C) 2001 Martin Heni (martin@heni-online.de)
00004     Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License version 2 as published by the Free Software Foundation.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018     Boston, MA 02111-1307, USA.
00019 */
00020 /*
00021     $Id: kgamenetwork.cpp,v 1.44 2003/08/24 21:22:29 andreas Exp $
00022 */
00023 
00024 #include "kgamenetwork.h"
00025 #include "kgamenetwork.moc"
00026 #include "kgamemessage.h"
00027 #include "kgameerror.h"
00028 
00029 #include "kmessageserver.h"
00030 #include "kmessageclient.h"
00031 #include "kmessageio.h"
00032 
00033 #include <kdebug.h>
00034 
00035 #include <qbuffer.h>
00036 
00037 
00038 class KGameNetworkPrivate
00039 {
00040 public:
00041         KGameNetworkPrivate()
00042         {
00043                 mMessageClient = 0;
00044                 mMessageServer = 0;
00045                 mDisconnectId = 0;
00046         }
00047 
00048 public:
00049         KMessageClient* mMessageClient;
00050         KMessageServer* mMessageServer;
00051         Q_UINT32 mDisconnectId;  // Stores gameId() over a disconnect process
00052 
00053         int mCookie;
00054 };
00055 
00056 // ------------------- NETWORK GAME ------------------------
00057 KGameNetwork::KGameNetwork(int c, QObject* parent) : QObject(parent, 0)
00058 {
00059  d = new KGameNetworkPrivate;
00060  d->mCookie = (Q_INT16)c;
00061 
00062  // Init the game as a local game, i.e.
00063  // create your own KMessageServer and a KMessageClient connected to it.
00064  setMaster();
00065 
00066  kdDebug(11001) << k_funcinfo << "this=" << this <<", cookie=" << cookie() << " sizeof(this)="<<sizeof(KGameNetwork) << endl;
00067 }
00068 
00069 KGameNetwork::~KGameNetwork()
00070 {
00071  kdDebug(11001) << k_funcinfo << "this=" << this << endl;
00072 // Debug();
00073  delete d;
00074 }
00075 
00076 // ----------------------------- status methods
00077 bool KGameNetwork::isNetwork() const
00078 { return isOfferingConnections() || d->mMessageClient->isNetwork();}
00079 
00080 Q_UINT32 KGameNetwork::gameId() const
00081 {
00082   //return d->mMessageClient->id() ;
00083   // Return stored id in the case of disconnect. In any other
00084   // case the disconnect id is 0
00085   if (d->mMessageClient->id()!=0 ) {
00086     return d->mMessageClient->id() ;
00087   } else {
00088     return d->mDisconnectId;
00089   }
00090 }
00091 
00092 int KGameNetwork::cookie() const
00093 { return d->mCookie; }
00094 
00095 bool KGameNetwork::isMaster() const
00096 { return (d->mMessageServer != 0); }
00097 
00098 bool KGameNetwork::isAdmin() const
00099 { return (d->mMessageClient->isAdmin()); }
00100 
00101 KMessageClient* KGameNetwork::messageClient() const
00102 { return d->mMessageClient; }
00103 
00104 KMessageServer* KGameNetwork::messageServer() const
00105 { return d->mMessageServer; }
00106 
00107 // ----------------------- network init
00108 void KGameNetwork::setMaster()
00109 {
00110  if (!d->mMessageServer) {
00111    d->mMessageServer = new KMessageServer (cookie(), this);
00112  } else {
00113    kdWarning(11001) << k_funcinfo << "Server already running!!" << endl;
00114  }
00115  if (!d->mMessageClient) {
00116    d->mMessageClient = new KMessageClient (this);
00117    connect (d->mMessageClient, SIGNAL(broadcastReceived(const QByteArray&, Q_UINT32)),
00118             this, SLOT(receiveNetworkTransmission(const QByteArray&, Q_UINT32)));
00119    connect (d->mMessageClient, SIGNAL(connectionBroken()),
00120             this, SIGNAL(signalConnectionBroken()));
00121    connect (d->mMessageClient, SIGNAL(aboutToDisconnect(Q_UINT32)),
00122             this, SLOT(aboutToLoseConnection(Q_UINT32)));
00123    connect (d->mMessageClient, SIGNAL(connectionBroken()),
00124             this, SLOT(slotResetConnection()));
00125 
00126    connect (d->mMessageClient, SIGNAL(adminStatusChanged(bool)),
00127             this, SLOT(slotAdminStatusChanged(bool)));
00128    connect (d->mMessageClient, SIGNAL(eventClientConnected(Q_UINT32)),
00129             this, SIGNAL(signalClientConnected(Q_UINT32)));
00130    connect (d->mMessageClient, SIGNAL(eventClientDisconnected(Q_UINT32, bool)),
00131             this, SIGNAL(signalClientDisconnected(Q_UINT32, bool)));
00132 
00133    // broacast and direct messages are treated equally on receive.
00134    connect (d->mMessageClient, SIGNAL(forwardReceived(const QByteArray&, Q_UINT32, const QValueList<Q_UINT32>&)),
00135             d->mMessageClient, SIGNAL(broadcastReceived(const QByteArray&, Q_UINT32)));
00136 
00137  } else {
00138    // should be no problem but still has to be tested
00139    kdDebug(11001) << k_funcinfo << "Client already exists!" << endl;
00140  }
00141  d->mMessageClient->setServer(d->mMessageServer);
00142 }
00143 
00144 bool KGameNetwork::offerConnections(Q_UINT16 port)
00145 {
00146  kdDebug (11001) << k_funcinfo << "on port " << port << endl;
00147  if (!isMaster()) {
00148    setMaster();
00149  }
00150 
00151  // Make sure this is 0
00152  d->mDisconnectId = 0;
00153 
00154  // FIXME: This debug message can be removed when the program is working correct.
00155  if (d->mMessageServer && d->mMessageServer->isOfferingConnections()) {
00156    kdDebug (11001) << k_funcinfo << "Already running as server! Changing the port now!" << endl;
00157  }
00158 
00159  kdDebug (11001) << k_funcinfo << "before Server->initNetwork" << endl;
00160  if (!d->mMessageServer->initNetwork (port)) {
00161    kdError (11001) << k_funcinfo << "Unable to bind to port " << port << "!" << endl;
00162    // no need to delete - we just cannot listen to the port
00163 //   delete d->mMessageServer;
00164 //   d->mMessageServer = 0;
00165 //   d->mMessageClient->setServer((KMessageServer*)0);
00166    return false;
00167  }
00168  kdDebug (11001) << k_funcinfo << "after Server->initNetwork" << endl;
00169  return true;
00170 }
00171 
00172 bool KGameNetwork::connectToServer (const QString& host, Q_UINT16 port)
00173 {
00174  if (host.isEmpty()) {
00175    kdError(11001) << k_funcinfo << "No hostname given" << endl;
00176    return false;
00177  }
00178 
00179  // Make sure this is 0
00180  d->mDisconnectId = 0;
00181 
00182 // if (!d->mMessageServer) {
00183 //   // FIXME: What shall we do here? Probably must stop a running game.
00184 //   kdWarning (11001) << k_funcinfo << "We are already connected to another server!" << endl;
00186 
00187  if (d->mMessageServer) {
00188    // FIXME: What shall we do here? Probably must stop a running game.
00189    kdWarning(11001) << "we are server but we are trying to connect to another server! "
00190                     << "make sure that all clients connect to that server! "
00191                     << "quitting the local server now..." << endl;
00192    stopServerConnection();
00193    d->mMessageClient->setServer((KMessageIO*)0);
00194    delete d->mMessageServer;
00195    d->mMessageServer = 0;
00196  }
00197 
00198  kdDebug(11001) << "    about to set server" << endl;
00199  d->mMessageClient->setServer(host, port);
00200  emit signalAdminStatusChanged(false); // as we delete the connection above isAdmin() is always false now!
00201 
00202  // OK: We say that we already have connected, but this isn't so yet!
00203  // If the connection cannot be established, it will look as being disconnected
00204  // again ("slotConnectionLost" is called).
00205  // Shall we differ between these?
00206  kdDebug(11001) << "connected to " << host << ":" << port << endl;
00207  return true;
00208 }
00209 
00210 Q_UINT16 KGameNetwork::port() const
00211 {
00212  if (isNetwork()) {
00213    if (isOfferingConnections()) {
00214      return d->mMessageServer->serverPort();
00215    } else {
00216      return d->mMessageClient->peerPort();
00217    }
00218  }
00219  return 0;
00220 }
00221 
00222 QString KGameNetwork::hostName() const
00223 {
00224  return d->mMessageClient->peerName();
00225 }
00226 
00227 bool KGameNetwork::stopServerConnection()
00228 {
00229  // We still are the Master, we just don't accept further connections!
00230  if (d->mMessageServer) {
00231    d->mMessageServer->stopNetwork();
00232    return true;
00233  }
00234  return false;
00235 }
00236 
00237 bool KGameNetwork::isOfferingConnections() const
00238 { return (d->mMessageServer && d->mMessageServer->isOfferingConnections()); }
00239 
00240 void KGameNetwork::disconnect()
00241 {
00242  // TODO MH
00243  kdDebug(11001) << k_funcinfo << endl;
00244  stopServerConnection();
00245  if (d->mMessageServer) {
00246     QValueList <Q_UINT32> list=d->mMessageServer->clientIDs();
00247     QValueList<Q_UINT32>::Iterator it;
00248     for( it = list.begin(); it != list.end(); ++it )
00249     {
00250       kdDebug(11001) << "Client id=" << (*it) <<  endl;
00251       KMessageIO *client=d->mMessageServer->findClient(*it);
00252       if (!client)
00253       {
00254         continue;
00255       }
00256       kdDebug(11001) << "   rtti=" << client->rtti() <<  endl;
00257       if (client->rtti()==2)
00258       {
00259         kdDebug(11001) << "DIRECT IO " << endl;
00260       }
00261       else
00262       {
00263         d->mMessageServer->removeClient(client,false);
00264       }
00265     }
00266  }
00267  else
00268  {
00269    kdDebug(11001) << k_funcinfo << "before client->disconnect() id="<<gameId()<< endl;
00270    //d->mMessageClient->setServer((KMessageIO*)0);
00271    kdDebug(11001) << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++"<<endl;
00272    d->mMessageClient->disconnect();
00273 
00274    kdDebug(11001) << "++++++--------------------------------------------+++++"<<endl;
00275  }
00276  //setMaster();
00277  /*
00278  if (d->mMessageServer) {
00279   //delete d->mMessageServer;
00280   //d->mMessageServer=0;
00281   server=true;
00282   kdDebug(11001) << "  server true" << endl;
00283   d->mMessageServer->deleteClients();
00284   kdDebug(11001) << "  server deleteClients" << endl;
00285  }
00286  */
00287  kdDebug(11001) << k_funcinfo << "DONE" << endl;
00288 }
00289 
00290 void KGameNetwork::aboutToLoseConnection(Q_UINT32 clientID)
00291 {
00292   kdDebug(11001) << "Storing client id of connection "<<clientID<<endl;
00293   d->mDisconnectId = clientID;
00294 }
00295 
00296 void KGameNetwork::slotResetConnection()
00297 {
00298   kdDebug(11001) << "Resseting client disconnect id"<<endl;
00299   d->mDisconnectId = 0;
00300 }
00301 
00302 void KGameNetwork::electAdmin(Q_UINT32 clientID)
00303 {
00304  if (!isAdmin()) {
00305     kdWarning(11001) << k_funcinfo << "only ADMIN is allowed to call this!" << endl;
00306     return;
00307  }
00308  QByteArray buffer;
00309  QDataStream stream(buffer,IO_WriteOnly);
00310  stream << static_cast<Q_UINT32>( KMessageServer::REQ_ADMIN_CHANGE );
00311  stream << clientID;
00312  d->mMessageClient->sendServerMessage(buffer);
00313 }
00314 
00315 void KGameNetwork::setMaxClients(int max)
00316 {
00317  if (!isAdmin()) {
00318     kdWarning(11001) << k_funcinfo << "only ADMIN is allowed to call this!" << endl;
00319     return;
00320  }
00321  QByteArray buffer;
00322  QDataStream stream(buffer,IO_WriteOnly);
00323  stream << static_cast<Q_UINT32>( KMessageServer::REQ_MAX_NUM_CLIENTS );
00324  stream << (Q_INT32)max;
00325  d->mMessageClient->sendServerMessage(buffer);
00326 }
00327 
00328 void KGameNetwork::lock()
00329 {
00330  if (messageClient()) {
00331    messageClient()->lock();
00332  }
00333 }
00334 
00335 void KGameNetwork::unlock()
00336 {
00337  if (messageClient()) {
00338    messageClient()->unlock();
00339  }
00340 }
00341 
00342 // --------------------- send messages ---------------------------
00343 
00344 bool KGameNetwork::sendSystemMessage(int data, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00345 {
00346  QByteArray buffer;
00347  QDataStream stream(buffer,IO_WriteOnly);
00348  stream << data;
00349  return sendSystemMessage(buffer,msgid,receiver,sender);
00350 }
00351 
00352 bool KGameNetwork::sendSystemMessage(const QString &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00353 {
00354  QByteArray buffer;
00355  QDataStream stream(buffer, IO_WriteOnly);
00356  stream << msg;
00357  return sendSystemMessage(buffer, msgid, receiver, sender);
00358 }
00359 
00360 bool KGameNetwork::sendSystemMessage(const QDataStream &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00361 { return sendSystemMessage(((QBuffer*)msg.device())->buffer(), msgid, receiver, sender); }
00362 
00363 bool KGameNetwork::sendSystemMessage(const QByteArray& data, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00364 {
00365  QByteArray buffer;
00366  QDataStream stream(buffer,IO_WriteOnly);
00367  if (!sender) {
00368    sender = gameId();
00369  }
00370 
00371  Q_UINT32 receiverClient = KGameMessage::rawGameId(receiver); // KGame::gameId()
00372  int receiverPlayer = KGameMessage::rawPlayerId(receiver); // KPlayer::id()
00373 
00374  KGameMessage::createHeader(stream, sender, receiver, msgid);
00375  stream.writeRawBytes(data.data(), data.size());
00376 
00377  /*
00378  kdDebug(11001) << "transmitGameClientMessage msgid=" << msgid << " recv="
00379                 << receiver << " sender=" << sender << " Buffersize="
00380                 << buffer.size() << endl;
00381   */
00382 
00383  if (!d->mMessageClient) {
00384    // No client created, this should never happen!
00385    // Having a local game means we have our own
00386    // KMessageServer and we are the only client.
00387    kdWarning (11001) << k_funcinfo << "We don't have a client! Should never happen!" << endl;
00388    return false;
00389  }
00390 
00391  if (receiverClient == 0 || receiverPlayer != 0)
00392  {
00393    // if receiverClient == 0 this is a broadcast message. if it is != 0 but
00394    // receiverPlayer is also != 0 we have to send broadcast anyway, because the
00395    // KPlayer object on all clients needs to receive the message.
00396    d->mMessageClient->sendBroadcast(buffer);
00397  }
00398  else
00399  {
00400    d->mMessageClient->sendForward(buffer, receiverClient);
00401  }
00402  return true;
00403 }
00404 
00405 bool KGameNetwork::sendMessage(int data, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00406 { return sendSystemMessage(data,msgid+KGameMessage::IdUser,receiver,sender); }
00407 
00408 bool KGameNetwork::sendMessage(const QString &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00409 { return sendSystemMessage(msg,msgid+KGameMessage::IdUser,receiver,sender); }
00410 
00411 bool KGameNetwork::sendMessage(const QDataStream &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00412 { return sendSystemMessage(msg, msgid+KGameMessage::IdUser, receiver, sender); }
00413 
00414 bool KGameNetwork::sendMessage(const QByteArray &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00415 { return sendSystemMessage(msg, msgid+KGameMessage::IdUser, receiver, sender); }
00416 
00417 void KGameNetwork::sendError(int error,const QByteArray& message, Q_UINT32 receiver, Q_UINT32 sender)
00418 {
00419  QByteArray buffer;
00420  QDataStream stream(buffer,IO_WriteOnly);
00421  stream << (Q_INT32) error;
00422  stream.writeRawBytes(message.data(), message.size());
00423  sendSystemMessage(stream,KGameMessage::IdError,receiver,sender);
00424 }
00425 
00426 
00427 // ----------------- receive messages from the network
00428 void KGameNetwork::receiveNetworkTransmission(const QByteArray& receiveBuffer, Q_UINT32 clientID)
00429 {
00430  QDataStream stream(receiveBuffer, IO_ReadOnly);
00431  int msgid;
00432  Q_UINT32 sender; // the id of the KGame/KPlayer who sent the message
00433  Q_UINT32 receiver; // the id of the KGame/KPlayer the message is for 
00434  KGameMessage::extractHeader(stream, sender, receiver, msgid);
00435 // kdDebug(11001) << k_funcinfo << "id=" << msgid << " sender=" << sender << " recv=" << receiver << endl;
00436 
00437  // No broadcast : receiver==0
00438  // No player isPlayer(receiver)
00439  // Different game gameId()!=receiver
00440  if (receiver &&  receiver!=gameId() && !KGameMessage::isPlayer(receiver) )
00441  {
00442    // receiver=0 is broadcast or player message
00443    kdDebug(11001) << k_funcinfo << "Message not meant for us "
00444             << gameId() << "!=" << receiver << " rawid="
00445             << KGameMessage::rawGameId(receiver) << endl;
00446    return;
00447  }
00448  else if (msgid==KGameMessage::IdError)
00449  {
00450    QString text;
00451    Q_INT32 error;
00452    stream >> error;
00453    kdDebug(11001) << k_funcinfo << "Got IdError " << error << endl;
00454    text = KGameError::errorText(error, stream);
00455    kdDebug(11001) << "Error text: " << text.latin1() << endl;
00456    emit signalNetworkErrorMessage((int)error,text);
00457  }
00458  else
00459  {
00460    networkTransmission(stream, msgid, receiver, sender, clientID);
00461  }
00462 }
00463 
00464 // -------------- slots for the signals of the client
00465 void KGameNetwork::slotAdminStatusChanged(bool isAdmin)
00466 {
00467  emit signalAdminStatusChanged(isAdmin);
00468 
00469 // TODO: I'm pretty sure there are a lot of things that should be done here...
00470 }
00471 
00472 void KGameNetwork::Debug()
00473 {
00474  kdDebug(11001) << "------------------- KNETWORKGAME -------------------------" << endl;
00475  kdDebug(11001) << "gameId         " << gameId() << endl;
00476  kdDebug(11001) << "gameMaster     " << isMaster() << endl;
00477  kdDebug(11001) << "gameAdmin      " << isAdmin() << endl;
00478  kdDebug(11001) << "---------------------------------------------------" << endl;
00479 }
00480 
00481 /*
00482  * vim: et sw=2
00483  */
KDE Logo
This file is part of the documentation for libkdegames Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Jan 20 04:22:43 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003