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., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 /*
00021     $Id: kgamenetwork.cpp 465369 2005-09-29 14:33:08Z mueller $
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 #include <dnssd/publicservice.h>
00033 
00034 #include <kdebug.h>
00035 
00036 #include <qbuffer.h>
00037 
00038 
00039 class KGameNetworkPrivate
00040 {
00041 public:
00042         KGameNetworkPrivate()
00043         {
00044                 mMessageClient = 0;
00045                 mMessageServer = 0;
00046                 mDisconnectId = 0;
00047         mService = 0;
00048         }
00049 
00050 public:
00051         KMessageClient* mMessageClient;
00052         KMessageServer* mMessageServer;
00053         Q_UINT32 mDisconnectId;  // Stores gameId() over a disconnect process
00054     DNSSD::PublicService* mService;
00055     QString mType;
00056     QString mName;
00057 
00058         int mCookie;
00059 };
00060 
00061 // ------------------- NETWORK GAME ------------------------
00062 KGameNetwork::KGameNetwork(int c, QObject* parent) : QObject(parent, 0)
00063 {
00064  d = new KGameNetworkPrivate;
00065  d->mCookie = (Q_INT16)c;
00066 
00067  // Init the game as a local game, i.e.
00068  // create your own KMessageServer and a KMessageClient connected to it.
00069  setMaster();
00070 
00071  kdDebug(11001) << k_funcinfo << "this=" << this <<", cookie=" << cookie() << " sizeof(this)="<<sizeof(KGameNetwork) << endl;
00072 }
00073 
00074 KGameNetwork::~KGameNetwork()
00075 {
00076  kdDebug(11001) << k_funcinfo << "this=" << this << endl;
00077 // Debug();
00078  delete d->mService;
00079  delete d;
00080 }
00081 
00082 // ----------------------------- status methods
00083 bool KGameNetwork::isNetwork() const
00084 { return isOfferingConnections() || d->mMessageClient->isNetwork();}
00085 
00086 Q_UINT32 KGameNetwork::gameId() const
00087 {
00088   //return d->mMessageClient->id() ;
00089   // Return stored id in the case of disconnect. In any other
00090   // case the disconnect id is 0
00091   if (d->mMessageClient->id()!=0 ) {
00092     return d->mMessageClient->id() ;
00093   } else {
00094     return d->mDisconnectId;
00095   }
00096 }
00097 
00098 int KGameNetwork::cookie() const
00099 { return d->mCookie; }
00100 
00101 bool KGameNetwork::isMaster() const
00102 { return (d->mMessageServer != 0); }
00103 
00104 bool KGameNetwork::isAdmin() const
00105 { return (d->mMessageClient->isAdmin()); }
00106 
00107 KMessageClient* KGameNetwork::messageClient() const
00108 { return d->mMessageClient; }
00109 
00110 KMessageServer* KGameNetwork::messageServer() const
00111 { return d->mMessageServer; }
00112 
00113 // ----------------------- network init
00114 void KGameNetwork::setMaster()
00115 {
00116  if (!d->mMessageServer) {
00117    d->mMessageServer = new KMessageServer (cookie(), this);
00118  } else {
00119    kdWarning(11001) << k_funcinfo << "Server already running!!" << endl;
00120  }
00121  if (!d->mMessageClient) {
00122    d->mMessageClient = new KMessageClient (this);
00123    connect (d->mMessageClient, SIGNAL(broadcastReceived(const QByteArray&, Q_UINT32)),
00124             this, SLOT(receiveNetworkTransmission(const QByteArray&, Q_UINT32)));
00125    connect (d->mMessageClient, SIGNAL(connectionBroken()),
00126             this, SIGNAL(signalConnectionBroken()));
00127    connect (d->mMessageClient, SIGNAL(aboutToDisconnect(Q_UINT32)),
00128             this, SLOT(aboutToLoseConnection(Q_UINT32)));
00129    connect (d->mMessageClient, SIGNAL(connectionBroken()),
00130             this, SLOT(slotResetConnection()));
00131 
00132    connect (d->mMessageClient, SIGNAL(adminStatusChanged(bool)),
00133             this, SLOT(slotAdminStatusChanged(bool)));
00134    connect (d->mMessageClient, SIGNAL(eventClientConnected(Q_UINT32)),
00135             this, SIGNAL(signalClientConnected(Q_UINT32)));
00136    connect (d->mMessageClient, SIGNAL(eventClientDisconnected(Q_UINT32, bool)),
00137             this, SIGNAL(signalClientDisconnected(Q_UINT32, bool)));
00138 
00139    // broacast and direct messages are treated equally on receive.
00140    connect (d->mMessageClient, SIGNAL(forwardReceived(const QByteArray&, Q_UINT32, const QValueList<Q_UINT32>&)),
00141             d->mMessageClient, SIGNAL(broadcastReceived(const QByteArray&, Q_UINT32)));
00142 
00143  } else {
00144    // should be no problem but still has to be tested
00145    kdDebug(11001) << k_funcinfo << "Client already exists!" << endl;
00146  }
00147  d->mMessageClient->setServer(d->mMessageServer);
00148 }
00149 
00150 void KGameNetwork::setDiscoveryInfo(const QString& type, const QString& name)
00151 {
00152  kdDebug() << k_funcinfo << type << ":" << name << endl;
00153  d->mType = type;
00154  d->mName = name;
00155  tryPublish();
00156 }
00157 
00158 void KGameNetwork::tryPublish()
00159 {
00160  if (d->mType.isNull() || !isOfferingConnections()) return;
00161  if (!d->mService) d->mService = new DNSSD::PublicService(d->mName,d->mType,port());
00162  else {
00163    if (d->mType!=d->mService->type()) d->mService->setType(d->mType);
00164    if (d->mName!=d->mService->serviceName()) d->mService->setServiceName(d->mName);
00165    }
00166  if (!d->mService->isPublished()) d->mService->publishAsync();
00167 }
00168 
00169 void KGameNetwork::tryStopPublishing()
00170 {
00171  if (d->mService) d->mService->stop();
00172 }
00173 
00174 bool KGameNetwork::offerConnections(Q_UINT16 port)
00175 {
00176  kdDebug (11001) << k_funcinfo << "on port " << port << endl;
00177  if (!isMaster()) {
00178    setMaster();
00179  }
00180 
00181  // Make sure this is 0
00182  d->mDisconnectId = 0;
00183 
00184  // FIXME: This debug message can be removed when the program is working correct.
00185  if (d->mMessageServer && d->mMessageServer->isOfferingConnections()) {
00186    kdDebug (11001) << k_funcinfo << "Already running as server! Changing the port now!" << endl;
00187  }
00188 
00189  tryStopPublishing();
00190  kdDebug (11001) << k_funcinfo << "before Server->initNetwork" << endl;
00191  if (!d->mMessageServer->initNetwork (port)) {
00192    kdError (11001) << k_funcinfo << "Unable to bind to port " << port << "!" << endl;
00193    // no need to delete - we just cannot listen to the port
00194 //   delete d->mMessageServer;
00195 //   d->mMessageServer = 0;
00196 //   d->mMessageClient->setServer((KMessageServer*)0);
00197    return false;
00198  }
00199  kdDebug (11001) << k_funcinfo << "after Server->initNetwork" << endl;
00200  tryPublish();
00201  return true;
00202 }
00203 
00204 bool KGameNetwork::connectToServer (const QString& host, Q_UINT16 port)
00205 {
00206  if (host.isEmpty()) {
00207    kdError(11001) << k_funcinfo << "No hostname given" << endl;
00208    return false;
00209  }
00210 
00211  // Make sure this is 0
00212  d->mDisconnectId = 0;
00213 
00214 // if (!d->mMessageServer) {
00215 //   // FIXME: What shall we do here? Probably must stop a running game.
00216 //   kdWarning (11001) << k_funcinfo << "We are already connected to another server!" << endl;
00218 
00219  if (d->mMessageServer) {
00220    // FIXME: What shall we do here? Probably must stop a running game.
00221    kdWarning(11001) << "we are server but we are trying to connect to another server! "
00222                     << "make sure that all clients connect to that server! "
00223                     << "quitting the local server now..." << endl;
00224    stopServerConnection();
00225    d->mMessageClient->setServer((KMessageIO*)0);
00226    delete d->mMessageServer;
00227    d->mMessageServer = 0;
00228  }
00229 
00230  kdDebug(11001) << "    about to set server" << endl;
00231  d->mMessageClient->setServer(host, port);
00232  emit signalAdminStatusChanged(false); // as we delete the connection above isAdmin() is always false now!
00233 
00234  // OK: We say that we already have connected, but this isn't so yet!
00235  // If the connection cannot be established, it will look as being disconnected
00236  // again ("slotConnectionLost" is called).
00237  // Shall we differ between these?
00238  kdDebug(11001) << "connected to " << host << ":" << port << endl;
00239  return true;
00240 }
00241 
00242 Q_UINT16 KGameNetwork::port() const
00243 {
00244  if (isNetwork()) {
00245    if (isOfferingConnections()) {
00246      return d->mMessageServer->serverPort();
00247    } else {
00248      return d->mMessageClient->peerPort();
00249    }
00250  }
00251  return 0;
00252 }
00253 
00254 QString KGameNetwork::hostName() const
00255 {
00256  return d->mMessageClient->peerName();
00257 }
00258 
00259 bool KGameNetwork::stopServerConnection()
00260 {
00261  // We still are the Master, we just don't accept further connections!
00262  tryStopPublishing();
00263  if (d->mMessageServer) {
00264    d->mMessageServer->stopNetwork();
00265    return true;
00266  }
00267  return false;
00268 }
00269 
00270 bool KGameNetwork::isOfferingConnections() const
00271 { return (d->mMessageServer && d->mMessageServer->isOfferingConnections()); }
00272 
00273 void KGameNetwork::disconnect()
00274 {
00275  // TODO MH
00276  kdDebug(11001) << k_funcinfo << endl;
00277  stopServerConnection();
00278  if (d->mMessageServer) {
00279     QValueList <Q_UINT32> list=d->mMessageServer->clientIDs();
00280     QValueList<Q_UINT32>::Iterator it;
00281     for( it = list.begin(); it != list.end(); ++it )
00282     {
00283       kdDebug(11001) << "Client id=" << (*it) <<  endl;
00284       KMessageIO *client=d->mMessageServer->findClient(*it);
00285       if (!client)
00286       {
00287         continue;
00288       }
00289       kdDebug(11001) << "   rtti=" << client->rtti() <<  endl;
00290       if (client->rtti()==2)
00291       {
00292         kdDebug(11001) << "DIRECT IO " << endl;
00293       }
00294       else
00295       {
00296         d->mMessageServer->removeClient(client,false);
00297       }
00298     }
00299  }
00300  else
00301  {
00302    kdDebug(11001) << k_funcinfo << "before client->disconnect() id="<<gameId()<< endl;
00303    //d->mMessageClient->setServer((KMessageIO*)0);
00304    kdDebug(11001) << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++"<<endl;
00305    d->mMessageClient->disconnect();
00306 
00307    kdDebug(11001) << "++++++--------------------------------------------+++++"<<endl;
00308  }
00309  //setMaster();
00310  /*
00311  if (d->mMessageServer) {
00312   //delete d->mMessageServer;
00313   //d->mMessageServer=0;
00314   server=true;
00315   kdDebug(11001) << "  server true" << endl;
00316   d->mMessageServer->deleteClients();
00317   kdDebug(11001) << "  server deleteClients" << endl;
00318  }
00319  */
00320  kdDebug(11001) << k_funcinfo << "DONE" << endl;
00321 }
00322 
00323 void KGameNetwork::aboutToLoseConnection(Q_UINT32 clientID)
00324 {
00325   kdDebug(11001) << "Storing client id of connection "<<clientID<<endl;
00326   d->mDisconnectId = clientID;
00327 }
00328 
00329 void KGameNetwork::slotResetConnection()
00330 {
00331   kdDebug(11001) << "Resseting client disconnect id"<<endl;
00332   d->mDisconnectId = 0;
00333 }
00334 
00335 void KGameNetwork::electAdmin(Q_UINT32 clientID)
00336 {
00337  if (!isAdmin()) {
00338     kdWarning(11001) << k_funcinfo << "only ADMIN is allowed to call this!" << endl;
00339     return;
00340  }
00341  QByteArray buffer;
00342  QDataStream stream(buffer,IO_WriteOnly);
00343  stream << static_cast<Q_UINT32>( KMessageServer::REQ_ADMIN_CHANGE );
00344  stream << clientID;
00345  d->mMessageClient->sendServerMessage(buffer);
00346 }
00347 
00348 void KGameNetwork::setMaxClients(int max)
00349 {
00350  if (!isAdmin()) {
00351     kdWarning(11001) << k_funcinfo << "only ADMIN is allowed to call this!" << endl;
00352     return;
00353  }
00354  QByteArray buffer;
00355  QDataStream stream(buffer,IO_WriteOnly);
00356  stream << static_cast<Q_UINT32>( KMessageServer::REQ_MAX_NUM_CLIENTS );
00357  stream << (Q_INT32)max;
00358  d->mMessageClient->sendServerMessage(buffer);
00359 }
00360 
00361 void KGameNetwork::lock()
00362 {
00363  if (messageClient()) {
00364    messageClient()->lock();
00365  }
00366 }
00367 
00368 void KGameNetwork::unlock()
00369 {
00370  if (messageClient()) {
00371    messageClient()->unlock();
00372  }
00373 }
00374 
00375 // --------------------- send messages ---------------------------
00376 
00377 bool KGameNetwork::sendSystemMessage(int data, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00378 {
00379  QByteArray buffer;
00380  QDataStream stream(buffer,IO_WriteOnly);
00381  stream << data;
00382  return sendSystemMessage(buffer,msgid,receiver,sender);
00383 }
00384 
00385 bool KGameNetwork::sendSystemMessage(const QString &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00386 {
00387  QByteArray buffer;
00388  QDataStream stream(buffer, IO_WriteOnly);
00389  stream << msg;
00390  return sendSystemMessage(buffer, msgid, receiver, sender);
00391 }
00392 
00393 bool KGameNetwork::sendSystemMessage(const QDataStream &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00394 { return sendSystemMessage(((QBuffer*)msg.device())->buffer(), msgid, receiver, sender); }
00395 
00396 bool KGameNetwork::sendSystemMessage(const QByteArray& data, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00397 {
00398  QByteArray buffer;
00399  QDataStream stream(buffer,IO_WriteOnly);
00400  if (!sender) {
00401    sender = gameId();
00402  }
00403 
00404  Q_UINT32 receiverClient = KGameMessage::rawGameId(receiver); // KGame::gameId()
00405  int receiverPlayer = KGameMessage::rawPlayerId(receiver); // KPlayer::id()
00406 
00407  KGameMessage::createHeader(stream, sender, receiver, msgid);
00408  stream.writeRawBytes(data.data(), data.size());
00409 
00410  /*
00411  kdDebug(11001) << "transmitGameClientMessage msgid=" << msgid << " recv="
00412                 << receiver << " sender=" << sender << " Buffersize="
00413                 << buffer.size() << endl;
00414   */
00415 
00416  if (!d->mMessageClient) {
00417    // No client created, this should never happen!
00418    // Having a local game means we have our own
00419    // KMessageServer and we are the only client.
00420    kdWarning (11001) << k_funcinfo << "We don't have a client! Should never happen!" << endl;
00421    return false;
00422  }
00423 
00424  if (receiverClient == 0 || receiverPlayer != 0)
00425  {
00426    // if receiverClient == 0 this is a broadcast message. if it is != 0 but
00427    // receiverPlayer is also != 0 we have to send broadcast anyway, because the
00428    // KPlayer object on all clients needs to receive the message.
00429    d->mMessageClient->sendBroadcast(buffer);
00430  }
00431  else
00432  {
00433    d->mMessageClient->sendForward(buffer, receiverClient);
00434  }
00435  return true;
00436 }
00437 
00438 bool KGameNetwork::sendMessage(int data, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00439 { return sendSystemMessage(data,msgid+KGameMessage::IdUser,receiver,sender); }
00440 
00441 bool KGameNetwork::sendMessage(const QString &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00442 { return sendSystemMessage(msg,msgid+KGameMessage::IdUser,receiver,sender); }
00443 
00444 bool KGameNetwork::sendMessage(const QDataStream &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00445 { return sendSystemMessage(msg, msgid+KGameMessage::IdUser, receiver, sender); }
00446 
00447 bool KGameNetwork::sendMessage(const QByteArray &msg, int msgid, Q_UINT32 receiver, Q_UINT32 sender)
00448 { return sendSystemMessage(msg, msgid+KGameMessage::IdUser, receiver, sender); }
00449 
00450 void KGameNetwork::sendError(int error,const QByteArray& message, Q_UINT32 receiver, Q_UINT32 sender)
00451 {
00452  QByteArray buffer;
00453  QDataStream stream(buffer,IO_WriteOnly);
00454  stream << (Q_INT32) error;
00455  stream.writeRawBytes(message.data(), message.size());
00456  sendSystemMessage(stream,KGameMessage::IdError,receiver,sender);
00457 }
00458 
00459 
00460 // ----------------- receive messages from the network
00461 void KGameNetwork::receiveNetworkTransmission(const QByteArray& receiveBuffer, Q_UINT32 clientID)
00462 {
00463  QDataStream stream(receiveBuffer, IO_ReadOnly);
00464  int msgid;
00465  Q_UINT32 sender; // the id of the KGame/KPlayer who sent the message
00466  Q_UINT32 receiver; // the id of the KGame/KPlayer the message is for 
00467  KGameMessage::extractHeader(stream, sender, receiver, msgid);
00468 // kdDebug(11001) << k_funcinfo << "id=" << msgid << " sender=" << sender << " recv=" << receiver << endl;
00469 
00470  // No broadcast : receiver==0
00471  // No player isPlayer(receiver)
00472  // Different game gameId()!=receiver
00473  if (receiver &&  receiver!=gameId() && !KGameMessage::isPlayer(receiver) )
00474  {
00475    // receiver=0 is broadcast or player message
00476    kdDebug(11001) << k_funcinfo << "Message not meant for us "
00477             << gameId() << "!=" << receiver << " rawid="
00478             << KGameMessage::rawGameId(receiver) << endl;
00479    return;
00480  }
00481  else if (msgid==KGameMessage::IdError)
00482  {
00483    QString text;
00484    Q_INT32 error;
00485    stream >> error;
00486    kdDebug(11001) << k_funcinfo << "Got IdError " << error << endl;
00487    text = KGameError::errorText(error, stream);
00488    kdDebug(11001) << "Error text: " << text.latin1() << endl;
00489    emit signalNetworkErrorMessage((int)error,text);
00490  }
00491  else
00492  {
00493    networkTransmission(stream, msgid, receiver, sender, clientID);
00494  }
00495 }
00496 
00497 // -------------- slots for the signals of the client
00498 void KGameNetwork::slotAdminStatusChanged(bool isAdmin)
00499 {
00500  emit signalAdminStatusChanged(isAdmin);
00501 
00502 // TODO: I'm pretty sure there are a lot of things that should be done here...
00503 }
00504 
00505 void KGameNetwork::Debug()
00506 {
00507  kdDebug(11001) << "------------------- KNETWORKGAME -------------------------" << endl;
00508  kdDebug(11001) << "gameId         " << gameId() << endl;
00509  kdDebug(11001) << "gameMaster     " << isMaster() << endl;
00510  kdDebug(11001) << "gameAdmin      " << isAdmin() << endl;
00511  kdDebug(11001) << "---------------------------------------------------" << endl;
00512 }
00513 
00514 /*
00515  * vim: et sw=2
00516  */
KDE Home | KDE Accessibility Home | Description of Access Keys