Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/proxy/src/lib/network/network_stream.cc @ 9436

Last change on this file since 9436 was 9436, checked in by patrick, 18 years ago

the server does not segfault anymore on client disconnect, but the client does

File size: 31.9 KB
Line 
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     June 2006: finishing work on the network stream for pps presentation (rennerc@ee.ethz.ch)
16     July 2006: some code rearangement and integration of the proxy server mechanism (boenzlip@ee.ethz.ch)
17*/
18
19
20#define DEBUG_MODULE_NETWORK
21
22
23#include "base_object.h"
24#include "network_protocol.h"
25#include "udp_socket.h"
26#include "udp_server_socket.h"
27#include "monitor/connection_monitor.h"
28#include "monitor/network_monitor.h"
29#include "synchronizeable.h"
30#include "ip.h"
31#include "network_game_manager.h"
32#include "shared_network_data.h"
33#include "message_manager.h"
34#include "preferences.h"
35#include "zip.h"
36
37#include "src/lib/util/loading/resource_manager.h"
38
39#include "network_log.h"
40
41#include "player_stats.h"
42
43#include "lib/util/loading/factory.h"
44
45#include "debug.h"
46#include "class_list.h"
47#include <algorithm>
48
49
50#include "network_stream.h"
51
52
53#include "converter.h"
54
55
56#define PACKAGE_SIZE  256
57
58
59/**
60 * empty constructor
61 */
62NetworkStream::NetworkStream()
63    : DataStream()
64{
65  this->init();
66  /* initialize the references */
67  this->pInfo->nodeType = NET_CLIENT;
68}
69
70
71NetworkStream::NetworkStream( int nodeType)
72{
73  this->init();
74
75  this->pInfo->nodeType = nodeType;
76
77  switch( nodeType)
78  {
79    case NET_MASTER_SERVER:
80      // init the shared network data
81      SharedNetworkData::getInstance()->setHostID(0);
82      break;
83
84    case NET_PROXY_SERVER_ACTIVE:
85      // init the shared network data
86      SharedNetworkData::getInstance()->setHostID(0);
87      break;
88    case NET_PROXY_SERVER_PASSIVE:
89      // init the shared network data
90      SharedNetworkData::getInstance()->setHostID(0);
91      break;
92    case NET_CLIENT:
93      break;
94  }
95
96  SharedNetworkData::getInstance()->setDefaultSyncStream(this);
97
98  // get the local ip address
99  IPaddress ip;
100  SDLNet_ResolveHost( &ip, NULL, 0);
101  this->pInfo->ip = ip;
102}
103
104
105
106/**
107 * generic init functions
108 */
109void NetworkStream::init()
110{
111  /* set the class id for the base object */
112  this->setClassID(CL_NETWORK_STREAM, "NetworkStream");
113  this->serverSocket = NULL;
114  this->networkGameManager = NULL;
115  this->networkMonitor = NULL;
116
117  this->pInfo = new PeerInfo();
118  this->pInfo->userId = 0;
119  this->pInfo->lastAckedState = 0;
120  this->pInfo->lastRecvedState = 0;
121
122  this->bRedirect = false;
123
124  this->currentState = 0;
125
126  remainingBytesToWriteToDict = Preferences::getInstance()->getInt( "compression", "writedict", 0 );
127
128  assert( Zip::getInstance()->loadDictionary( "testdict" ) >= 0 );
129  this->dictClient = Zip::getInstance()->loadDictionary( "dict2pl_client" );
130  assert( this->dictClient >= 0 );
131  this->dictServer = Zip::getInstance()->loadDictionary( "dict2p_server" );
132  assert( this->dictServer >= 0 );
133}
134
135
136/**
137 * deconstructor
138 */
139NetworkStream::~NetworkStream()
140{
141  if ( this->serverSocket )
142  {
143    serverSocket->close();
144    delete serverSocket;
145    serverSocket = NULL;
146  }
147  for ( PeerList::iterator i = peers.begin(); i!=peers.end(); i++)
148  {
149    if ( i->second.socket )
150    {
151      i->second.socket->disconnectServer();
152      delete i->second.socket;
153      i->second.socket = NULL;
154    }
155
156    if ( i->second.handshake )
157    {
158      delete i->second.handshake;
159      i->second.handshake = NULL;
160    }
161
162    if ( i->second.connectionMonitor )
163    {
164      delete i->second.connectionMonitor;
165      i->second.connectionMonitor = NULL;
166    }
167  }
168  for ( SynchronizeableList::const_iterator it = getSyncBegin(); it != getSyncEnd(); it ++ )
169    (*it)->setNetworkStream( NULL );
170
171  if( this->pInfo)
172    delete this->pInfo;
173
174  if( this->networkMonitor)
175    delete this->networkMonitor;
176}
177
178
179/**
180 * establish a connection to a remote master server
181 * @param host: host name
182 * @param port: the port number
183 */
184void NetworkStream::connectToMasterServer(std::string host, int port)
185{
186  int node = this->peers.size();
187  this->peers[node].socket = new UdpSocket( host, port );
188  this->peers[node].userId = 0;
189
190  this->peers[node].nodeType = NET_MASTER_SERVER;
191  this->peers[node].connectionMonitor = new ConnectionMonitor( 0 );
192  this->peers[node].ip = this->peers[node].socket->getRemoteAddress();
193}
194
195
196/**
197 * establish a connection to a remote proxy server
198 * @param host: host name
199 * @param port: the port number
200 */
201void NetworkStream::connectToProxyServer(std::string host, int port)
202{
203  int node = this->peers.size();
204  PRINTF(0)("connect to proxy %s, this is node %i\n", host.c_str(), node);
205
206  if( this->peers[node].socket != NULL)
207    delete this->peers[node].socket;
208
209  this->peers[node].socket = new UdpSocket( host, port );
210  this->peers[node].userId = 0;
211
212  this->peers[node].nodeType = NET_PROXY_SERVER_ACTIVE;
213  this->peers[node].connectionMonitor = new ConnectionMonitor( 0 );
214  this->peers[node].ip = this->peers[node].socket->getRemoteAddress();
215}
216
217
218/**
219 * create a server
220 * @param port: interface port for all clients
221 */
222void NetworkStream::createServer(int port)
223{
224  this->serverSocket = new UdpServerSocket(port);
225}
226
227
228/**
229 * creates a new instance of the network game manager
230 */
231void NetworkStream::createNetworkGameManager()
232{
233  this->networkGameManager = NetworkGameManager::getInstance();
234
235  this->networkGameManager->setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() );
236  MessageManager::getInstance()->setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() );
237}
238
239
240/**
241 * starts the network handshake
242 * handsakes are always initialized from the client side first. this starts the handshake and therefore is only
243 * executed as client
244 * @param userId: start handshake for this user id (optional, default == 0)
245 */
246void NetworkStream::startHandshake(int userId)
247{
248  Handshake* hs = new Handshake(this->pInfo->nodeType);
249  hs->setUniqueID( 0 );
250  assert( peers[userId].handshake == NULL );
251  peers[userId].handshake = hs;
252
253  // set the preferred nick name
254  hs->setPreferedNickName( Preferences::getInstance()->getString( "multiplayer", "nickname", "Player" ) );
255
256  PRINTF(0)("NetworkStream: Handshake created: %s\n", hs->getCName());
257}
258
259
260/**
261 * this functions connects a synchronizeable to the networkstream, therefore synchronizeing
262 * it all over the network and creating it on the other platforms (if and only if it is a
263 * server
264 * @param sync: the synchronizeable to add
265 */
266void NetworkStream::connectSynchronizeable(Synchronizeable& sync)
267{
268  this->synchronizeables.push_back(&sync);
269  sync.setNetworkStream( this );
270}
271
272
273/**
274 * removes the synchronizeable from the list of synchronized entities
275 * @param sync: the syncronizeable to remove
276 */
277void NetworkStream::disconnectSynchronizeable(Synchronizeable& sync)
278{
279  // removing the Synchronizeable from the List.
280  std::list<Synchronizeable*>::iterator disconnectSynchro = std::find(this->synchronizeables.begin(), this->synchronizeables.end(), &sync);
281  if (disconnectSynchro != this->synchronizeables.end())
282    this->synchronizeables.erase(disconnectSynchro);
283
284  oldSynchronizeables[sync.getUniqueID()] = SDL_GetTicks();
285}
286
287
288/**
289 * this is called to process data from the network socket to the synchronizeable and vice versa
290 */
291void NetworkStream::processData()
292{
293  // create the network monitor after all the init work and before there is any connection handlings
294  if( this->networkMonitor == NULL)
295    this->networkMonitor = new NetworkMonitor(this);
296
297
298  int tick = SDL_GetTicks();
299
300  this->currentState++;
301  // there was a wrap around
302  if( this->currentState < 0)
303  {
304    PRINTF(1)("A wrap around in the state variable as occured. The server was running so long? Pls restart server or write a mail to the supporters!\n");
305  }
306
307  if ( this->pInfo->isMasterServer())
308  {
309    // execute everytthing the master server shoudl do
310    if ( serverSocket )
311      serverSocket->update();
312
313    this->updateConnectionList();
314  }
315  else if( this->pInfo->isProxyServer())
316  {
317    // execute everything the proxy server should do
318    if ( serverSocket )
319      serverSocket->update();
320
321    this->updateConnectionList();
322  }
323  else
324  {
325    // check if the connection is ok else terminate and remove
326    if ( peers[0].socket && ( !peers[0].socket->isOk() || peers[0].connectionMonitor->hasTimedOut() ) )
327    {
328      this->handleDisconnect( 0);
329      PRINTF(1)("lost connection to server\n");
330    }
331    // check if there is a redirection command
332    if( this->bRedirect)
333    {
334      this->handleReconnect( 0);
335    }
336  }
337
338  this->cleanUpOldSyncList();
339  this->handleHandshakes();
340
341  // update the network monitor
342  this->networkMonitor->process();
343
344  // order of up/downstream is important!!!!
345  // don't change it
346  this->handleDownstream( tick );
347  this->handleUpstream( tick );
348}
349
350
351/**
352 * if we are a NET_MASTER_SERVER or NET_PROXY_SERVER_ACTIVE update the connection list to accept new
353 * connections (clients) also start the handsake for the new clients
354 */
355void NetworkStream::updateConnectionList( )
356{
357  //check for new connections
358
359  NetworkSocket* tempNetworkSocket = serverSocket->getNewSocket();
360
361  // we got new network node
362  if ( tempNetworkSocket )
363  {
364    int clientId;
365    // if there is a list of free client id slots, take these
366    if ( freeSocketSlots.size() > 0 )
367    {
368      clientId = freeSocketSlots.back();
369      freeSocketSlots.pop_back();
370    }
371    else
372    {
373      clientId = 1;
374
375      for ( PeerList::iterator it = peers.begin(); it != peers.end(); it++ )
376        if ( it->first >= clientId )
377          clientId = it->first + 1;
378    }
379    peers[clientId].socket = tempNetworkSocket;
380
381
382    // create new handshake and init its variables
383    peers[clientId].handshake = new Handshake(this->pInfo->nodeType, clientId, this->networkGameManager->getUniqueID(), MessageManager::getInstance()->getUniqueID());
384    peers[clientId].handshake->setUniqueID(clientId);
385
386    peers[clientId].connectionMonitor = new ConnectionMonitor( clientId );
387    peers[clientId].userId = clientId;
388
389    PRINTF(0)("num sync: %d\n", synchronizeables.size());
390
391    // get the proxy server informations and write them to the handshake, if any (proxy)
392    assert( this->networkMonitor != NULL);
393    PeerInfo* pi = this->networkMonitor->getFirstChoiceProxy();
394    if( pi != NULL)
395    {
396      peers[clientId].handshake->setProxy1Address( pi->ip);
397    }
398    pi = this->networkMonitor->getSecondChoiceProxy();
399    if( pi != NULL)
400      peers[clientId].handshake->setProxy2Address( pi->ip);
401
402    // check if the connecting client should reconnect to a proxy server
403    peers[clientId].handshake->setRedirect(/*this->networkMonitor->isReconnectNextClient()*/true);
404
405    // the connecting node of course is a client
406    peers[clientId].nodeType = NET_CLIENT;
407    peers[clientId].ip = peers[clientId].socket->getRemoteAddress();
408
409
410    // check if there are too many clients connected (DEPRECATED: new: the masterserver sends a list of proxy servers)
411//     if ( clientId > SharedNetworkData::getInstance()->getMaxPlayer() )
412//     {
413// //       peers[clientId].handshake->setRedirect(true);
414// //
415// //       peers[clientId].handshake->doReject( "too many connections" );
416//       PRINTF(0)("Will reject client %d because there are to many connections!\n", clientId);
417//     }
418//     else
419//     {
420//       PRINTF(0)("New Client: %d\n", clientId);
421//     }
422    PRINTF(0)("New Client: %d\n", clientId);
423
424
425  }
426
427
428
429  //check if connections are ok else remove them
430  for ( PeerList::iterator it = peers.begin(); it != peers.end(); )
431  {
432    if (
433          it->second.socket &&
434          (
435            !it->second.socket->isOk()  ||
436            it->second.connectionMonitor->hasTimedOut()
437          )
438       )
439    {
440      std::string reason = "disconnected";
441      if ( it->second.connectionMonitor->hasTimedOut() )
442        reason = "timeout";
443      PRINTF(0)("Client is gone: %d (%s)\n", it->second.userId, reason.c_str());
444
445      this->handleDisconnect( it->second.userId);
446
447#warning this is some more disconnct handling, consider doing it in the handleDisconnect() funciton
448      // and cleanup the user infos
449//       for ( SynchronizeableList::iterator it2 = synchronizeables.begin(); it2 != synchronizeables.end(); it2++ )
450//       {
451//         (*it2)->cleanUpUser( it->second.userId );
452//       }
453//
454//       NetworkGameManager::getInstance()->signalLeftPlayer(it->second.userId);
455//
456//       freeSocketSlots.push_back( it->second.userId );
457
458//       PeerList::iterator delit = it;
459      it++;
460
461//       peers.erase( delit );
462
463      continue;
464    }
465
466    it++;
467  }
468
469
470}
471
472
473void NetworkStream::debug()
474{
475  if( SharedNetworkData::getInstance()->isMasterServer()) {
476    PRINT(0)(" Host ist Master Server with ID: %i\n", this->pInfo->userId);
477  }
478  else if( SharedNetworkData::getInstance()->isProxyServer()) {
479    PRINT(0)(" Host ist Proxy Server with ID: %i\n", this->pInfo->userId);
480  }
481  else {
482    PRINT(0)(" Host ist Client with ID: %i\n", this->pInfo->userId);
483  }
484
485  PRINT(0)(" Got %i connected Synchronizeables, showing active Syncs:\n", this->synchronizeables.size());
486  for (SynchronizeableList::iterator it = synchronizeables.begin(); it!=synchronizeables.end(); it++)
487  {
488    if( (*it)->beSynchronized() == true)
489      PRINT(0)("  Synchronizeable of class: %s::%s, with unique ID: %i, Synchronize: %i\n", (*it)->getClassCName(), (*it)->getCName(),
490               (*it)->getUniqueID(), (*it)->beSynchronized());
491  }
492  PRINT(0)(" Maximal Connections: %i\n", SharedNetworkData::getInstance()->getMaxPlayer() );
493
494}
495
496
497/**
498 * @returns the number of synchronizeables registered to this stream
499 */
500int NetworkStream::getSyncCount()
501{
502  int n = 0;
503  for (SynchronizeableList::iterator it = synchronizeables.begin(); it!=synchronizeables.end(); it++)
504    if( (*it)->beSynchronized() == true)
505      ++n;
506
507  //return synchronizeables.size();
508  return n;
509}
510
511
512/**
513 * check if handshakes completed. if so create the network game manager else remove it again
514 */
515void NetworkStream::handleHandshakes( )
516{
517  for ( PeerList::iterator it = peers.begin(); it != peers.end(); it++ )
518  {
519    if ( it->second.handshake )
520    {
521      // handshake finished
522      if ( it->second.handshake->completed() )
523      {
524        //handshake is correct
525        if ( it->second.handshake->ok() )
526        {
527          // the counter part didn't mark it free for deletion yet
528          if ( !it->second.handshake->allowDel() )
529          {
530            // make sure this is a client
531            if( this->pInfo->isClient())
532            {
533              SharedNetworkData::getInstance()->setHostID( it->second.handshake->getHostId() );
534              this->pInfo->userId = SharedNetworkData::getInstance()->getHostID();
535
536              it->second.nodeType = it->second.handshake->getRemoteNodeType();
537              it->second.ip = it->second.socket->getRemoteAddress();
538              // add the new server to the nodes list (it can be a NET_MASTER_SERVER or NET_PROXY_SERVER)
539              this->networkMonitor->addNode(&it->second);
540              // get proxy 1 address and add it
541              this->networkMonitor->addNode(it->second.handshake->getProxy1Address(), NET_PROXY_SERVER_ACTIVE);
542              // get proxy 2 address and add it
543              this->networkMonitor->addNode(it->second.handshake->getProxy2Address(), NET_PROXY_SERVER_ACTIVE);
544
545              // now check if the server accepted the connection
546              if( it->second.handshake->redirect() )
547              {
548                this->bRedirect = true;
549              }
550
551              // create the new network game manager and init it
552              this->networkGameManager = NetworkGameManager::getInstance();
553              this->networkGameManager->setUniqueID( it->second.handshake->getNetworkGameManagerId() );
554              // init the new message manager
555              MessageManager::getInstance()->setUniqueID( it->second.handshake->getMessageManagerId() );
556            }
557
558            PRINT(0)("handshake finished id=%d\n", it->second.handshake->getNetworkGameManagerId());
559            it->second.handshake->del();
560
561          }
562          else
563          {
564            // handshake finished registring new player
565            if ( it->second.handshake->canDel() )
566            {
567
568              if ( this->pInfo->isMasterServer() )
569              {
570                it->second.nodeType = it->second.handshake->getRemoteNodeType();
571                it->second.ip = it->second.socket->getRemoteAddress();
572
573                this->networkMonitor->addNode(&it->second);
574
575                this->handleNewClient( it->second.userId );
576
577                if ( PlayerStats::getStats( it->second.userId ) && it->second.handshake->getPreferedNickName() != "" )
578                {
579                  PlayerStats::getStats( it->second.userId )->setNickName( it->second.handshake->getPreferedNickName() );
580                }
581              }
582              else if ( this->pInfo->isProxyServer() )
583              {
584                it->second.nodeType = it->second.handshake->getRemoteNodeType();
585                it->second.ip = it->second.socket->getRemoteAddress();
586
587                this->networkMonitor->addNode(&it->second);
588
589                this->handleNewClient( it->second.userId );
590
591                if ( PlayerStats::getStats( it->second.userId ) && it->second.handshake->getPreferedNickName() != "" )
592                {
593                  PlayerStats::getStats( it->second.userId )->setNickName( it->second.handshake->getPreferedNickName() );
594                }
595              }
596
597              PRINT(0)("handshake finished delete it\n");
598              delete it->second.handshake;
599              it->second.handshake = NULL;
600            }
601          }
602
603        }
604        else
605        {
606          PRINT(1)("handshake failed!\n");
607          it->second.socket->disconnectServer();
608        }
609      }
610    }
611  }
612}
613
614
615/**
616 * this functions handles a reconnect event received from the a NET_MASTER_SERVER or NET_PROXY_SERVER
617 */
618void NetworkStream::handleReconnect(int userId)
619{
620  this->bRedirect = false;
621  PeerInfo* pInfo = &this->peers[userId];
622
623  PRINTF(0)("===============================================\n");
624  PRINTF(0)("Client is redirected to the other proxy servers\n");
625  PRINTF(0)("  user id: %i\n", userId);
626  PRINTF(0)("  connecting to: %s\n", this->networkMonitor->getFirstChoiceProxy()->ip.ipString().c_str());
627  PRINTF(0)("===============================================\n");
628
629  // flush the old synchronization states, since the numbering could be completely different
630  pInfo->lastAckedState = 0;
631  pInfo->lastRecvedState = 0;
632
633  // temp save the ip address here
634  IP proxyIP = pInfo->handshake->getProxy1Address();
635
636  // disconnect from the current server and reconnect to proxy server
637//   pInfo->socket->reconnectToServer( proxyIP.ipString(), proxyIP.port());
638  this->handleDisconnect( userId);
639  this->connectToProxyServer(proxyIP.ipString(), 9999);
640#warning the ports are not yet integrated correctly in the ip class
641
642  // and restart the handshake
643//   this->startHandshake( userId);
644}
645
646
647/**
648 * handles the disconnect event
649 * @param userId id of the user to remove
650 */
651void NetworkStream::handleDisconnect( int userId )
652{
653  peers[userId].socket->disconnectServer();
654  delete peers[userId].socket;
655  peers[userId].socket = NULL;
656
657  if ( peers[userId].handshake )
658    delete peers[userId].handshake;
659  peers[userId].handshake = NULL;
660
661  if ( peers[userId].connectionMonitor )
662    delete peers[userId].connectionMonitor;
663  peers[userId].connectionMonitor = NULL;
664
665
666  for ( SynchronizeableList::iterator it2 = synchronizeables.begin(); it2 != synchronizeables.end(); it2++ )  {
667    (*it2)->cleanUpUser( userId );
668  }
669
670  if( SharedNetworkData::getInstance()->isMasterServer())
671    NetworkGameManager::getInstance()->signalLeftPlayer(userId);
672
673  this->freeSocketSlots.push_back( userId );
674
675  peers.erase( userId );
676
677//   this->pInfo->userId = 0;
678//   this->pInfo->lastAckedState = 0;
679//   this->pInfo->lastRecvedState = 0;
680//   this->pInfo->connectionMonitor = NULL;
681//   this->pInfo->handshake = NULL;
682//   this->pInfo->socket = NULL;
683//   this->pInfo->nodeType = NET_CLIENT;
684}
685
686
687
688/**
689 * handle upstream network traffic
690 * @param tick: seconds elapsed since last update
691 */
692void NetworkStream::handleUpstream( int tick )
693{
694  int offset;
695  int n;
696
697  for ( PeerList::reverse_iterator peer = peers.rbegin(); peer != peers.rend(); peer++ )
698  {
699    offset = INTSIZE; // reserve enough space for the packet length
700
701    // continue with the next peer if this peer has no socket assigned (therefore no network)
702    if ( !peer->second.socket )
703      continue;
704
705    // header informations: current state
706    n = Converter::intToByteArray( currentState, buf + offset, UDP_PACKET_SIZE - offset );
707    assert( n == INTSIZE );
708    offset += n;
709
710    // header informations: last acked state
711    n = Converter::intToByteArray( peer->second.lastAckedState, buf + offset, UDP_PACKET_SIZE - offset );
712    assert( n == INTSIZE );
713    offset += n;
714
715    // header informations: last recved state
716    n = Converter::intToByteArray( peer->second.lastRecvedState, buf + offset, UDP_PACKET_SIZE - offset );
717    assert( n == INTSIZE );
718    offset += n;
719
720    // now write all synchronizeables in the packet
721    for ( SynchronizeableList::iterator it = synchronizeables.begin(); it != synchronizeables.end(); it++ )
722    {
723
724      int oldOffset = offset;
725      Synchronizeable & sync = **it;
726
727
728      // do not include synchronizeables with uninit id and syncs that don't want to be synchronized
729      if ( !sync.beSynchronized() || sync.getUniqueID() < 0 )
730        continue;
731
732      // if handshake not finished only sync handshake
733      if ( peer->second.handshake && sync.getLeafClassID() != CL_HANDSHAKE )
734        continue;
735
736      // if we are a server (both master and proxy servers) and this is not our handshake
737      if ( ( SharedNetworkData::getInstance()->isMasterServer() || SharedNetworkData::getInstance()->isProxyServer() ) && sync.getLeafClassID() == CL_HANDSHAKE && sync.getUniqueID() != peer->second.userId )
738        continue;
739
740      /* list of synchronizeables that will never be synchronized over the network: */
741      // do not sync null parent
742      if ( sync.getLeafClassID() == CL_NULL_PARENT )
743        continue;
744
745
746      assert( sync.getLeafClassID() != 0);
747
748      assert( offset + INTSIZE <= UDP_PACKET_SIZE );
749
750      // server fakes uniqueid == 0 for handshake
751      if ( ( SharedNetworkData::getInstance()->isMasterServer() || SharedNetworkData::getInstance()->isProxyServer() ) &&
752             sync.getUniqueID() <= SharedNetworkData::getInstance()->getMaxPlayer() + 1) // plus one to handle one client more than the max to redirect it
753        n = Converter::intToByteArray( 0, buf + offset, UDP_PACKET_SIZE - offset );
754      else
755        n = Converter::intToByteArray( sync.getUniqueID(), buf + offset, UDP_PACKET_SIZE - offset );
756
757
758      assert( n == INTSIZE );
759      offset += n;
760
761      // make space for packet size
762      offset += INTSIZE;
763
764      n = sync.getStateDiff( peer->second.userId, buf + offset, UDP_PACKET_SIZE-offset, currentState, peer->second.lastAckedState, -1000 );
765      offset += n;
766
767      assert( Converter::intToByteArray( n, buf + offset - n - INTSIZE, INTSIZE ) == INTSIZE );
768
769      // check if all data bytes == 0 -> remove data and the synchronizeable from the sync process since there is no update
770      // TODO not all synchronizeables like this maybe add Synchronizeable::canRemoveZeroDiff()
771      bool allZero = true;
772      for ( int i = 0; i < n; i++ )
773      {
774         if ( buf[i+oldOffset+2*INTSIZE] != 0 )
775           allZero = false;
776      }
777      // if there is no new data in this synchronizeable reset the data offset to the last state -> dont synchronizes
778      // data that hast not changed
779      if ( allZero )
780      {
781        offset = oldOffset;
782      }
783    } // all synchronizeables written
784
785
786
787    for ( SynchronizeableList::iterator it = synchronizeables.begin(); it != synchronizeables.end(); it++ )
788    {
789      Synchronizeable & sync = **it;
790
791      if ( !sync.beSynchronized() || sync.getUniqueID() < 0 )
792        continue;
793
794      sync.handleSentState( peer->second.userId, currentState, peer->second.lastAckedState );
795    }
796
797
798    assert( Converter::intToByteArray( offset, buf, INTSIZE ) == INTSIZE );
799
800    // now compress the data with the zip library
801    int compLength = 0;
802    if ( SharedNetworkData::getInstance()->isMasterServer() || SharedNetworkData::getInstance()->isProxyServer())
803      compLength = Zip::getInstance()->zip( buf, offset, compBuf, UDP_PACKET_SIZE, dictServer );
804    else
805      compLength = Zip::getInstance()->zip( buf, offset, compBuf, UDP_PACKET_SIZE, dictClient );
806
807    if ( compLength <= 0 )
808    {
809      PRINTF(1)("compression failed!\n");
810      continue;
811    }
812
813    assert( peer->second.socket->writePacket( compBuf, compLength ) );
814
815    if ( this->remainingBytesToWriteToDict > 0 )
816      writeToNewDict( buf, offset, true );
817
818    peer->second.connectionMonitor->processUnzippedOutgoingPacket( tick, buf, offset, currentState );
819    peer->second.connectionMonitor->processZippedOutgoingPacket( tick, compBuf, compLength, currentState );
820
821  }
822}
823
824/**
825 * handle downstream network traffic
826 */
827void NetworkStream::handleDownstream( int tick )
828{
829  int offset = 0;
830
831  int length = 0;
832  int packetLength = 0;
833  int compLength = 0;
834  int uniqueId = 0;
835  int state = 0;
836  int ackedState = 0;
837  int fromState = 0;
838  int syncDataLength = 0;
839
840  for ( PeerList::iterator peer = peers.begin(); peer != peers.end(); peer++ )
841  {
842
843    if ( !peer->second.socket )
844      continue;
845
846    while ( 0 < (compLength = peer->second.socket->readPacket( compBuf, UDP_PACKET_SIZE )) )
847    {
848      peer->second.connectionMonitor->processZippedIncomingPacket( tick, compBuf, compLength );
849
850      packetLength = Zip::getInstance()->unZip( compBuf, compLength, buf, UDP_PACKET_SIZE );
851
852      if ( packetLength < 4*INTSIZE )
853      {
854        if ( packetLength != 0 )
855          PRINTF(1)("got too small packet: %d\n", packetLength);
856        continue;
857      }
858
859      if ( this->remainingBytesToWriteToDict > 0 )
860        writeToNewDict( buf, packetLength, false );
861
862      assert( Converter::byteArrayToInt( buf, &length ) == INTSIZE );
863      assert( Converter::byteArrayToInt( buf + INTSIZE, &state ) == INTSIZE );
864      assert( Converter::byteArrayToInt( buf + 2*INTSIZE, &fromState ) == INTSIZE );
865      assert( Converter::byteArrayToInt( buf + 3*INTSIZE, &ackedState ) == INTSIZE );
866      offset = 4*INTSIZE;
867
868      peer->second.connectionMonitor->processUnzippedIncomingPacket( tick, buf, packetLength, state, ackedState );
869
870
871      //if this is an old state drop it
872      if ( state <= peer->second.lastRecvedState )
873        continue;
874
875      if ( packetLength != length )
876      {
877        PRINTF(1)("real packet length (%d) and transmitted packet length (%d) do not match!\n", packetLength, length);
878        peer->second.socket->disconnectServer();
879        continue;
880      }
881
882      while ( offset + 2 * INTSIZE < length )
883      {
884        assert( offset > 0 );
885        assert( Converter::byteArrayToInt( buf + offset, &uniqueId ) == INTSIZE );
886        offset += INTSIZE;
887
888        assert( Converter::byteArrayToInt( buf + offset, &syncDataLength ) == INTSIZE );
889        offset += INTSIZE;
890
891        assert( syncDataLength > 0 );
892        assert( syncDataLength < 10000 );
893
894        Synchronizeable * sync = NULL;
895
896        // look for the synchronizeable in question
897        for ( SynchronizeableList::iterator it = synchronizeables.begin(); it != synchronizeables.end(); it++ )
898        {
899          // client thinks his handshake has id 0!!!!!
900          if ( (*it)->getUniqueID() == uniqueId || ( uniqueId == 0 && (*it)->getUniqueID() == peer->second.userId ) )
901          {
902            sync = *it;
903            break;
904          }
905        }
906
907        // this synchronizeable does not yet exist! create it
908        if ( sync == NULL )
909        {
910          PRINTF(0)("could not find sync with id %d. try to create it\n", uniqueId);
911
912          // if it is an old synchronizeable already removed, ignore it
913          if ( oldSynchronizeables.find( uniqueId ) != oldSynchronizeables.end() )
914          {
915            offset += syncDataLength;
916            continue;
917          }
918
919          // if the node we got this unknown sync from is a client we ignore it (since it has no rights to create a new sync)
920          if ( peers[peer->second.userId].isClient() )
921          {
922            offset += syncDataLength;
923            continue;
924          }
925
926          int leafClassId;
927          if ( INTSIZE > length - offset )
928          {
929            offset += syncDataLength;
930            continue;
931          }
932
933          Converter::byteArrayToInt( buf + offset, &leafClassId );
934
935          assert( leafClassId != 0 );
936
937
938          BaseObject * b = NULL;
939          /* These are some small exeptions in creation: Not all objects can/should be created via Factory */
940          /* Exception 1: NullParent */
941          if( leafClassId == CL_NULL_PARENT || leafClassId == CL_SYNCHRONIZEABLE || leafClassId == CL_NETWORK_GAME_MANAGER )
942          {
943            PRINTF(1)("Don't create Object with ID %x, ignored!\n", (int)leafClassId);
944            offset += syncDataLength;
945            continue;
946          }
947          else
948            b = Factory::fabricate( (ClassID)leafClassId );
949
950          if ( !b )
951          {
952            PRINTF(1)("Could not fabricate Object with classID %x\n", leafClassId);
953            offset += syncDataLength;
954            continue;
955          }
956
957          if ( b->isA(CL_SYNCHRONIZEABLE) )
958          {
959            sync = dynamic_cast<Synchronizeable*>(b);
960            sync->setUniqueID( uniqueId );
961            sync->setSynchronized(true);
962
963            PRINTF(0)("Fabricated %s with id %d\n", sync->getClassCName(), sync->getUniqueID());
964          }
965          else
966          {
967            PRINTF(1)("Class with ID %x is not a synchronizeable!\n", (int)leafClassId);
968            delete b;
969            offset += syncDataLength;
970            continue;
971          }
972        }
973
974
975        int n = sync->setStateDiff( peer->second.userId, buf+offset, syncDataLength, state, fromState );
976        offset += n;
977
978      }
979
980      if ( offset != length )
981      {
982        PRINTF(0)("offset (%d) != length (%d)\n", offset, length);
983        peer->second.socket->disconnectServer();
984      }
985
986
987      for ( SynchronizeableList::iterator it = synchronizeables.begin(); it != synchronizeables.end(); it++ )
988      {
989        Synchronizeable & sync = **it;
990
991        if ( !sync.beSynchronized() || sync.getUniqueID() < 0 )
992          continue;
993
994        sync.handleRecvState( peer->second.userId, state, fromState );
995      }
996
997      assert( peer->second.lastAckedState <= ackedState );
998      peer->second.lastAckedState = ackedState;
999
1000      assert( peer->second.lastRecvedState < state );
1001      peer->second.lastRecvedState = state;
1002
1003    }
1004
1005  }
1006
1007}
1008
1009/**
1010 * is executed when a handshake has finished
1011 */
1012void NetworkStream::handleNewClient( int userId )
1013{
1014  // init and assign the message manager
1015  MessageManager::getInstance()->initUser( userId );
1016  // do all game relevant stuff here
1017  networkGameManager->signalNewPlayer( userId );
1018}
1019
1020
1021/**
1022 * removes old items from oldSynchronizeables
1023 */
1024void NetworkStream::cleanUpOldSyncList( )
1025{
1026  int now = SDL_GetTicks();
1027
1028  for ( std::map<int,int>::iterator it = oldSynchronizeables.begin(); it != oldSynchronizeables.end();  )
1029  {
1030    if ( it->second < now - 10*1000 )
1031    {
1032      std::map<int,int>::iterator delIt = it;
1033      it++;
1034      oldSynchronizeables.erase( delIt );
1035      continue;
1036    }
1037    it++;
1038  }
1039}
1040
1041/**
1042 * writes data to DATA/dicts/newdict
1043 * @param data pointer to data
1044 * @param length length
1045 */
1046void NetworkStream::writeToNewDict( byte * data, int length, bool upstream )
1047{
1048  if ( remainingBytesToWriteToDict <= 0 )
1049    return;
1050
1051  if ( length > remainingBytesToWriteToDict )
1052    length = remainingBytesToWriteToDict;
1053
1054  std::string fileName = ResourceManager::getInstance()->getDataDir();
1055  fileName += "/dicts/newdict";
1056
1057  if ( upstream )
1058    fileName += "_upstream";
1059  else
1060    fileName += "_downstream";
1061
1062  FILE * f = fopen( fileName.c_str(), "a" );
1063
1064  if ( !f )
1065  {
1066    PRINTF(2)("could not open %s\n", fileName.c_str());
1067    remainingBytesToWriteToDict = 0;
1068    return;
1069  }
1070
1071  if ( fwrite( data, 1, length, f ) != length )
1072  {
1073    PRINTF(2)("could not write to file\n");
1074    fclose( f );
1075    return;
1076  }
1077
1078  fclose( f );
1079
1080  remainingBytesToWriteToDict -= length;
1081}
1082
1083
1084
1085
1086
1087
Note: See TracBrowser for help on using the repository browser.