Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

handshake server problems by reconnection

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