kgamenetwork.cpp
00001 /* 00002 This file is part of the TDE 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$ 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 <tqbuffer.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 TQ_UINT32 mDisconnectId; // Stores gameId() over a disconnect process 00054 DNSSD::PublicService* mService; 00055 TQString mType; 00056 TQString mName; 00057 00058 int mCookie; 00059 }; 00060 00061 // ------------------- NETWORK GAME ------------------------ 00062 KGameNetwork::KGameNetwork(int c, TQObject* parent) : TQObject(parent, 0) 00063 { 00064 d = new KGameNetworkPrivate; 00065 d->mCookie = (TQ_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 TQ_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, TQT_SIGNAL(broadcastReceived(const TQByteArray&, TQ_UINT32)), 00124 this, TQT_SLOT(receiveNetworkTransmission(const TQByteArray&, TQ_UINT32))); 00125 connect (d->mMessageClient, TQT_SIGNAL(connectionBroken()), 00126 this, TQT_SIGNAL(signalConnectionBroken())); 00127 connect (d->mMessageClient, TQT_SIGNAL(aboutToDisconnect(TQ_UINT32)), 00128 this, TQT_SLOT(aboutToLoseConnection(TQ_UINT32))); 00129 connect (d->mMessageClient, TQT_SIGNAL(connectionBroken()), 00130 this, TQT_SLOT(slotResetConnection())); 00131 00132 connect (d->mMessageClient, TQT_SIGNAL(adminStatusChanged(bool)), 00133 this, TQT_SLOT(slotAdminStatusChanged(bool))); 00134 connect (d->mMessageClient, TQT_SIGNAL(eventClientConnected(TQ_UINT32)), 00135 this, TQT_SIGNAL(signalClientConnected(TQ_UINT32))); 00136 connect (d->mMessageClient, TQT_SIGNAL(eventClientDisconnected(TQ_UINT32, bool)), 00137 this, TQT_SIGNAL(signalClientDisconnected(TQ_UINT32, bool))); 00138 00139 // broacast and direct messages are treated equally on receive. 00140 connect (d->mMessageClient, TQT_SIGNAL(forwardReceived(const TQByteArray&, TQ_UINT32, const TQValueList<TQ_UINT32>&)), 00141 d->mMessageClient, TQT_SIGNAL(broadcastReceived(const TQByteArray&, TQ_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 TQString& type, const TQString& 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(TQ_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 TQString& host, TQ_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 TQ_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 TQString 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 TQValueList <TQ_UINT32> list=d->mMessageServer->clientIDs(); 00280 TQValueList<TQ_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(TQ_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(TQ_UINT32 clientID) 00336 { 00337 if (!isAdmin()) { 00338 kdWarning(11001) << k_funcinfo << "only ADMIN is allowed to call this!" << endl; 00339 return; 00340 } 00341 TQByteArray buffer; 00342 TQDataStream stream(buffer,IO_WriteOnly); 00343 stream << static_cast<TQ_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 TQByteArray buffer; 00355 TQDataStream stream(buffer,IO_WriteOnly); 00356 stream << static_cast<TQ_UINT32>( KMessageServer::REQ_MAX_NUM_CLIENTS ); 00357 stream << (TQ_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, TQ_UINT32 receiver, TQ_UINT32 sender) 00378 { 00379 TQByteArray buffer; 00380 TQDataStream stream(buffer,IO_WriteOnly); 00381 stream << data; 00382 return sendSystemMessage(buffer,msgid,receiver,sender); 00383 } 00384 00385 bool KGameNetwork::sendSystemMessage(const TQString &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender) 00386 { 00387 TQByteArray buffer; 00388 TQDataStream stream(buffer, IO_WriteOnly); 00389 stream << msg; 00390 return sendSystemMessage(buffer, msgid, receiver, sender); 00391 } 00392 00393 bool KGameNetwork::sendSystemMessage(const TQDataStream &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender) 00394 { return sendSystemMessage(((TQBuffer*)msg.device())->buffer(), msgid, receiver, sender); } 00395 00396 bool KGameNetwork::sendSystemMessage(const TQByteArray& data, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender) 00397 { 00398 TQByteArray buffer; 00399 TQDataStream stream(buffer,IO_WriteOnly); 00400 if (!sender) { 00401 sender = gameId(); 00402 } 00403 00404 TQ_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, TQ_UINT32 receiver, TQ_UINT32 sender) 00439 { return sendSystemMessage(data,msgid+KGameMessage::IdUser,receiver,sender); } 00440 00441 bool KGameNetwork::sendMessage(const TQString &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender) 00442 { return sendSystemMessage(msg,msgid+KGameMessage::IdUser,receiver,sender); } 00443 00444 bool KGameNetwork::sendMessage(const TQDataStream &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender) 00445 { return sendSystemMessage(msg, msgid+KGameMessage::IdUser, receiver, sender); } 00446 00447 bool KGameNetwork::sendMessage(const TQByteArray &msg, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender) 00448 { return sendSystemMessage(msg, msgid+KGameMessage::IdUser, receiver, sender); } 00449 00450 void KGameNetwork::sendError(int error,const TQByteArray& message, TQ_UINT32 receiver, TQ_UINT32 sender) 00451 { 00452 TQByteArray buffer; 00453 TQDataStream stream(buffer,IO_WriteOnly); 00454 stream << (TQ_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 TQByteArray& receiveBuffer, TQ_UINT32 clientID) 00462 { 00463 TQDataStream stream(receiveBuffer, IO_ReadOnly); 00464 int msgid; 00465 TQ_UINT32 sender; // the id of the KGame/KPlayer who sent the message 00466 TQ_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 TQString text; 00484 TQ_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 */