Index: trunk/src/lib/network/network_stream.cc
===================================================================
--- trunk/src/lib/network/network_stream.cc	(revision 9494)
+++ trunk/src/lib/network/network_stream.cc	(revision 9656)
@@ -11,8 +11,8 @@
 ### File Specific:
    main-programmer: Christoph Renner rennerc@ee.ethz.ch
-   co-programmer:   Patrick Boenzli  boenzlip@orxonox.ethz.ch
+   co-programmer:   Patrick Boenzli  patrick@orxonox.ethz.ch
 
      June 2006: finishing work on the network stream for pps presentation (rennerc@ee.ethz.ch)
-     July 2006: some code rearangement and integration of the proxy server mechanism (boenzlip@ee.ethz.ch)
+     July 2006: some code rearangement and integration of the proxy server mechanism (patrick@orxonox.ethz.ch)
 */
 
@@ -20,4 +20,5 @@
 #define DEBUG_MODULE_NETWORK
 
+#include "proxy/proxy_control.h"
 
 #include "base_object.h"
@@ -80,15 +81,23 @@
       // init the shared network data
       SharedNetworkData::getInstance()->setHostID(NET_ID_MASTER_SERVER);
+      this->pInfo->userId = NET_ID_MASTER_SERVER;
+      this->pInfo->nodeType = NET_MASTER_SERVER;
+
       break;
     case NET_PROXY_SERVER_ACTIVE:
       // init the shared network data
       SharedNetworkData::getInstance()->setHostID(NET_ID_PROXY_SERVER_01);
+      this->pInfo->nodeType = NET_PROXY_SERVER_ACTIVE;
+
       break;
     case NET_PROXY_SERVER_PASSIVE:
       // init the shared network data
       SharedNetworkData::getInstance()->setHostID(NET_ID_PROXY_SERVER_01);
+      this->pInfo->nodeType = NET_PROXY_SERVER_PASSIVE;
+
       break;
     case NET_CLIENT:
       SharedNetworkData::getInstance()->setHostID(NET_ID_UNASSIGNED);
+      this->pInfo->nodeType = NET_CLIENT;
       break;
   }
@@ -97,6 +106,5 @@
 
   // get the local ip address
-  IPaddress ip;
-  SDLNet_ResolveHost( &ip, NULL, 0);
+  IP ip("localhost", 0);
   this->pInfo->ip = ip;
 }
@@ -112,4 +120,5 @@
   this->setClassID(CL_NETWORK_STREAM, "NetworkStream");
   this->clientSocket = NULL;
+  this->clientSoftSocket = NULL;
   this->proxySocket = NULL;
   this->networkGameManager = NULL;
@@ -117,11 +126,13 @@
 
   this->pInfo = new PeerInfo();
-  this->pInfo->userId = 0;
+  this->pInfo->userId = NET_UID_UNASSIGNED;
   this->pInfo->lastAckedState = 0;
   this->pInfo->lastRecvedState = 0;
+  this->pInfo->bLocal = true;
 
   this->bRedirect = false;
 
   this->currentState = 0;
+  this->redirectionUID = NET_ID_MASTER_SERVER;
 
   remainingBytesToWriteToDict = Preferences::getInstance()->getInt( "compression", "writedict", 0 );
@@ -142,7 +153,13 @@
   if ( this->clientSocket )
   {
-    clientSocket->close();
-    delete clientSocket;
-    clientSocket = NULL;
+    this->clientSocket->close();
+    delete this->clientSocket;
+    this->clientSocket = NULL;
+  }
+  if ( this->clientSoftSocket )
+  {
+    this->clientSoftSocket->close();
+    delete this->clientSoftSocket;
+    this->clientSoftSocket = NULL;
   }
   if ( this->proxySocket)
@@ -199,4 +216,5 @@
   this->peers[node].connectionMonitor = new ConnectionMonitor( NET_ID_MASTER_SERVER );
   this->peers[node].ip = this->peers[node].socket->getRemoteAddress();
+  this->peers[node].bLocal = true;
 }
 
@@ -218,4 +236,5 @@
   this->peers[proxyId].connectionMonitor = new ConnectionMonitor( proxyId );
   this->peers[proxyId].ip = this->peers[proxyId].socket->getRemoteAddress();
+  this->peers[proxyId].bLocal = true;
 }
 
@@ -225,8 +244,9 @@
  * @param port: interface port for all clients
  */
-void NetworkStream::createServer(int clientPort, int proxyPort)
+void NetworkStream::createServer(int clientPort, int proxyPort, int clientSoftPort)
 {
   PRINTF(0)(" Creating new Server: listening for clients on port %i and for proxies on port %i", clientPort, proxyPort);
   this->clientSocket= new UdpServerSocket(clientPort);
+  this->clientSoftSocket= new UdpServerSocket(clientSoftPort);
   this->proxySocket = new UdpServerSocket(proxyPort);
 }
@@ -255,7 +275,8 @@
   Handshake* hs = new Handshake(this->pInfo->nodeType);
   // fake the unique id
-  hs->setUniqueID( NET_UID_HANDSHAKE );
-  assert( peers[userId].handshake == NULL );
-  peers[userId].handshake = hs;
+  hs->setUniqueID( userId);
+  assert( this->peers[userId].handshake == NULL );
+  this->peers[userId].handshake = hs;
+  this->peers[userId].bLocal = true;
 
   // set the preferred nick name
@@ -301,5 +322,8 @@
   // create the network monitor after all the init work and before there is any connection handlings
   if( this->networkMonitor == NULL)
+  {
     this->networkMonitor = new NetworkMonitor(this);
+    SharedNetworkData::getInstance()->setNetworkMonitor( this->networkMonitor);
+  }
 
 
@@ -318,4 +342,6 @@
     if ( this->clientSocket )
       this->clientSocket->update();
+    if ( this->clientSoftSocket)
+      this->clientSoftSocket->update();
     if( this->proxySocket)
       this->proxySocket->update();
@@ -328,4 +354,6 @@
     if ( this->clientSocket )
       this->clientSocket->update();
+    if ( this->clientSoftSocket)
+      this->clientSoftSocket->update();
     if( this->proxySocket)
       this->proxySocket->update();
@@ -348,5 +376,5 @@
     if( this->bRedirect)
     {
-      this->handleReconnect( NET_ID_MASTER_SERVER);
+      this->handleReconnect( this->redirectionUID);
     }
   }
@@ -362,4 +390,10 @@
   this->handleDownstream( tick );
   this->handleUpstream( tick );
+
+  // process the local data of the message manager
+  MessageManager::getInstance()->processData();
+
+  if( this->bSoftRedirect)
+    this->softReconnectToServer(0, IP("localhost", 10001));
 }
 
@@ -385,17 +419,23 @@
     if ( tempNetworkSocket )
     {
-      // determine the network node id
-      if ( freeSocketSlots.size() > 0 )
+      // get a userId
+//       if ( freeSocketSlots.size() > 0 )
+//       {
+//         // this should never be called
+//         userId = freeSocketSlots.back();
+//         freeSocketSlots.pop_back();
+//       }
+//       else
       {
-        userId = freeSocketSlots.back();
-        freeSocketSlots.pop_back();
-      }
-      else
-      {
-        userId = 1;
+        // each server (proxy and master) have an address space for new network nodes of 1000 nodes
+        // the first NET_ID_PROXY_MAX are always reserved for proxy servers
+        userId = SharedNetworkData::getInstance()->getHostID() * 1000 + NET_ID_PROXY_MAX + 1;
 
         for ( PeerList::iterator it = peers.begin(); it != peers.end(); it++ )
           if ( it->first >= userId )
             userId = it->first + 1;
+
+        // make sure that this server only uses an address space of 1000
+        assert( userId < (SharedNetworkData::getInstance()->getHostID() + 1) * 1000);
       }
       // this creates a new entry in the peers list
@@ -410,4 +450,23 @@
   }
 
+  if( this->clientSoftSocket != NULL)
+  {
+    tempNetworkSocket = this->clientSoftSocket->getNewSocket();
+
+    // we got new NET_CLIENT connecting
+    if ( tempNetworkSocket )
+    {
+
+      // this creates a new entry in the peers list
+      peers[userId].socket = tempNetworkSocket;
+      peers[userId].nodeType = NET_CLIENT;
+
+      // handle the newly connected client
+      this->handleSoftConnect(userId);
+
+      PRINTF(0)("New Client softly connected: %d :D\n", userId);
+    }
+  }
+
 
   if( this->proxySocket != NULL)
@@ -419,16 +478,26 @@
     {
       // determine the network node id
-      if ( freeSocketSlots.size() > 0 )
-      {
-        userId = freeSocketSlots.back();
-        freeSocketSlots.pop_back();
-      }
-      else
+//       if ( freeSocketSlots.size() > 0 )
+//       {
+//         userId = freeSocketSlots.back();
+//         freeSocketSlots.pop_back();
+//       }
+//       else
       {
         userId = 1;
 
-        for ( PeerList::iterator it = peers.begin(); it != peers.end(); it++ )
-          if ( it->first >= userId )
-            userId = it->first + 1;
+        // find an empty slot within the range
+        for( int i = 0; i < NET_ID_PROXY_MAX; i++)
+        {
+          if( this->peers.find( i) == this->peers.end())
+          {
+            userId = i;
+            break;
+          }
+        }
+
+//         for ( PeerList::iterator it = peers.begin(); it != peers.end(); it++ )
+//           if ( it->first >= userId )
+//             userId = it->first + 1;
       }
 
@@ -443,4 +512,5 @@
     }
   }
+
 
 
@@ -461,5 +531,9 @@
       PRINTF(0)("Client is gone: %d (%s)\n", it->second.userId, reason.c_str());
 
+
       this->handleDisconnect( it->second.userId);
+
+      if( SharedNetworkData::getInstance()->isProxyServerActive())
+        ProxyControl::getInstance()->signalLeaveClient(it->second.userId);
 
       it++;
@@ -469,6 +543,4 @@
     it++;
   }
-
-
 }
 
@@ -481,9 +553,10 @@
 {
   // create new handshake and init its variables
-  peers[userId].handshake = new Handshake(this->pInfo->nodeType, userId, this->networkGameManager->getUniqueID(), MessageManager::getInstance()->getUniqueID());
-  peers[userId].handshake->setUniqueID(userId);
-
-  peers[userId].connectionMonitor = new ConnectionMonitor( userId );
-  peers[userId].userId = userId;
+  this->peers[userId].handshake = new Handshake(this->pInfo->nodeType, userId, this->networkGameManager->getUniqueID(), MessageManager::getInstance()->getUniqueID());
+  this->peers[userId].handshake->setUniqueID(userId);
+
+  this->peers[userId].connectionMonitor = new ConnectionMonitor( userId );
+  this->peers[userId].userId = userId;
+  this->peers[userId].bLocal = true;
 
   PRINTF(0)("num sync: %d\n", synchronizeables.size());
@@ -494,17 +567,49 @@
   if( pi != NULL)
   {
-    peers[userId].handshake->setProxy1Address( pi->ip);
+    this->peers[userId].handshake->setProxy1Address( pi->ip);
   }
   pi = this->networkMonitor->getSecondChoiceProxy();
   if( pi != NULL)
-    peers[userId].handshake->setProxy2Address( pi->ip);
+    this->peers[userId].handshake->setProxy2Address( pi->ip);
 
   // check if the connecting client should reconnect to a proxy server
   if( SharedNetworkData::getInstance()->isMasterServer())
-    peers[userId].handshake->setRedirect(/*this->networkMonitor->isReconnectNextClient()*/false);
+  {
+    if( this->networkMonitor->isReconnectNextClient())
+    {
+      this->peers[userId].handshake->setRedirect(true);
+      PRINTF(0)("forwarding client to proxy server because this server is saturated\n");
+    }
+  }
 
   // the connecting node of course is a client
-  peers[userId].ip = peers[userId].socket->getRemoteAddress();
-}
+  this->peers[userId].ip = this->peers[userId].socket->getRemoteAddress();
+}
+
+
+/**
+ * this handles new soft connections
+ * @param userId: the id of the new user node
+ *
+ * soft connections are connections from clients that are already in the network and don't need a new handshake etc.
+ * the state of all entitites owned by userId are not deleted and stay
+ * soft connections can not be redirected therefore they are negotiated between the to parties
+ */
+void NetworkStream::handleSoftConnect( int userId)
+{
+  // create new handshake and init its variables
+  this->peers[userId].handshake = NULL;
+  this->peers[userId].handshake->setUniqueID(userId);
+
+  this->peers[userId].connectionMonitor = new ConnectionMonitor( userId );
+  this->peers[userId].userId = userId;
+  this->peers[userId].bLocal = true;
+
+  PRINTF(0)("num sync: %d\n", synchronizeables.size());
+
+  // the connecting node of course is a client
+  this->peers[userId].ip = this->peers[userId].socket->getRemoteAddress();
+}
+
 
 
@@ -524,4 +629,12 @@
     PRINT(0)(" Host ist Client with ID: %i\n", this->pInfo->userId);
   }
+
+  PRINT(0)(" Current number of connections is: %i\n", this->peers.size());
+  for ( PeerList::iterator it = peers.begin(); it != peers.end(); it++ )
+  {
+    PRINT(0)("  peers[%i] with uniqueId %i and address: %s\n", it->first, it->second.userId, it->second.ip.ipString().c_str());
+  }
+  PRINT(0)("\n\n");
+
 
   PRINT(0)(" Got %i connected Synchronizeables, showing active Syncs:\n", this->synchronizeables.size());
@@ -576,15 +689,16 @@
             // - client       <==> master server
             // - proxy server <==> master server
-            if(  SharedNetworkData::getInstance()->isClient() || SharedNetworkData::getInstance()->isProxyServerActive() && it->second.isMasterServer())
+            if(  SharedNetworkData::getInstance()->isClient() ||
+                 SharedNetworkData::getInstance()->isProxyServerActive() &&
+                 SharedNetworkData::getInstance()->isUserMasterServer(it->second.userId))
             {
-              PRINTF(0)("Handshake: i am in client role\n");
+              PRINTF(4)("Handshake: i am in client role\n");
 
               SharedNetworkData::getInstance()->setHostID( it->second.handshake->getHostId() );
               this->pInfo->userId = SharedNetworkData::getInstance()->getHostID();
 
-#warning the ip address is not set here because it results in a segfault when connecting to a proxy server => trace this later
 //               it->second.ip = it->second.socket->getRemoteAddress();
 
-              // it->second.nodeType = it->second.handshake->getRemoteNodeType();
+              it->second.nodeType = it->second.handshake->getRemoteNodeType();
               // it->second.ip = it->second.socket->getRemoteAddress();
               // add the new server to the nodes list (it can be a NET_MASTER_SERVER or NET_PROXY_SERVER)
@@ -633,5 +747,5 @@
               else if ( SharedNetworkData::getInstance()->isProxyServerActive() && it->second.isClient() )
               {
-                PRINTF(0)("Handshake: i am in server role\n");
+                PRINTF(4)("Handshake: Proxy in server role: connecting %i\n", it->second.userId);
 
                 it->second.ip = it->second.socket->getRemoteAddress();
@@ -639,5 +753,6 @@
                 this->networkMonitor->addNode(&it->second);
 
-                this->handleNewClient( it->second.userId );
+                // work with the ProxyControl to init the new client
+                ProxyControl::getInstance()->signalNewClient( it->second.userId);
 
                 if ( PlayerStats::getStats( it->second.userId ) && it->second.handshake->getPreferedNickName() != "" )
@@ -667,14 +782,22 @@
 /**
  * this functions handles a reconnect event received from the a NET_MASTER_SERVER or NET_PROXY_SERVER
+ * @param userId
  */
 void NetworkStream::handleReconnect(int userId)
 {
   this->bRedirect = false;
+#warning this peer will be created if it does not yet exist: dangerous
   PeerInfo* pInfo = &this->peers[userId];
+
+  IP proxyIP;
+  if( this->networkMonitor->isForcedReconnection())
+    proxyIP = this->networkMonitor->getForcedReconnectionIP();
+  else
+    proxyIP = pInfo->handshake->getProxy1Address();
 
   PRINTF(0)("===============================================\n");
   PRINTF(0)("Client is redirected to the other proxy servers\n");
   PRINTF(0)("  user id: %i\n", userId);
-  PRINTF(0)("  connecting to: %s\n", this->networkMonitor->getFirstChoiceProxy()->ip.ipString().c_str());
+  PRINTF(0)("  connecting to: %s\n", proxyIP.ipString().c_str());
   PRINTF(0)("===============================================\n");
 
@@ -683,10 +806,8 @@
   pInfo->lastRecvedState = 0;
 
-  // temp save the ip address here
-  IP proxyIP = pInfo->handshake->getProxy1Address();
-
   // disconnect from the current server and reconnect to proxy server
   this->handleDisconnect( userId);
   this->connectToProxyServer(NET_ID_PROXY_SERVER_01, proxyIP.ipString(), 9999);
+//   this->connectToMasterServer(proxyIP.ipString(), 9999);
   #warning the ports are not yet integrated correctly in the ip class
 
@@ -696,4 +817,79 @@
 
 
+
+/**
+ * reconnects to another server, with full handshake
+ * @param address of the new server
+ */
+void NetworkStream::reconnectToServer(IP address)
+{
+  ///TODO make a redirection struct and push it to the network monitor
+  this->networkMonitor->setForcedReconnection(address);
+
+  // reconnect (depending on how we are connected at the moment)
+  if ( peers.find( NET_ID_MASTER_SERVER) != peers.end() )
+    this->redirectionUID = NET_ID_MASTER_SERVER;
+  else if( peers.find( NET_ID_PROXY_SERVER_01) != peers.end() )
+    this->redirectionUID = NET_ID_PROXY_SERVER_01;
+
+  this->bRedirect = true;
+}
+
+
+
+/**
+ * softly reconnecting to another server
+ * @param serverUserId the id of the client
+ * @param address  of the new server
+ */
+void NetworkStream::softReconnectToServer(int serverUserId, IP address)
+{
+//   this->networkMonitor->setForcedReconnection(address);
+//   this->handleReconnect( NET_ID_MASTER_SERVER);
+
+  // create the new udp socket and open the connection to the soft connection port
+  NetworkSocket* newSocket = new UdpSocket(address.ipString(), 10001);
+
+  // delete the synchronization state of this client for all syncs
+  for ( SynchronizeableList::iterator it2 = synchronizeables.begin(); it2 != synchronizeables.end(); it2++ )  {
+    (*it2)->cleanUpUser( serverUserId );
+  }
+
+  // temp save the old socket
+  NetworkSocket* oldSocket = this->peers[serverUserId].socket;
+
+  // now integrate the new socket
+  this->peers[serverUserId].socket = newSocket;
+
+  this->bSoftRedirect = false;
+  return;
+
+  // now remove the old socket
+  oldSocket->disconnectServer();
+  delete oldSocket;
+
+  // replace the old connection monitor
+  if ( this->peers[serverUserId].connectionMonitor )
+    delete this->peers[serverUserId].connectionMonitor;
+  this->peers[serverUserId].connectionMonitor = new ConnectionMonitor(serverUserId);
+
+  // remove old node from the network monitor
+  this->networkMonitor->removeNode(&this->peers[serverUserId]);
+
+}
+
+
+
+/**
+ * prepares a soft connection for a client to connect to
+ * @param userId that will connect to this server
+ */
+void NetworkStream::prepareSoftConnection(int userId)
+{
+  PRINTF(0)("prepare soft connection for userId %i\n");
+}
+
+
+
 /**
  * handles the disconnect event
@@ -702,17 +898,17 @@
 void NetworkStream::handleDisconnect( int userId )
 {
-  peers[userId].socket->disconnectServer();
-  delete peers[userId].socket;
-  peers[userId].socket = NULL;
-
-  if ( peers[userId].handshake )
-    delete peers[userId].handshake;
-  peers[userId].handshake = NULL;
-
-  if ( peers[userId].connectionMonitor )
-    delete peers[userId].connectionMonitor;
-  peers[userId].connectionMonitor = NULL;
-
-
+  this->peers[userId].socket->disconnectServer();
+  delete this->peers[userId].socket;
+  this->peers[userId].socket = NULL;
+
+  if ( this->peers[userId].handshake )
+    delete this->peers[userId].handshake;
+  this->peers[userId].handshake = NULL;
+
+  if ( this->peers[userId].connectionMonitor )
+    delete this->peers[userId].connectionMonitor;
+  this->peers[userId].connectionMonitor = NULL;
+
+  // delete the synchronization state of this client for all syncs
   for ( SynchronizeableList::iterator it2 = synchronizeables.begin(); it2 != synchronizeables.end(); it2++ )  {
     (*it2)->cleanUpUser( userId );
@@ -724,7 +920,7 @@
   this->freeSocketSlots.push_back( userId );
 
-  peers.erase( userId);
-}
-
+  this->networkMonitor->removeNode(&this->peers[userId]);
+  this->peers.erase( userId);
+}
 
 
@@ -793,8 +989,8 @@
       assert( offset + INTSIZE <= UDP_PACKET_SIZE );
 
-      // server fakes uniqueid == 0 for handshake
+      // server fakes uniqueid == 0 for handshake synchronizeable
       if ( ( SharedNetworkData::getInstance()->isMasterServer() ||
              SharedNetworkData::getInstance()->isProxyServerActive() &&  peer->second.isClient() ) &&
-             sync.getUniqueID() <= SharedNetworkData::getInstance()->getMaxPlayer() + 1) // plus one to handle one client more than the max to redirect it
+             ( sync.getUniqueID() >= 1000 || sync.getUniqueID() <= SharedNetworkData::getInstance()->getMaxPlayer() + 1 + NET_ID_PROXY_MAX))
         n = Converter::intToByteArray( 0, buf + offset, UDP_PACKET_SIZE - offset );
       else
@@ -930,8 +1126,10 @@
       while ( offset + 2 * INTSIZE < length )
       {
+        // read the unique id of the sync
         assert( offset > 0 );
         assert( Converter::byteArrayToInt( buf + offset, &uniqueId ) == INTSIZE );
         offset += INTSIZE;
 
+        // read the data length
         assert( Converter::byteArrayToInt( buf + offset, &syncDataLength ) == INTSIZE );
         offset += INTSIZE;
@@ -945,6 +1143,7 @@
         for ( SynchronizeableList::iterator it = synchronizeables.begin(); it != synchronizeables.end(); it++ )
         {
-          // client thinks his handshake has id 0!!!!!
-          if ( (*it)->getUniqueID() == uniqueId || ( uniqueId == 0 && (*it)->getUniqueID() == peer->second.userId ) )
+          // client thinks his handshake has a special id: hostId * 1000 (host id of this server)
+          if ( (*it)->getUniqueID() == uniqueId ||                                          // so this client exists already go to sync work
+                 ( uniqueId == 0  && (*it)->getUniqueID() == peer->second.userId ) )        // so this is a Handshake!
           {
             sync = *it;
