]> git.mxchange.org Git - flightgear.git/blobdiff - src/MultiPlayer/multiplaymgr.cxx
Fixed an property tieing issue on sim reset.
[flightgear.git] / src / MultiPlayer / multiplaymgr.cxx
index 317d2df41da8e98be0b1ee8a096871fb78cf7453..9a541382786f10de1cabd9433d103e07ba0e5de4 100644 (file)
@@ -1,6 +1,6 @@
 //////////////////////////////////////////////////////////////////////
 //
-// multiplaymgr.hpp
+// multiplaymgr.cxx
 //
 // Written by Duncan McCreanor, started February 2003.
 // duncan.mccreanor@airservicesaustralia.com
@@ -35,7 +35,6 @@
 #include <algorithm>
 #include <cstring>
 #include <osg/Math>             // isNaN
-#include <plib/netSocket.h>
 
 #include <simgear/misc/stdint.hxx>
 #include <simgear/timing/timestamp.hxx>
@@ -411,7 +410,7 @@ FGMultiplayMgr::init (void)
   SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-callsign= "<<mCallsign);
   Close(); // Should Init be called twice, close Socket first
            // A memory leak was reported here by valgrind
-  mSocket = new netSocket();
+  mSocket = new simgear::Socket();
   if (!mSocket->open(false)) {
     SG_LOG( SG_NETWORK, SG_DEBUG,
             "FGMultiplayMgr::init - Failed to create data socket" );
@@ -527,137 +526,184 @@ union FGMultiplayMgr::MsgBuf
     T_MsgHdr Header;
 };
 
+bool
+FGMultiplayMgr::isSane(const FGExternalMotionData& motionInfo)
+{
+    // check for corrupted data (NaNs)
+    bool isCorrupted = false;
+    isCorrupted |= ((osg::isNaN(motionInfo.time           )) ||
+                    (osg::isNaN(motionInfo.lag            )) ||
+                    (osg::isNaN(motionInfo.orientation(3) )));
+    for (unsigned i = 0; (i < 3)&&(!isCorrupted); ++i)
+    {
+        isCorrupted |= ((osg::isNaN(motionInfo.position(i)      ))||
+                        (osg::isNaN(motionInfo.orientation(i)   ))||
+                        (osg::isNaN(motionInfo.linearVel(i))    )||
+                        (osg::isNaN(motionInfo.angularVel(i))   )||
+                        (osg::isNaN(motionInfo.linearAccel(i))  )||
+                        (osg::isNaN(motionInfo.angularAccel(i)) ));
+    }
+    return !isCorrupted;
+}
+
 void
 FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
 {
   if ((! mInitialised) || (! mHaveServer))
         return;
+
   if (! mHaveServer) {
-    SG_LOG( SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::SendMyPosition - no server");
-    return;
+      SG_LOG( SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::SendMyPosition - no server");
+      return;
   }
 
-  MsgBuf msgBuf;
+  if (!isSane(motionInfo))
+  {
+      // Current local data is invalid (NaN), so stop MP transmission.
+      // => Be nice to older FG versions (no NaN checks) and don't waste bandwidth.
+      SG_LOG(SG_NETWORK, SG_ALERT, "FGMultiplayMgr::SendMyPosition - "
+              << "Local data is invalid (NaN). Data not transmitted.");
+      return;
+  }
+
+  static MsgBuf msgBuf;
+  static unsigned msgLen = 0;
   T_PositionMsg* PosMsg = msgBuf.posMsg();
 
   strncpy(PosMsg->Model, fgGetString("/sim/model/path"), MAX_MODEL_NAME_LEN);
   PosMsg->Model[MAX_MODEL_NAME_LEN - 1] = '\0';
-  
-  PosMsg->time = XDR_encode_double (motionInfo.time);
-  PosMsg->lag = XDR_encode_double (motionInfo.lag);
-  for (unsigned i = 0 ; i < 3; ++i)
-    PosMsg->position[i] = XDR_encode_double (motionInfo.position(i));
-  SGVec3f angleAxis;
-  motionInfo.orientation.getAngleAxis(angleAxis);
-  for (unsigned i = 0 ; i < 3; ++i)
-    PosMsg->orientation[i] = XDR_encode_float (angleAxis(i));
-  for (unsigned i = 0 ; i < 3; ++i)
-    PosMsg->linearVel[i] = XDR_encode_float (motionInfo.linearVel(i));
-  for (unsigned i = 0 ; i < 3; ++i)
-    PosMsg->angularVel[i] = XDR_encode_float (motionInfo.angularVel(i));
-  for (unsigned i = 0 ; i < 3; ++i)
-    PosMsg->linearAccel[i] = XDR_encode_float (motionInfo.linearAccel(i));
-  for (unsigned i = 0 ; i < 3; ++i)
-    PosMsg->angularAccel[i] = XDR_encode_float (motionInfo.angularAccel(i));
-  
-  xdr_data_t* ptr = msgBuf.properties();
-  std::vector<FGPropertyData*>::const_iterator it;
-  it = motionInfo.properties.begin();
-  //cout << "OUTPUT PROPERTIES\n";
-  xdr_data_t* msgEnd = msgBuf.propsEnd();
-  while (it != motionInfo.properties.end() && ptr + 2 < msgEnd) {
-    
-    // First element is the ID. Write it out when we know we have room for
-    // the whole property.
-    xdr_data_t id =  XDR_encode_uint32((*it)->id);
-    // The actual data representation depends on the type
-    switch ((*it)->type) {
-      case simgear::props::INT:
-      case simgear::props::BOOL:
-      case simgear::props::LONG:
-        *ptr++ = id;
-        *ptr++ = XDR_encode_uint32((*it)->int_value);
-        //cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->int_value << "\n";
-        break;
-      case simgear::props::FLOAT:
-      case simgear::props::DOUBLE:
-        *ptr++ = id;
-        *ptr++ = XDR_encode_float((*it)->float_value);
-        //cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->float_value << "\n";
-        break;
-      case simgear::props::STRING:
-      case simgear::props::UNSPECIFIED:
-        {
-          // String is complicated. It consists of
-          // The length of the string
-          // The string itself
-          // Padding to the nearest 4-bytes.        
-          const char* lcharptr = (*it)->string_value;
-          
-          if (lcharptr != 0)
-          {
-            // Add the length         
-            ////cout << "String length: " << strlen(lcharptr) << "\n";
-            uint32_t len = strlen(lcharptr);
-            if (len > MAX_TEXT_SIZE)
-              len = MAX_TEXT_SIZE;
-            // XXX This should not be using 4 bytes per character!
-            // If there's not enough room for this property, drop it
-            // on the floor.
-            if (ptr + 2 + ((len + 3) & ~3) > msgEnd)
-                goto escape;
-            //cout << "String length unint32: " << len << "\n";
+  if (fgGetBool("/sim/freeze/replay-state", true))
+  {
+      // do not send position updates during replay
+      for (unsigned i = 0 ; i < 3; ++i)
+      {
+          // no movement during replay
+          PosMsg->linearVel[i] = XDR_encode_float (0.0);
+          PosMsg->angularVel[i] = XDR_encode_float (0.0);
+          PosMsg->linearAccel[i] = XDR_encode_float (0.0);
+          PosMsg->angularAccel[i] = XDR_encode_float (0.0);
+      }
+      // all other data remains unchanged (resend last state) 
+  }
+  else
+  {
+      PosMsg->time = XDR_encode_double (motionInfo.time);
+      PosMsg->lag = XDR_encode_double (motionInfo.lag);
+      for (unsigned i = 0 ; i < 3; ++i)
+        PosMsg->position[i] = XDR_encode_double (motionInfo.position(i));
+      SGVec3f angleAxis;
+      motionInfo.orientation.getAngleAxis(angleAxis);
+      for (unsigned i = 0 ; i < 3; ++i)
+        PosMsg->orientation[i] = XDR_encode_float (angleAxis(i));
+      for (unsigned i = 0 ; i < 3; ++i)
+        PosMsg->linearVel[i] = XDR_encode_float (motionInfo.linearVel(i));
+      for (unsigned i = 0 ; i < 3; ++i)
+        PosMsg->angularVel[i] = XDR_encode_float (motionInfo.angularVel(i));
+      for (unsigned i = 0 ; i < 3; ++i)
+        PosMsg->linearAccel[i] = XDR_encode_float (motionInfo.linearAccel(i));
+      for (unsigned i = 0 ; i < 3; ++i)
+        PosMsg->angularAccel[i] = XDR_encode_float (motionInfo.angularAccel(i));
+
+      xdr_data_t* ptr = msgBuf.properties();
+      std::vector<FGPropertyData*>::const_iterator it;
+      it = motionInfo.properties.begin();
+      //cout << "OUTPUT PROPERTIES\n";
+      xdr_data_t* msgEnd = msgBuf.propsEnd();
+      while (it != motionInfo.properties.end() && ptr + 2 < msgEnd) {
+        
+        // First element is the ID. Write it out when we know we have room for
+        // the whole property.
+        xdr_data_t id =  XDR_encode_uint32((*it)->id);
+        // The actual data representation depends on the type
+        switch ((*it)->type) {
+          case simgear::props::INT:
+          case simgear::props::BOOL:
+          case simgear::props::LONG:
             *ptr++ = id;
-            *ptr++ = XDR_encode_uint32(len);
-            if (len != 0)
+            *ptr++ = XDR_encode_uint32((*it)->int_value);
+            //cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->int_value << "\n";
+            break;
+          case simgear::props::FLOAT:
+          case simgear::props::DOUBLE:
+            *ptr++ = id;
+            *ptr++ = XDR_encode_float((*it)->float_value);
+            //cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->float_value << "\n";
+            break;
+          case simgear::props::STRING:
+          case simgear::props::UNSPECIFIED:
             {
-              // Now the text itself
-              // XXX This should not be using 4 bytes per character!
-              int lcount = 0;
-              while ((*lcharptr != '\0') && (lcount < MAX_TEXT_SIZE)) 
+              // String is complicated. It consists of
+              // The length of the string
+              // The string itself
+              // Padding to the nearest 4-bytes.        
+              const char* lcharptr = (*it)->string_value;
+              
+              if (lcharptr != 0)
               {
-                *ptr++ = XDR_encode_int8(*lcharptr);
-                lcharptr++;
-                lcount++;          
+                // Add the length         
+                ////cout << "String length: " << strlen(lcharptr) << "\n";
+                uint32_t len = strlen(lcharptr);
+                if (len > MAX_TEXT_SIZE)
+                  len = MAX_TEXT_SIZE;
+                // XXX This should not be using 4 bytes per character!
+                // If there's not enough room for this property, drop it
+                // on the floor.
+                if (ptr + 2 + ((len + 3) & ~3) > msgEnd)
+                    goto escape;
+                //cout << "String length unint32: " << len << "\n";
+                *ptr++ = id;
+                *ptr++ = XDR_encode_uint32(len);
+                if (len != 0)
+                {
+                  // Now the text itself
+                  // XXX This should not be using 4 bytes per character!
+                  int lcount = 0;
+                  while ((*lcharptr != '\0') && (lcount < MAX_TEXT_SIZE)) 
+                  {
+                    *ptr++ = XDR_encode_int8(*lcharptr);
+                    lcharptr++;
+                    lcount++;          
+                  }
+    
+                  //cout << "Prop:" << (*it)->id << " " << (*it)->type << " " << len << " " << (*it)->string_value;
+    
+                  // Now pad if required
+                  while ((lcount % 4) != 0)
+                  {
+                    *ptr++ = XDR_encode_int8(0);
+                    lcount++;          
+                    //cout << "0";
+                  }
+                  
+                  //cout << "\n";
+                }
               }
-
-              //cout << "Prop:" << (*it)->id << " " << (*it)->type << " " << len << " " << (*it)->string_value;
-
-              // Now pad if required
-              while ((lcount % 4) != 0)
+              else
               {
-                *ptr++ = XDR_encode_int8(0);
-                lcount++;          
-                //cout << "0";
+                // Nothing to encode
+                *ptr++ = id;
+                *ptr++ = XDR_encode_uint32(0);
+                //cout << "Prop:" << (*it)->id << " " << (*it)->type << " 0\n";
               }
-              
-              //cout << "\n";
             }
-          }
-          else
-          {
-            // Nothing to encode
+            break;
+            
+          default:
+            //cout << " Unknown Type: " << (*it)->type << "\n";
             *ptr++ = id;
-            *ptr++ = XDR_encode_uint32(0);
-            //cout << "Prop:" << (*it)->id << " " << (*it)->type << " 0\n";
-          }
+            *ptr++ = XDR_encode_float((*it)->float_value);;
+            //cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->float_value << "\n";
+            break;
         }
-        break;
-        
-      default:
-        //cout << " Unknown Type: " << (*it)->type << "\n";
-        *ptr++ = id;
-        *ptr++ = XDR_encode_float((*it)->float_value);;
-        //cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->float_value << "\n";
-        break;
-    }
-        
-    ++it;
+            
+        ++it;
+      }
+  escape:
+      msgLen = reinterpret_cast<char*>(ptr) - msgBuf.Msg;
+      FillMsgHdr(msgBuf.msgHdr(), POS_DATA_ID, msgLen);
   }
-escape:
-  unsigned msgLen = reinterpret_cast<char*>(ptr) - msgBuf.Msg;
-  FillMsgHdr(msgBuf.msgHdr(), POS_DATA_ID, msgLen);
-  mSocket->sendto(msgBuf.Msg, msgLen, 0, &mServer);
+  if (msgLen>0)
+      mSocket->sendto(msgBuf.Msg, msgLen, 0, &mServer);
   SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::SendMyPosition");
 } // FGMultiplayMgr::SendMyPosition()
 
@@ -731,7 +777,7 @@ FGMultiplayMgr::update(double)
     //  returned will only be that of the next
     //  packet waiting to be processed.
     //////////////////////////////////////////////////
-    netAddress SenderAddress;
+    simgear::IPAddress SenderAddress;
     bytes = mSocket->recvfrom(msgBuf.Msg, sizeof(msgBuf.Msg), 0,
                               &SenderAddress);
     //////////////////////////////////////////////////
@@ -764,7 +810,7 @@ FGMultiplayMgr::update(double)
     }
     if (MsgHdr->Version != PROTO_VER) {
       SG_LOG( SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::MP_ProcessData - "
-              << "message has invalid protocoll number!" );
+              << "message has invalid protocol number!" );
       break;
     }
     if (MsgHdr->MsgLen != bytes) {
@@ -815,7 +861,7 @@ FGMultiplayMgr::update(double)
 //////////////////////////////////////////////////////////////////////
 void
 FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
-                              const netAddress& SenderAddress, long stamp)
+                              const simgear::IPAddress& SenderAddress, long stamp)
 {
   const T_MsgHdr* MsgHdr = Msg.msgHdr();
   if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
@@ -842,6 +888,15 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
   for (unsigned i = 0; i < 3; ++i)
     motionInfo.angularAccel(i) = XDR_decode_float(PosMsg->angularAccel[i]);
 
+  // sanity check: do not allow injection of corrupted data (NaNs)
+  if (!isSane(motionInfo))
+  {
+      // drop this message, keep old position until receiving valid data
+      SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::ProcessPosMsg - "
+              << "Position message with invalid data (NaN) received from "
+              << MsgHdr->Callsign);
+      return;
+  }
 
   //cout << "INPUT MESSAGE\n";
 
@@ -868,19 +923,20 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
       goto noprops;
   }
   while (xdr < Msg.propsRecvdEnd()) {
-    FGPropertyData* pData = new FGPropertyData;
     // simgear::props::Type type = simgear::props::UNSPECIFIED;
     
     // First element is always the ID
-    pData->id = XDR_decode_uint32(*xdr);
+    unsigned id = XDR_decode_uint32(*xdr);
     //cout << pData->id << " ";
     xdr++;
     
     // Check the ID actually exists and get the type
-    const IdPropertyList* plist = findProperty(pData->id);
+    const IdPropertyList* plist = findProperty(id);
     
     if (plist)
     {
+      FGPropertyData* pData = new FGPropertyData;
+      pData->id = id;
       pData->type = plist->type;
       // How we decode the remainder of the property depends on the type
       switch (pData->type) {
@@ -937,7 +993,7 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
           SG_LOG(SG_NETWORK, SG_DEBUG, "Unknown Prop type " << pData->id << " " << pData->type);
           xdr++;
           break;
-      }            
+      }
 
       motionInfo.properties.push_back(pData);
     }
@@ -946,7 +1002,7 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
       // We failed to find the property. We'll try the next packet immediately.
       SG_LOG(SG_NETWORK, SG_INFO, "FGMultiplayMgr::ProcessPosMsg - "
              "message from " << MsgHdr->Callsign << " has unknown property id "
-             << pData->id); 
+             << id); 
     }
   }
  noprops:
@@ -960,12 +1016,12 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
 //////////////////////////////////////////////////////////////////////
 //
 //  handle a chat message
-//  FIXME: display chat message withi flightgear
+//  FIXME: display chat message within flightgear
 //
 //////////////////////////////////////////////////////////////////////
 void
 FGMultiplayMgr::ProcessChatMsg(const MsgBuf& Msg,
-                               const netAddress& SenderAddress)
+                               const simgear::IPAddress& SenderAddress)
 {
   const T_MsgHdr* MsgHdr = Msg.msgHdr();
   if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + 1) {