| 1 | /* | 
|---|
| 2 |    orxonox - the future of 3D-vertical-scrollers | 
|---|
| 3 |  | 
|---|
| 4 |    Copyright (C) 2004 orx | 
|---|
| 5 |  | 
|---|
| 6 |    This program is free software; you can redistribute it and/or modify | 
|---|
| 7 |    it under the terms of the GNU General Public License as published by | 
|---|
| 8 |    the Free Software Foundation; either version 2, or (at your option) | 
|---|
| 9 |    any later version. | 
|---|
| 10 |  | 
|---|
| 11 | ### File Specific: | 
|---|
| 12 |    main-programmer: Christoph Renner rennerc@ee.ethz.ch | 
|---|
| 13 |    co-programmer:   Patrick Boenzli  boenzlip@orxonox.ethz.ch | 
|---|
| 14 | */ | 
|---|
| 15 |  | 
|---|
| 16 |  | 
|---|
| 17 | #define DEBUG_MODULE_NETWORK | 
|---|
| 18 |  | 
|---|
| 19 |  | 
|---|
| 20 | #include "base_object.h" | 
|---|
| 21 | #include "network_protocol.h" | 
|---|
| 22 | #include "udp_socket.h" | 
|---|
| 23 | #include "udp_server_socket.h" | 
|---|
| 24 | #include "connection_monitor.h" | 
|---|
| 25 | #include "synchronizeable.h" | 
|---|
| 26 | #include "network_game_manager.h" | 
|---|
| 27 | #include "shared_network_data.h" | 
|---|
| 28 | #include "message_manager.h" | 
|---|
| 29 | #include "preferences.h" | 
|---|
| 30 | #include "zip.h" | 
|---|
| 31 |  | 
|---|
| 32 | #include "src/lib/util/loading/resource_manager.h" | 
|---|
| 33 |  | 
|---|
| 34 | #include "network_log.h" | 
|---|
| 35 |  | 
|---|
| 36 | #include "player_stats.h" | 
|---|
| 37 |  | 
|---|
| 38 | #include "lib/util/loading/factory.h" | 
|---|
| 39 |  | 
|---|
| 40 | #include "debug.h" | 
|---|
| 41 | #include "class_list.h" | 
|---|
| 42 | #include <algorithm> | 
|---|
| 43 |  | 
|---|
| 44 | /* include your own header */ | 
|---|
| 45 | #include "network_stream.h" | 
|---|
| 46 |  | 
|---|
| 47 | /* probably unnecessary */ | 
|---|
| 48 | using namespace std; | 
|---|
| 49 |  | 
|---|
| 50 |  | 
|---|
| 51 | #define PACKAGE_SIZE  256 | 
|---|
| 52 |  | 
|---|
| 53 |  | 
|---|
| 54 | NetworkStream::NetworkStream() | 
|---|
| 55 |     : DataStream() | 
|---|
| 56 | { | 
|---|
| 57 |   this->init(); | 
|---|
| 58 |   /* initialize the references */ | 
|---|
| 59 |   this->type = NET_CLIENT; | 
|---|
| 60 | } | 
|---|
| 61 |  | 
|---|
| 62 |  | 
|---|
| 63 | /** | 
|---|
| 64 |  * connect to a server as a client | 
|---|
| 65 |  *  @param host: host name (address) | 
|---|
| 66 |  *  @param port: port number | 
|---|
| 67 |  */ | 
|---|
| 68 | NetworkStream::NetworkStream( std::string host, int port ) | 
|---|
| 69 | { | 
|---|
| 70 |   this->type = NET_CLIENT; | 
|---|
| 71 |   this->init(); | 
|---|
| 72 |   this->peers[0].socket = new UdpSocket( host, port ); | 
|---|
| 73 |   this->peers[0].userId = 0; | 
|---|
| 74 |   this->peers[0].isServer = true; | 
|---|
| 75 |   this->peers[0].connectionMonitor = new ConnectionMonitor( 0 ); | 
|---|
| 76 | } | 
|---|
| 77 |  | 
|---|
| 78 |  | 
|---|
| 79 | /** | 
|---|
| 80 |  * start as a server | 
|---|
| 81 |  *  @param port: at this port | 
|---|
| 82 |  */ | 
|---|
| 83 | NetworkStream::NetworkStream( int port ) | 
|---|
| 84 | { | 
|---|
| 85 |   this->type = NET_SERVER; | 
|---|
| 86 |   this->init(); | 
|---|
| 87 |   this->serverSocket = new UdpServerSocket(port); | 
|---|
| 88 |   this->bActive = true; | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 |  | 
|---|
| 92 | /** | 
|---|
| 93 |  * generic init functions | 
|---|
| 94 |  */ | 
|---|
| 95 | void NetworkStream::init() | 
|---|
| 96 | { | 
|---|
| 97 |   /* set the class id for the base object */ | 
|---|
| 98 |   this->setClassID(CL_NETWORK_STREAM, "NetworkStream"); | 
|---|
| 99 |   this->bActive = false; | 
|---|
| 100 |   this->serverSocket = NULL; | 
|---|
| 101 |   this->networkGameManager = NULL; | 
|---|
| 102 |   myHostId = 0; | 
|---|
| 103 |   currentState = 0; | 
|---|
| 104 |  | 
|---|
| 105 |   remainingBytesToWriteToDict = Preferences::getInstance()->getInt( "compression", "writedict", 0 ); | 
|---|
| 106 |  | 
|---|
| 107 |   assert( Zip::getInstance()->loadDictionary( "testdict" ) >= 0 ); | 
|---|
| 108 |   this->dictClient = Zip::getInstance()->loadDictionary( "dict2pl_client" ); | 
|---|
| 109 |   assert( this->dictClient >= 0 ); | 
|---|
| 110 |   this->dictServer = Zip::getInstance()->loadDictionary( "dict2p_server" ); | 
|---|
| 111 |   assert( this->dictServer >= 0 ); | 
|---|
| 112 | } | 
|---|
| 113 |  | 
|---|
| 114 |  | 
|---|
| 115 | /** | 
|---|
| 116 |  * deconstructor | 
|---|
| 117 |  */ | 
|---|
| 118 | NetworkStream::~NetworkStream() | 
|---|
| 119 | { | 
|---|
| 120 |   if ( this->serverSocket ) | 
|---|
| 121 |   { | 
|---|
| 122 |     serverSocket->close(); | 
|---|
| 123 |     delete serverSocket; | 
|---|
| 124 |     serverSocket = NULL; | 
|---|
| 125 |   } | 
|---|
| 126 |   for ( PeerList::iterator i = peers.begin(); i!=peers.end(); i++) | 
|---|
| 127 |   { | 
|---|
| 128 |     if ( i->second.socket ) | 
|---|
| 129 |     { | 
|---|
| 130 |       i->second.socket->disconnectServer(); | 
|---|
| 131 |       delete i->second.socket; | 
|---|
| 132 |       i->second.socket = NULL; | 
|---|
| 133 |     } | 
|---|
| 134 |  | 
|---|
| 135 |     if ( i->second.handshake ) | 
|---|
| 136 |     { | 
|---|
| 137 |       delete i->second.handshake; | 
|---|
| 138 |       i->second.handshake = NULL; | 
|---|
| 139 |     } | 
|---|
| 140 |  | 
|---|
| 141 |     if ( i->second.connectionMonitor ) | 
|---|
| 142 |     { | 
|---|
| 143 |       delete i->second.connectionMonitor; | 
|---|
| 144 |       i->second.connectionMonitor = NULL; | 
|---|
| 145 |     } | 
|---|
| 146 |   } | 
|---|
| 147 |   for ( SynchronizeableList::const_iterator it = getSyncBegin(); it != getSyncEnd(); it ++ ) | 
|---|
| 148 |     (*it)->setNetworkStream( NULL ); | 
|---|
| 149 | } | 
|---|
| 150 |  | 
|---|
| 151 |  | 
|---|
| 152 | /** | 
|---|
| 153 |  * creates a new instance of the network game manager | 
|---|
| 154 |  */ | 
|---|
| 155 | void NetworkStream::createNetworkGameManager() | 
|---|
| 156 | { | 
|---|
| 157 |   this->networkGameManager = NetworkGameManager::getInstance(); | 
|---|
| 158 |   // setUniqueID( maxCon+2 ) because we need one id for every handshake | 
|---|
| 159 |   // and one for handshake to reject client maxCon+1 | 
|---|
| 160 |   this->networkGameManager->setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() ); | 
|---|
| 161 |   MessageManager::getInstance()->setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() ); | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|
| 164 |  | 
|---|
| 165 | /** | 
|---|
| 166 |  * starts the network handshake | 
|---|
| 167 |  */ | 
|---|
| 168 | void NetworkStream::startHandshake() | 
|---|
| 169 | { | 
|---|
| 170 |   Handshake* hs = new Handshake(false); | 
|---|
| 171 |   hs->setUniqueID( 0 ); | 
|---|
| 172 |   assert( peers[0].handshake == NULL ); | 
|---|
| 173 |   peers[0].handshake = hs; | 
|---|
| 174 |  | 
|---|
| 175 |   hs->setPreferedNickName( Preferences::getInstance()->getString( "multiplayer", "nickname", "Player" ) ); | 
|---|
| 176 |  | 
|---|
| 177 | //   peers[0].handshake->setSynchronized( true ); | 
|---|
| 178 |   //this->connectSynchronizeable(*hs); | 
|---|
| 179 |   //this->connectSynchronizeable(*hs); | 
|---|
| 180 |   PRINTF(0)("NetworkStream: Handshake created: %s\n", hs->getName()); | 
|---|
| 181 | } | 
|---|
| 182 |  | 
|---|
| 183 |  | 
|---|
| 184 | /** | 
|---|
| 185 |  * this functions connects a synchronizeable to the networkstream, therefore synchronizeing | 
|---|
| 186 |  * it all over the network and creating it on the other platforms (if and only if it is a | 
|---|
| 187 |  * server | 
|---|
| 188 |  */ | 
|---|
| 189 | void NetworkStream::connectSynchronizeable(Synchronizeable& sync) | 
|---|
| 190 | { | 
|---|
| 191 |   this->synchronizeables.push_back(&sync); | 
|---|
| 192 |   sync.setNetworkStream( this ); | 
|---|
| 193 |  | 
|---|
| 194 |   this->bActive = true; | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 |  | 
|---|
| 198 | /** | 
|---|
| 199 |  * removes the synchronizeable from the list of synchronized entities | 
|---|
| 200 |  */ | 
|---|
| 201 | void NetworkStream::disconnectSynchronizeable(Synchronizeable& sync) | 
|---|
| 202 | { | 
|---|
| 203 |   // removing the Synchronizeable from the List. | 
|---|
| 204 |   std::list<Synchronizeable*>::iterator disconnectSynchro = std::find(this->synchronizeables.begin(), this->synchronizeables.end(), &sync); | 
|---|
| 205 |   if (disconnectSynchro != this->synchronizeables.end()) | 
|---|
| 206 |     this->synchronizeables.erase(disconnectSynchro); | 
|---|
| 207 |  | 
|---|
| 208 |   oldSynchronizeables[sync.getUniqueID()] = SDL_GetTicks(); | 
|---|
| 209 | } | 
|---|
| 210 |  | 
|---|
| 211 |  | 
|---|
| 212 | /** | 
|---|
| 213 |  * this is called to process data from the network socket to the synchronizeable and vice versa | 
|---|
| 214 |  */ | 
|---|
| 215 | void NetworkStream::processData() | 
|---|
| 216 | { | 
|---|
| 217 |   int tick = SDL_GetTicks(); | 
|---|
| 218 |  | 
|---|
| 219 |   currentState++; | 
|---|
| 220 |  | 
|---|
| 221 |   if ( this->type == NET_SERVER ) | 
|---|
| 222 |   { | 
|---|
| 223 |     if ( serverSocket ) | 
|---|
| 224 |       serverSocket->update(); | 
|---|
| 225 |  | 
|---|
| 226 |     this->updateConnectionList(); | 
|---|
| 227 |   } | 
|---|
| 228 |   else | 
|---|
| 229 |   { | 
|---|
| 230 |     // check if the connection is ok else terminate and remove | 
|---|
| 231 |     if ( peers[0].socket && ( !peers[0].socket->isOk() || peers[0].connectionMonitor->hasTimedOut() ) ) | 
|---|
| 232 |     { | 
|---|
| 233 |       PRINTF(1)("lost connection to server\n"); | 
|---|
| 234 |  | 
|---|
| 235 |       peers[0].socket->disconnectServer(); | 
|---|
| 236 |       delete peers[0].socket; | 
|---|
| 237 |       peers[0].socket = NULL; | 
|---|
| 238 |  | 
|---|
| 239 |       if ( peers[0].handshake ) | 
|---|
| 240 |         delete peers[0].handshake; | 
|---|
| 241 |       peers[0].handshake = NULL; | 
|---|
| 242 |  | 
|---|
| 243 |       if ( peers[0].connectionMonitor ) | 
|---|
| 244 |         delete peers[0].connectionMonitor; | 
|---|
| 245 |       peers[0].connectionMonitor = NULL; | 
|---|
| 246 |     } | 
|---|
| 247 |   } | 
|---|
| 248 |  | 
|---|
| 249 |   cleanUpOldSyncList(); | 
|---|
| 250 |   handleHandshakes(); | 
|---|
| 251 |  | 
|---|
| 252 |   // order of up/downstream is important!!!! | 
|---|
| 253 |   // don't change it | 
|---|
| 254 |   handleDownstream( tick ); | 
|---|
| 255 |   handleUpstream( tick ); | 
|---|
| 256 | } | 
|---|
| 257 |  | 
|---|
| 258 |  | 
|---|
| 259 | /** | 
|---|
| 260 |  * if we are a server update the connection list to accept new connections (clients) | 
|---|
| 261 |  * also start the handsake for the new clients | 
|---|
| 262 |  */ | 
|---|
| 263 | void NetworkStream::updateConnectionList( ) | 
|---|
| 264 | { | 
|---|
| 265 |   //check for new connections | 
|---|
| 266 |  | 
|---|
| 267 |   NetworkSocket* tempNetworkSocket = serverSocket->getNewSocket(); | 
|---|
| 268 |  | 
|---|
| 269 |   // we got new network node | 
|---|
| 270 |   if ( tempNetworkSocket ) | 
|---|
| 271 |   { | 
|---|
| 272 |     int clientId; | 
|---|
| 273 |     // if there is a list of free client id slots, take these | 
|---|
| 274 |     if ( freeSocketSlots.size() > 0 ) | 
|---|
| 275 |     { | 
|---|
| 276 |       clientId = freeSocketSlots.back(); | 
|---|
| 277 |       freeSocketSlots.pop_back(); | 
|---|
| 278 |       peers[clientId].socket = tempNetworkSocket; | 
|---|
| 279 |       peers[clientId].handshake = new Handshake(true, clientId, this->networkGameManager->getUniqueID(), MessageManager::getInstance()->getUniqueID() ); | 
|---|
| 280 |       peers[clientId].connectionMonitor = new ConnectionMonitor( clientId ); | 
|---|
| 281 |       peers[clientId].handshake->setUniqueID(clientId); | 
|---|
| 282 |       peers[clientId].userId = clientId; | 
|---|
| 283 |       peers[clientId].isServer = false; | 
|---|
| 284 |     } | 
|---|
| 285 |     else | 
|---|
| 286 |     { | 
|---|
| 287 |       clientId = 1; | 
|---|
| 288 |  | 
|---|
| 289 |       for ( PeerList::iterator it = peers.begin(); it != peers.end(); it++ ) | 
|---|
| 290 |         if ( it->first >= clientId ) | 
|---|
| 291 |           clientId = it->first + 1; | 
|---|
| 292 |  | 
|---|
| 293 |       peers[clientId].socket = tempNetworkSocket; | 
|---|
| 294 |       peers[clientId].handshake = new Handshake(true, clientId, this->networkGameManager->getUniqueID(), MessageManager::getInstance()->getUniqueID()); | 
|---|
| 295 |       peers[clientId].handshake->setUniqueID(clientId); | 
|---|
| 296 |       peers[clientId].connectionMonitor = new ConnectionMonitor( clientId ); | 
|---|
| 297 |       peers[clientId].userId = clientId; | 
|---|
| 298 |       peers[clientId].isServer = false; | 
|---|
| 299 |  | 
|---|
| 300 |       PRINTF(0)("num sync: %d\n", synchronizeables.size()); | 
|---|
| 301 |     } | 
|---|
| 302 |  | 
|---|
| 303 |     // check if there are too many clients connected | 
|---|
| 304 |     if ( clientId > MAX_CONNECTIONS ) | 
|---|
| 305 |     { | 
|---|
| 306 |       peers[clientId].handshake->doReject( "too many connections" ); | 
|---|
| 307 |       PRINTF(0)("Will reject client %d because there are to many connections!\n", clientId); | 
|---|
| 308 |     } | 
|---|
| 309 |     else | 
|---|
| 310 |     { | 
|---|
| 311 |       PRINTF(0)("New Client: %d\n", clientId); | 
|---|
| 312 |     } | 
|---|
| 313 |  | 
|---|
| 314 |     //this->connectSynchronizeable(*handshakes[clientId]); | 
|---|
| 315 |   } | 
|---|
| 316 |  | 
|---|
| 317 |  | 
|---|
| 318 |  | 
|---|
| 319 |   //check if connections are ok else remove them | 
|---|
| 320 |   for ( PeerList::iterator it = peers.begin(); it != peers.end(); ) | 
|---|
| 321 |   { | 
|---|
| 322 |     if ( | 
|---|
| 323 |           it->second.socket && | 
|---|
| 324 |           ( | 
|---|
| 325 |             !it->second.socket->isOk()  || | 
|---|
| 326 |             it->second.connectionMonitor->hasTimedOut() | 
|---|
| 327 |           ) | 
|---|
| 328 |        ) | 
|---|
| 329 |     { | 
|---|
| 330 |       std::string reason = "disconnected"; | 
|---|
| 331 |       if ( it->second.connectionMonitor->hasTimedOut() ) | 
|---|
| 332 |         reason = "timeout"; | 
|---|
| 333 |       PRINTF(0)("Client is gone: %d (%s)\n", it->second.userId, reason.c_str()); | 
|---|
| 334 |  | 
|---|
| 335 |  | 
|---|
| 336 |       // clean up the network data | 
|---|
| 337 |       it->second.socket->disconnectServer(); | 
|---|
| 338 |       delete it->second.socket; | 
|---|
| 339 |       it->second.socket = NULL; | 
|---|
| 340 |  | 
|---|
| 341 |       if ( it->second.connectionMonitor ) | 
|---|
| 342 |         delete it->second.connectionMonitor; | 
|---|
| 343 |       it->second.connectionMonitor = NULL; | 
|---|
| 344 |  | 
|---|
| 345 |       if ( it->second.handshake ) | 
|---|
| 346 |         delete it->second.handshake; | 
|---|
| 347 |       it->second.handshake = NULL; | 
|---|
| 348 |  | 
|---|
| 349 |       for ( SynchronizeableList::iterator it2 = synchronizeables.begin(); it2 != synchronizeables.end(); it2++ ) | 
|---|
| 350 |       { | 
|---|
| 351 |         (*it2)->cleanUpUser( it->second.userId ); | 
|---|
| 352 |       } | 
|---|
| 353 |  | 
|---|
| 354 |       NetworkGameManager::getInstance()->signalLeftPlayer(it->second.userId); | 
|---|
| 355 |  | 
|---|
| 356 |       freeSocketSlots.push_back( it->second.userId ); | 
|---|
| 357 |  | 
|---|
| 358 |       PeerList::iterator delit = it; | 
|---|
| 359 |       it++; | 
|---|
| 360 |  | 
|---|
| 361 |       peers.erase( delit ); | 
|---|
| 362 |  | 
|---|
| 363 |       continue; | 
|---|
| 364 |     } | 
|---|
| 365 |  | 
|---|
| 366 |     it++; | 
|---|
| 367 |   } | 
|---|
| 368 |  | 
|---|
| 369 |  | 
|---|
| 370 | } | 
|---|
| 371 |  | 
|---|
| 372 |  | 
|---|
| 373 | void NetworkStream::debug() | 
|---|
| 374 | { | 
|---|
| 375 |   if( this->isServer()) | 
|---|
| 376 |     PRINT(0)(" Host ist Server with ID: %i\n", this->myHostId); | 
|---|
| 377 |   else | 
|---|
| 378 |     PRINT(0)(" Host ist Client with ID: %i\n", this->myHostId); | 
|---|
| 379 |  | 
|---|
| 380 |   PRINT(0)(" Got %i connected Synchronizeables, showing active Syncs:\n", this->synchronizeables.size()); | 
|---|
| 381 |   for (SynchronizeableList::iterator it = synchronizeables.begin(); it!=synchronizeables.end(); it++) | 
|---|
| 382 |   { | 
|---|
| 383 |     if( (*it)->beSynchronized() == true) | 
|---|
| 384 |       PRINT(0)("  Synchronizeable of class: %s::%s, with unique ID: %i, Synchronize: %i\n", (*it)->getClassName(), (*it)->getName(), | 
|---|
| 385 |                (*it)->getUniqueID(), (*it)->beSynchronized()); | 
|---|
| 386 |   } | 
|---|
| 387 |   PRINT(0)(" Maximal Connections: %i\n", MAX_CONNECTIONS ); | 
|---|
| 388 |  | 
|---|
| 389 | } | 
|---|
| 390 |  | 
|---|
| 391 |  | 
|---|
| 392 | /** | 
|---|
| 393 |  * @returns the number of synchronizeables registered to this stream | 
|---|
| 394 |  */ | 
|---|
| 395 | int NetworkStream::getSyncCount() | 
|---|
| 396 | { | 
|---|
| 397 |   int n = 0; | 
|---|
| 398 |   for (SynchronizeableList::iterator it = synchronizeables.begin(); it!=synchronizeables.end(); it++) | 
|---|
| 399 |     if( (*it)->beSynchronized() == true) | 
|---|
| 400 |       ++n; | 
|---|
| 401 |  | 
|---|
| 402 |   //return synchronizeables.size(); | 
|---|
| 403 |   return n; | 
|---|
| 404 | } | 
|---|
| 405 |  | 
|---|
| 406 |  | 
|---|
| 407 | /** | 
|---|
| 408 |  * check if handshakes completed. if so create the network game manager else remove it again | 
|---|
| 409 |  */ | 
|---|
| 410 | void NetworkStream::handleHandshakes( ) | 
|---|
| 411 | { | 
|---|
| 412 |   for ( PeerList::iterator it = peers.begin(); it != peers.end(); it++ ) | 
|---|
| 413 |   { | 
|---|
| 414 |     if ( it->second.handshake ) | 
|---|
| 415 |     { | 
|---|
| 416 |       if ( it->second.handshake->completed() ) | 
|---|
| 417 |       { | 
|---|
| 418 |         if ( it->second.handshake->ok() ) | 
|---|
| 419 |         { | 
|---|
| 420 |           if ( !it->second.handshake->allowDel() ) | 
|---|
| 421 |           { | 
|---|
| 422 |             if ( type != NET_SERVER ) | 
|---|
| 423 |             { | 
|---|
| 424 |               SharedNetworkData::getInstance()->setHostID( it->second.handshake->getHostId() ); | 
|---|
| 425 |               myHostId = SharedNetworkData::getInstance()->getHostID(); | 
|---|
| 426 |  | 
|---|
| 427 |               this->networkGameManager = NetworkGameManager::getInstance(); | 
|---|
| 428 |               this->networkGameManager->setUniqueID( it->second.handshake->getNetworkGameManagerId() ); | 
|---|
| 429 |               MessageManager::getInstance()->setUniqueID( it->second.handshake->getMessageManagerId() ); | 
|---|
| 430 |             } | 
|---|
| 431 |  | 
|---|
| 432 |  | 
|---|
| 433 |             PRINT(0)("handshake finished id=%d\n", it->second.handshake->getNetworkGameManagerId()); | 
|---|
| 434 |  | 
|---|
| 435 |             it->second.handshake->del(); | 
|---|
| 436 |           } | 
|---|
| 437 |           else | 
|---|
| 438 |           { | 
|---|
| 439 |             if ( it->second.handshake->canDel() ) | 
|---|
| 440 |             { | 
|---|
| 441 |               if ( type == NET_SERVER ) | 
|---|
| 442 |               { | 
|---|
| 443 |                 handleNewClient( it->second.userId ); | 
|---|
| 444 |  | 
|---|
| 445 |                 if ( PlayerStats::getStats( it->second.userId ) && it->second.handshake->getPreferedNickName() != "" ) | 
|---|
| 446 |                 { | 
|---|
| 447 |                   PlayerStats::getStats( it->second.userId )->setNickName( it->second.handshake->getPreferedNickName() ); | 
|---|
| 448 |                 } | 
|---|
| 449 |               } | 
|---|
| 450 |  | 
|---|
| 451 |               PRINT(0)("handshake finished delete it\n"); | 
|---|
| 452 |               delete it->second.handshake; | 
|---|
| 453 |               it->second.handshake = NULL; | 
|---|
| 454 |             } | 
|---|
| 455 |           } | 
|---|
| 456 |  | 
|---|
| 457 |         } | 
|---|
| 458 |         else | 
|---|
| 459 |         { | 
|---|
| 460 |           PRINT(1)("handshake failed!\n"); | 
|---|
| 461 |           it->second.socket->disconnectServer(); | 
|---|
| 462 |         } | 
|---|
| 463 |       } | 
|---|
| 464 |     } | 
|---|
| 465 |   } | 
|---|
| 466 | } | 
|---|
| 467 |  | 
|---|
| 468 |  | 
|---|
| 469 | /** | 
|---|
| 470 |  * handle upstream network traffic | 
|---|
| 471 |  */ | 
|---|
| 472 | void NetworkStream::handleUpstream( int tick ) | 
|---|
| 473 | { | 
|---|
| 474 |   int offset; | 
|---|
| 475 |   int n; | 
|---|
| 476 |  | 
|---|
| 477 |   for ( PeerList::reverse_iterator peer = peers.rbegin(); peer != peers.rend(); peer++ ) | 
|---|
| 478 |   { | 
|---|
| 479 |     offset = INTSIZE; // reserve enough space for the packet length | 
|---|
| 480 |  | 
|---|
| 481 |     // continue with the next peer if this peer has no socket assigned (therefore no network) | 
|---|
| 482 |     if ( !peer->second.socket ) | 
|---|
| 483 |       continue; | 
|---|
| 484 |  | 
|---|
| 485 |     // header informations: current state | 
|---|
| 486 |     n = Converter::intToByteArray( currentState, buf + offset, UDP_PACKET_SIZE - offset ); | 
|---|
| 487 |     assert( n == INTSIZE ); | 
|---|
| 488 |     offset += n; | 
|---|
| 489 |  | 
|---|
| 490 |     // header informations: last acked state | 
|---|
| 491 |     n = Converter::intToByteArray( peer->second.lastAckedState, buf + offset, UDP_PACKET_SIZE - offset ); | 
|---|
| 492 |     assert( n == INTSIZE ); | 
|---|
| 493 |     offset += n; | 
|---|
| 494 |  | 
|---|
| 495 |     // header informations: last recved state | 
|---|
| 496 |     n = Converter::intToByteArray( peer->second.lastRecvedState, buf + offset, UDP_PACKET_SIZE - offset ); | 
|---|
| 497 |     assert( n == INTSIZE ); | 
|---|
| 498 |     offset += n; | 
|---|
| 499 |  | 
|---|
| 500 |     // now write all synchronizeables in the packet | 
|---|
| 501 |     for ( SynchronizeableList::iterator it = synchronizeables.begin(); it != synchronizeables.end(); it++ ) | 
|---|
| 502 |     { | 
|---|
| 503 |       int oldOffset = offset; | 
|---|
| 504 |       Synchronizeable & sync = **it; | 
|---|
| 505 |  | 
|---|
| 506 |       // do not include synchronizeables with uninit id and syncs that don't want to be synchronized | 
|---|
| 507 |       if ( !sync.beSynchronized() || sync.getUniqueID() < 0 ) | 
|---|
| 508 |         continue; | 
|---|
| 509 |  | 
|---|
| 510 |       // if handshake not finished only sync handshake | 
|---|
| 511 |       if ( peer->second.handshake && sync.getLeafClassID() != CL_HANDSHAKE ) | 
|---|
| 512 |         continue; | 
|---|
| 513 |  | 
|---|
| 514 |       // if we are a server and this is not our handshake | 
|---|
| 515 |       if ( isServer() && sync.getLeafClassID() == CL_HANDSHAKE && sync.getUniqueID() != peer->second.userId ) | 
|---|
| 516 |         continue; | 
|---|
| 517 |  | 
|---|
| 518 |       /* list of synchronizeables that will never be synchronized over the network: */ | 
|---|
| 519 |       // do not sync null parent | 
|---|
| 520 |       if ( sync.getLeafClassID() == CL_NULL_PARENT ) | 
|---|
| 521 |         continue; | 
|---|
| 522 |  | 
|---|
| 523 |       assert( offset + INTSIZE <= UDP_PACKET_SIZE ); | 
|---|
| 524 |  | 
|---|
| 525 |       // server fakes uniqueid == 0 for handshake | 
|---|
| 526 |       if ( this->isServer() && sync.getUniqueID() < MAX_CONNECTIONS - 1 ) | 
|---|
| 527 |         n = Converter::intToByteArray( 0, buf + offset, UDP_PACKET_SIZE - offset ); | 
|---|
| 528 |       else | 
|---|
| 529 |         n = Converter::intToByteArray( sync.getUniqueID(), buf + offset, UDP_PACKET_SIZE - offset ); | 
|---|
| 530 |  | 
|---|
| 531 |       assert( n == INTSIZE ); | 
|---|
| 532 |       offset += n; | 
|---|
| 533 |  | 
|---|
| 534 |       // make space for size | 
|---|
| 535 |       offset += INTSIZE; | 
|---|
| 536 |  | 
|---|
| 537 |       n = sync.getStateDiff( peer->second.userId, buf + offset, UDP_PACKET_SIZE-offset, currentState, peer->second.lastAckedState, -1000 ); | 
|---|
| 538 |       offset += n; | 
|---|
| 539 |  | 
|---|
| 540 |       assert( Converter::intToByteArray( n, buf + offset - n - INTSIZE, INTSIZE ) == INTSIZE ); | 
|---|
| 541 |  | 
|---|
| 542 |       // check if all data bytes == 0 -> remove data and the synchronizeable from the sync process since there is no update | 
|---|
| 543 |       // TODO not all synchronizeables like this maybe add Synchronizeable::canRemoveZeroDiff() | 
|---|
| 544 |       bool allZero = true; | 
|---|
| 545 |       for ( int i = 0; i < n; i++ ) | 
|---|
| 546 |       { | 
|---|
| 547 |          if ( buf[i+oldOffset+2*INTSIZE] != 0 ) | 
|---|
| 548 |            allZero = false; | 
|---|
| 549 |       } | 
|---|
| 550 |       // if there is no new data in this synchronizeable reset the data offset to the last state -> dont synchronizes | 
|---|
| 551 |       // data that hast not changed | 
|---|
| 552 |       if ( allZero ) | 
|---|
| 553 |       { | 
|---|
| 554 |         offset = oldOffset; | 
|---|
| 555 |       } | 
|---|
| 556 |     } // all synchronizeables written | 
|---|
| 557 |  | 
|---|
| 558 |  | 
|---|
| 559 |  | 
|---|
| 560 |     for ( SynchronizeableList::iterator it = synchronizeables.begin(); it != synchronizeables.end(); it++ ) | 
|---|
| 561 |     { | 
|---|
| 562 |       Synchronizeable & sync = **it; | 
|---|
| 563 |  | 
|---|
| 564 |       if ( !sync.beSynchronized() || sync.getUniqueID() < 0 ) | 
|---|
| 565 |         continue; | 
|---|
| 566 |  | 
|---|
| 567 |       sync.handleSentState( peer->second.userId, currentState, peer->second.lastAckedState ); | 
|---|
| 568 |     } | 
|---|
| 569 |  | 
|---|
| 570 |  | 
|---|
| 571 |     assert( Converter::intToByteArray( offset, buf, INTSIZE ) == INTSIZE ); | 
|---|
| 572 |  | 
|---|
| 573 |     // now compress the data with the zip library | 
|---|
| 574 |     int compLength = 0; | 
|---|
| 575 |     if ( this->isServer() ) | 
|---|
| 576 |       compLength = Zip::getInstance()->zip( buf, offset, compBuf, UDP_PACKET_SIZE, dictServer ); | 
|---|
| 577 |     else | 
|---|
| 578 |       compLength = Zip::getInstance()->zip( buf, offset, compBuf, UDP_PACKET_SIZE, dictClient ); | 
|---|
| 579 |  | 
|---|
| 580 |     if ( compLength <= 0 ) | 
|---|
| 581 |     { | 
|---|
| 582 |       PRINTF(1)("compression failed!\n"); | 
|---|
| 583 |       continue; | 
|---|
| 584 |     } | 
|---|
| 585 |  | 
|---|
| 586 |     assert( peer->second.socket->writePacket( compBuf, compLength ) ); | 
|---|
| 587 |  | 
|---|
| 588 |     if ( this->remainingBytesToWriteToDict > 0 ) | 
|---|
| 589 |       writeToNewDict( buf, offset, true ); | 
|---|
| 590 |  | 
|---|
| 591 |     peer->second.connectionMonitor->processUnzippedOutgoingPacket( tick, buf, offset, currentState ); | 
|---|
| 592 |     peer->second.connectionMonitor->processZippedOutgoingPacket( tick, compBuf, compLength, currentState ); | 
|---|
| 593 |  | 
|---|
| 594 |   } | 
|---|
| 595 | } | 
|---|
| 596 |  | 
|---|
| 597 | /** | 
|---|
| 598 |  * handle downstream network traffic | 
|---|
| 599 |  */ | 
|---|
| 600 | void NetworkStream::handleDownstream( int tick ) | 
|---|
| 601 | { | 
|---|
| 602 |   int offset = 0; | 
|---|
| 603 |  | 
|---|
| 604 |   int length = 0; | 
|---|
| 605 |   int packetLength = 0; | 
|---|
| 606 |   int compLength = 0; | 
|---|
| 607 |   int uniqueId = 0; | 
|---|
| 608 |   int state = 0; | 
|---|
| 609 |   int ackedState = 0; | 
|---|
| 610 |   int fromState = 0; | 
|---|
| 611 |   int syncDataLength = 0; | 
|---|
| 612 |  | 
|---|
| 613 |   for ( PeerList::iterator peer = peers.begin(); peer != peers.end(); peer++ ) | 
|---|
| 614 |   { | 
|---|
| 615 |  | 
|---|
| 616 |     if ( !peer->second.socket ) | 
|---|
| 617 |       continue; | 
|---|
| 618 |  | 
|---|
| 619 |     while ( 0 < (compLength = peer->second.socket->readPacket( compBuf, UDP_PACKET_SIZE )) ) | 
|---|
| 620 |     { | 
|---|
| 621 |       peer->second.connectionMonitor->processZippedIncomingPacket( tick, compBuf, compLength ); | 
|---|
| 622 |  | 
|---|
| 623 |       packetLength = Zip::getInstance()->unZip( compBuf, compLength, buf, UDP_PACKET_SIZE ); | 
|---|
| 624 |  | 
|---|
| 625 |       if ( packetLength < 4*INTSIZE ) | 
|---|
| 626 |       { | 
|---|
| 627 |         if ( packetLength != 0 ) | 
|---|
| 628 |           PRINTF(1)("got too small packet: %d\n", packetLength); | 
|---|
| 629 |         continue; | 
|---|
| 630 |       } | 
|---|
| 631 |  | 
|---|
| 632 |       if ( this->remainingBytesToWriteToDict > 0 ) | 
|---|
| 633 |         writeToNewDict( buf, packetLength, false ); | 
|---|
| 634 |  | 
|---|
| 635 |       assert( Converter::byteArrayToInt( buf, &length ) == INTSIZE ); | 
|---|
| 636 |       assert( Converter::byteArrayToInt( buf + INTSIZE, &state ) == INTSIZE ); | 
|---|
| 637 |       assert( Converter::byteArrayToInt( buf + 2*INTSIZE, &fromState ) == INTSIZE ); | 
|---|
| 638 |       assert( Converter::byteArrayToInt( buf + 3*INTSIZE, &ackedState ) == INTSIZE ); | 
|---|
| 639 |       //NETPRINTF(n)("ackedstate: %d\n", ackedState); | 
|---|
| 640 |       offset = 4*INTSIZE; | 
|---|
| 641 |  | 
|---|
| 642 |       peer->second.connectionMonitor->processUnzippedIncomingPacket( tick, buf, packetLength, state, ackedState ); | 
|---|
| 643 |  | 
|---|
| 644 |       //NETPRINTF(n)("got packet: %d, %d\n", length, packetLength); | 
|---|
| 645 |  | 
|---|
| 646 |     //if this is an old state drop it | 
|---|
| 647 |       if ( state <= peer->second.lastRecvedState ) | 
|---|
| 648 |         continue; | 
|---|
| 649 |  | 
|---|
| 650 |       if ( packetLength != length ) | 
|---|
| 651 |       { | 
|---|
| 652 |         PRINTF(1)("real packet length (%d) and transmitted packet length (%d) do not match!\n", packetLength, length); | 
|---|
| 653 |         peer->second.socket->disconnectServer(); | 
|---|
| 654 |         continue; | 
|---|
| 655 |       } | 
|---|
| 656 |  | 
|---|
| 657 |       while ( offset + 2*INTSIZE < length ) | 
|---|
| 658 |       { | 
|---|
| 659 |         assert( offset > 0 ); | 
|---|
| 660 |         assert( Converter::byteArrayToInt( buf + offset, &uniqueId ) == INTSIZE ); | 
|---|
| 661 |         offset += INTSIZE; | 
|---|
| 662 |  | 
|---|
| 663 |         assert( Converter::byteArrayToInt( buf + offset, &syncDataLength ) == INTSIZE ); | 
|---|
| 664 |         offset += INTSIZE; | 
|---|
| 665 |  | 
|---|
| 666 |         assert( syncDataLength > 0 ); | 
|---|
| 667 |         assert( syncDataLength < 10000 ); | 
|---|
| 668 |  | 
|---|
| 669 |         Synchronizeable * sync = NULL; | 
|---|
| 670 |  | 
|---|
| 671 |         for ( SynchronizeableList::iterator it = synchronizeables.begin(); it != synchronizeables.end(); it++ ) | 
|---|
| 672 |         { | 
|---|
| 673 |         //                                        client thinks his handshake has id 0!!!!! | 
|---|
| 674 |           if ( (*it)->getUniqueID() == uniqueId || ( uniqueId == 0 && (*it)->getUniqueID() == peer->second.userId ) ) | 
|---|
| 675 |           { | 
|---|
| 676 |             sync = *it; | 
|---|
| 677 |             break; | 
|---|
| 678 |           } | 
|---|
| 679 |         } | 
|---|
| 680 |  | 
|---|
| 681 |         if ( sync == NULL ) | 
|---|
| 682 |         { | 
|---|
| 683 |           PRINTF(0)("could not find sync with id %d. try to create it\n", uniqueId); | 
|---|
| 684 |           if ( oldSynchronizeables.find( uniqueId ) != oldSynchronizeables.end() ) | 
|---|
| 685 |           { | 
|---|
| 686 |             offset += syncDataLength; | 
|---|
| 687 |             continue; | 
|---|
| 688 |           } | 
|---|
| 689 |  | 
|---|
| 690 |           if ( !peers[peer->second.userId].isServer ) | 
|---|
| 691 |           { | 
|---|
| 692 |             offset += syncDataLength; | 
|---|
| 693 |             continue; | 
|---|
| 694 |           } | 
|---|
| 695 |  | 
|---|
| 696 |           int leafClassId; | 
|---|
| 697 |           if ( INTSIZE > length - offset ) | 
|---|
| 698 |           { | 
|---|
| 699 |             offset += syncDataLength; | 
|---|
| 700 |             continue; | 
|---|
| 701 |           } | 
|---|
| 702 |  | 
|---|
| 703 |           Converter::byteArrayToInt( buf + offset, &leafClassId ); | 
|---|
| 704 |  | 
|---|
| 705 |           assert( leafClassId != 0 ); | 
|---|
| 706 |  | 
|---|
| 707 |           BaseObject * b = NULL; | 
|---|
| 708 |           /* These are some small exeptions in creation: Not all objects can/should be created via Factory */ | 
|---|
| 709 |           /* Exception 1: NullParent */ | 
|---|
| 710 |           if( leafClassId == CL_NULL_PARENT || leafClassId == CL_SYNCHRONIZEABLE || leafClassId == CL_NETWORK_GAME_MANAGER ) | 
|---|
| 711 |           { | 
|---|
| 712 |             PRINTF(1)("Can not create Class with ID %x!\n", (int)leafClassId); | 
|---|
| 713 |             offset += syncDataLength; | 
|---|
| 714 |             continue; | 
|---|
| 715 |           } | 
|---|
| 716 |           else | 
|---|
| 717 |             b = Factory::fabricate( (ClassID)leafClassId ); | 
|---|
| 718 |  | 
|---|
| 719 |           if ( !b ) | 
|---|
| 720 |           { | 
|---|
| 721 |             PRINTF(1)("Could not fabricate Object with classID %x\n", leafClassId); | 
|---|
| 722 |             offset += syncDataLength; | 
|---|
| 723 |             continue; | 
|---|
| 724 |           } | 
|---|
| 725 |  | 
|---|
| 726 |           if ( b->isA(CL_SYNCHRONIZEABLE) ) | 
|---|
| 727 |           { | 
|---|
| 728 |             sync = dynamic_cast<Synchronizeable*>(b); | 
|---|
| 729 |             sync->setUniqueID( uniqueId ); | 
|---|
| 730 |             sync->setSynchronized(true); | 
|---|
| 731 |  | 
|---|
| 732 |             PRINTF(0)("Fabricated %s with id %d\n", sync->getClassName(), sync->getUniqueID()); | 
|---|
| 733 |           } | 
|---|
| 734 |           else | 
|---|
| 735 |           { | 
|---|
| 736 |             PRINTF(1)("Class with ID %x is not a synchronizeable!\n", (int)leafClassId); | 
|---|
| 737 |             delete b; | 
|---|
| 738 |             offset += syncDataLength; | 
|---|
| 739 |             continue; | 
|---|
| 740 |           } | 
|---|
| 741 |         } | 
|---|
| 742 |  | 
|---|
| 743 |  | 
|---|
| 744 |         int n = sync->setStateDiff( peer->second.userId, buf+offset, syncDataLength, state, fromState ); | 
|---|
| 745 |         offset += n; | 
|---|
| 746 |         //NETPRINTF(0)("SSSSSEEEEETTTTT: %s %d\n",sync->getClassName(), n); | 
|---|
| 747 |  | 
|---|
| 748 |       } | 
|---|
| 749 |  | 
|---|
| 750 |       if ( offset != length ) | 
|---|
| 751 |       { | 
|---|
| 752 |         PRINTF(0)("offset (%d) != length (%d)\n", offset, length); | 
|---|
| 753 |         peer->second.socket->disconnectServer(); | 
|---|
| 754 |       } | 
|---|
| 755 |  | 
|---|
| 756 |  | 
|---|
| 757 |       for ( SynchronizeableList::iterator it = synchronizeables.begin(); it != synchronizeables.end(); it++ ) | 
|---|
| 758 |       { | 
|---|
| 759 |         Synchronizeable & sync = **it; | 
|---|
| 760 |  | 
|---|
| 761 |         if ( !sync.beSynchronized() || sync.getUniqueID() < 0 ) | 
|---|
| 762 |           continue; | 
|---|
| 763 |  | 
|---|
| 764 |         sync.handleRecvState( peer->second.userId, state, fromState ); | 
|---|
| 765 |       } | 
|---|
| 766 |  | 
|---|
| 767 |       assert( peer->second.lastAckedState <= ackedState ); | 
|---|
| 768 |       peer->second.lastAckedState = ackedState; | 
|---|
| 769 |  | 
|---|
| 770 |       assert( peer->second.lastRecvedState < state ); | 
|---|
| 771 |       peer->second.lastRecvedState = state; | 
|---|
| 772 |  | 
|---|
| 773 |     } | 
|---|
| 774 |  | 
|---|
| 775 |   } | 
|---|
| 776 |  | 
|---|
| 777 | } | 
|---|
| 778 |  | 
|---|
| 779 | /** | 
|---|
| 780 |  * is executed when a handshake has finished | 
|---|
| 781 |  * @todo create playable for new user | 
|---|
| 782 |  */ | 
|---|
| 783 | void NetworkStream::handleNewClient( int userId ) | 
|---|
| 784 | { | 
|---|
| 785 |   MessageManager::getInstance()->initUser( userId ); | 
|---|
| 786 |  | 
|---|
| 787 |   networkGameManager->signalNewPlayer( userId ); | 
|---|
| 788 | } | 
|---|
| 789 |  | 
|---|
| 790 | /** | 
|---|
| 791 |  * removes old items from oldSynchronizeables | 
|---|
| 792 |  */ | 
|---|
| 793 | void NetworkStream::cleanUpOldSyncList( ) | 
|---|
| 794 | { | 
|---|
| 795 |   int now = SDL_GetTicks(); | 
|---|
| 796 |  | 
|---|
| 797 |   for ( std::map<int,int>::iterator it = oldSynchronizeables.begin(); it != oldSynchronizeables.end();  ) | 
|---|
| 798 |   { | 
|---|
| 799 |     if ( it->second < now - 10*1000 ) | 
|---|
| 800 |     { | 
|---|
| 801 |       std::map<int,int>::iterator delIt = it; | 
|---|
| 802 |       it++; | 
|---|
| 803 |       oldSynchronizeables.erase( delIt ); | 
|---|
| 804 |       continue; | 
|---|
| 805 |     } | 
|---|
| 806 |     it++; | 
|---|
| 807 |   } | 
|---|
| 808 | } | 
|---|
| 809 |  | 
|---|
| 810 | /** | 
|---|
| 811 |  * writes data to DATA/dicts/newdict | 
|---|
| 812 |  * @param data pointer to data | 
|---|
| 813 |  * @param length length | 
|---|
| 814 |  */ | 
|---|
| 815 | void NetworkStream::writeToNewDict( byte * data, int length, bool upstream ) | 
|---|
| 816 | { | 
|---|
| 817 |   if ( remainingBytesToWriteToDict <= 0 ) | 
|---|
| 818 |     return; | 
|---|
| 819 |  | 
|---|
| 820 |   if ( length > remainingBytesToWriteToDict ) | 
|---|
| 821 |     length = remainingBytesToWriteToDict; | 
|---|
| 822 |  | 
|---|
| 823 |   std::string fileName = ResourceManager::getInstance()->getDataDir(); | 
|---|
| 824 |   fileName += "/dicts/newdict"; | 
|---|
| 825 |  | 
|---|
| 826 |   if ( upstream ) | 
|---|
| 827 |     fileName += "_upstream"; | 
|---|
| 828 |   else | 
|---|
| 829 |     fileName += "_downstream"; | 
|---|
| 830 |  | 
|---|
| 831 |   FILE * f = fopen( fileName.c_str(), "a" ); | 
|---|
| 832 |  | 
|---|
| 833 |   if ( !f ) | 
|---|
| 834 |   { | 
|---|
| 835 |     PRINTF(2)("could not open %s\n", fileName.c_str()); | 
|---|
| 836 |     remainingBytesToWriteToDict = 0; | 
|---|
| 837 |     return; | 
|---|
| 838 |   } | 
|---|
| 839 |  | 
|---|
| 840 |   if ( fwrite( data, 1, length, f ) != length ) | 
|---|
| 841 |   { | 
|---|
| 842 |     PRINTF(2)("could not write to file\n"); | 
|---|
| 843 |     fclose( f ); | 
|---|
| 844 |     return; | 
|---|
| 845 |   } | 
|---|
| 846 |  | 
|---|
| 847 |   fclose( f ); | 
|---|
| 848 |  | 
|---|
| 849 |   remainingBytesToWriteToDict -= length; | 
|---|
| 850 | } | 
|---|
| 851 |  | 
|---|
| 852 |  | 
|---|
| 853 |  | 
|---|
| 854 |  | 
|---|
| 855 |  | 
|---|
| 856 |  | 
|---|