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.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Aug 26 00:21:40 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003