]> git.mxchange.org Git - flightgear.git/blobdiff - src/MultiPlayer/multiplaymgr.cxx
Merge branch 'maint' into next
[flightgear.git] / src / MultiPlayer / multiplaymgr.cxx
index 8983205a0ffc4bbb2aa33168737f2c870f5cb34a..b0bb1e0925011f72f3e37459acad19355905909a 100644 (file)
@@ -32,6 +32,8 @@
 #endif
 
 #include <iostream>
+#include <algorithm>
+#include <osg/Math>             // isNaN
 #include <plib/netSocket.h>
 
 #include <simgear/misc/stdint.hxx>
@@ -58,7 +60,7 @@ const char sMULTIPLAYMGR_HID[] = MULTIPLAYTXMGR_HID;
 // This should be extendable dynamically for every specific aircraft ...
 // For now only that static list
 FGMultiplayMgr::IdPropertyList
-FGMultiplayMgr::sIdPropertyList[] = {
+const FGMultiplayMgr::sIdPropertyList[] = {
   {100, "surface-positions/left-aileron-pos-norm",  SGPropertyNode::FLOAT},
   {101, "surface-positions/right-aileron-pos-norm", SGPropertyNode::FLOAT},
   {102, "surface-positions/elevator-pos-norm",      SGPropertyNode::FLOAT},
@@ -155,6 +157,8 @@ FGMultiplayMgr::sIdPropertyList[] = {
   {1100, "sim/model/variant", SGPropertyNode::INT},
   {1101, "sim/model/livery/file", SGPropertyNode::STRING},
 
+  {1200, "environment/wildfire/data", SGPropertyNode::STRING},
+
   {10001, "sim/multiplay/transmission-freq-hz",  SGPropertyNode::STRING},
   {10002, "sim/multiplay/chat",  SGPropertyNode::STRING},
 
@@ -168,6 +172,16 @@ FGMultiplayMgr::sIdPropertyList[] = {
   {10107, "sim/multiplay/generic/string[7]", SGPropertyNode::STRING},
   {10108, "sim/multiplay/generic/string[8]", SGPropertyNode::STRING},
   {10109, "sim/multiplay/generic/string[9]", SGPropertyNode::STRING},
+  {10110, "sim/multiplay/generic/string[10]", SGPropertyNode::STRING},
+  {10111, "sim/multiplay/generic/string[11]", SGPropertyNode::STRING},
+  {10112, "sim/multiplay/generic/string[12]", SGPropertyNode::STRING},
+  {10113, "sim/multiplay/generic/string[13]", SGPropertyNode::STRING},
+  {10114, "sim/multiplay/generic/string[14]", SGPropertyNode::STRING},
+  {10115, "sim/multiplay/generic/string[15]", SGPropertyNode::STRING},
+  {10116, "sim/multiplay/generic/string[16]", SGPropertyNode::STRING},
+  {10117, "sim/multiplay/generic/string[17]", SGPropertyNode::STRING},
+  {10118, "sim/multiplay/generic/string[18]", SGPropertyNode::STRING},
+  {10119, "sim/multiplay/generic/string[19]", SGPropertyNode::STRING},
 
   {10200, "sim/multiplay/generic/float[0]", SGPropertyNode::FLOAT},
   {10201, "sim/multiplay/generic/float[1]", SGPropertyNode::FLOAT},
@@ -179,6 +193,16 @@ FGMultiplayMgr::sIdPropertyList[] = {
   {10207, "sim/multiplay/generic/float[7]", SGPropertyNode::FLOAT},
   {10208, "sim/multiplay/generic/float[8]", SGPropertyNode::FLOAT},
   {10209, "sim/multiplay/generic/float[9]", SGPropertyNode::FLOAT},
+  {10210, "sim/multiplay/generic/float[10]", SGPropertyNode::FLOAT},
+  {10211, "sim/multiplay/generic/float[11]", SGPropertyNode::FLOAT},
+  {10212, "sim/multiplay/generic/float[12]", SGPropertyNode::FLOAT},
+  {10213, "sim/multiplay/generic/float[13]", SGPropertyNode::FLOAT},
+  {10214, "sim/multiplay/generic/float[14]", SGPropertyNode::FLOAT},
+  {10215, "sim/multiplay/generic/float[15]", SGPropertyNode::FLOAT},
+  {10216, "sim/multiplay/generic/float[16]", SGPropertyNode::FLOAT},
+  {10217, "sim/multiplay/generic/float[17]", SGPropertyNode::FLOAT},
+  {10218, "sim/multiplay/generic/float[18]", SGPropertyNode::FLOAT},
+  {10219, "sim/multiplay/generic/float[19]", SGPropertyNode::FLOAT},
 
   {10300, "sim/multiplay/generic/int[0]", SGPropertyNode::INT},
   {10301, "sim/multiplay/generic/int[1]", SGPropertyNode::INT},
@@ -190,11 +214,125 @@ FGMultiplayMgr::sIdPropertyList[] = {
   {10307, "sim/multiplay/generic/int[7]", SGPropertyNode::INT},
   {10308, "sim/multiplay/generic/int[8]", SGPropertyNode::INT},
   {10309, "sim/multiplay/generic/int[9]", SGPropertyNode::INT},
-
-  /// termination
-  {0, 0, SGPropertyNode::UNSPECIFIED}
+  {10310, "sim/multiplay/generic/int[10]", SGPropertyNode::INT},
+  {10311, "sim/multiplay/generic/int[11]", SGPropertyNode::INT},
+  {10312, "sim/multiplay/generic/int[12]", SGPropertyNode::INT},
+  {10313, "sim/multiplay/generic/int[13]", SGPropertyNode::INT},
+  {10314, "sim/multiplay/generic/int[14]", SGPropertyNode::INT},
+  {10315, "sim/multiplay/generic/int[15]", SGPropertyNode::INT},
+  {10316, "sim/multiplay/generic/int[16]", SGPropertyNode::INT},
+  {10317, "sim/multiplay/generic/int[17]", SGPropertyNode::INT},
+  {10318, "sim/multiplay/generic/int[18]", SGPropertyNode::INT},
+  {10319, "sim/multiplay/generic/int[19]", SGPropertyNode::INT},
 };
 
+const unsigned
+FGMultiplayMgr::numProperties = (sizeof(FGMultiplayMgr::sIdPropertyList)
+                                 / sizeof(FGMultiplayMgr::sIdPropertyList[0]));
+
+// Look up a property ID using binary search.
+namespace
+{
+  struct ComparePropertyId
+  {
+    bool operator()(const FGMultiplayMgr::IdPropertyList& lhs,
+                    const FGMultiplayMgr::IdPropertyList& rhs)
+    {
+      return lhs.id < rhs.id;
+    }
+    bool operator()(const FGMultiplayMgr::IdPropertyList& lhs,
+                    unsigned id)
+    {
+      return lhs.id < id;
+    }
+    bool operator()(unsigned id,
+                    const FGMultiplayMgr::IdPropertyList& rhs)
+    {
+      return id < rhs.id;
+    }
+  };
+    
+}
+const FGMultiplayMgr::IdPropertyList* FGMultiplayMgr::findProperty(unsigned id)
+{
+  std::pair<const IdPropertyList*, const IdPropertyList*> result
+    = std::equal_range(sIdPropertyList, sIdPropertyList + numProperties, id,
+                       ComparePropertyId());
+  if (result.first == result.second) {
+    return 0;
+  } else {
+    return result.first;
+  }
+}
+
+namespace
+{
+  bool verifyProperties(const xdr_data_t* data, const xdr_data_t* end)
+  {
+    const xdr_data_t* xdr = data;
+    while (xdr < end) {
+      unsigned id = XDR_decode_uint32(*xdr);
+      const FGMultiplayMgr::IdPropertyList* plist
+        = FGMultiplayMgr::findProperty(id);
+    
+      if (plist) {
+        xdr++;
+        // How we decode the remainder of the property depends on the type
+        switch (plist->type) {
+        case SGPropertyNode::INT:        
+        case SGPropertyNode::BOOL:
+        case SGPropertyNode::LONG:
+          xdr++;
+          break;
+        case SGPropertyNode::FLOAT:
+        case SGPropertyNode::DOUBLE:
+          {
+            float val = XDR_decode_float(*xdr);
+            if (osg::isNaN(val))
+              return false;
+            xdr++;
+            break;
+          }
+        case SGPropertyNode::STRING:
+        case SGPropertyNode::UNSPECIFIED:
+          {
+            // String is complicated. It consists of
+            // The length of the string
+            // The string itself
+            // Padding to the nearest 4-bytes.
+            // XXX Yes, each byte is padded out to a word! Too late
+            // to change...
+            uint32_t length = XDR_decode_uint32(*xdr);
+            xdr++;
+            if ((length > 0) && (length < MAX_TEXT_SIZE)) {
+              xdr += length;
+              // Now handle the padding
+              while ((length % 4) != 0)
+                {
+                  xdr++;
+                  length++;
+                  //cout << "0";
+                }
+            } else {
+              // The string appears to be invalid; bail.
+              return false;
+            }
+          }
+          break;
+        default:
+          // cerr << "Unknown Prop type " << id << " " << type << "\n";
+          xdr++;
+          break;
+        }            
+      }
+      else {
+        // give up; this is a malformed property list.
+        return false;
+      }
+    }
+    return true;
+  }
+}
 //////////////////////////////////////////////////////////////////////
 //
 //  MultiplayMgr constructor
@@ -323,6 +461,8 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
   }
 
   T_PositionMsg PosMsg;
+
+  memset(&PosMsg, 0, sizeof(PosMsg));
   strncpy(PosMsg.Model, fgGetString("/sim/model/path"), MAX_MODEL_NAME_LEN);
   PosMsg.Model[MAX_MODEL_NAME_LEN - 1] = '\0';
   
@@ -645,6 +785,29 @@ FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
   //cout << "INPUT MESSAGE\n";
   xdr_data_t* xdr = (xdr_data_t*) 
                    (Msg + sizeof(T_MsgHdr) + sizeof(T_PositionMsg));
+  // There was a bug in 1.9.0 and before: T_PositionMsg was 196 bytes
+  // on 32 bit architectures and 200 bytes on 64 bit, and this
+  // structure is put directly on the wire. By looking at the padding,
+  // we can sort through the mess, mostly:
+  // If padding is 0 (which is not a valid property type), then the
+  // message was produced by a new client or an old 64 bit client that
+  // happened to have 0 on the stack;
+  // Else if the property list starting with the padding word is
+  // well-formed, then the client is probably an old 32 bit client and
+  // we'll go with that;
+  // Else it is an old 64-bit client and properties start after the
+  // padding.
+  // There is a chance that we could be fooled by garbage in the
+  // padding looking like a valid property, so verifyProperties() is
+  // strict about the validity of the property values.
+  if (PosMsg->pad != 0) {
+    if (verifyProperties(&PosMsg->pad,
+                         reinterpret_cast<const xdr_data_t*>(Msg + len)))
+      xdr = &PosMsg->pad;
+    else if (!verifyProperties(xdr,
+                               reinterpret_cast<const xdr_data_t*>(Msg + len)))
+      goto noprops;
+  }
   while ((char*)xdr < Msg + len) {
     FGPropertyData* pData = new FGPropertyData;
     SGPropertyNode::Type type = SGPropertyNode::UNSPECIFIED;
@@ -655,21 +818,11 @@ FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
     xdr++;
     
     // Check the ID actually exists and get the type
-    unsigned i = 0;
-    bool found = false;
-    while (FGMultiplayMgr::sIdPropertyList[i].name) 
-    {
-      if (sIdPropertyList[i].id == pData->id)
-      {
-        found = true;
-        pData->type = sIdPropertyList[i].type;
-      } 
-      
-      i++;
-    }
+    const IdPropertyList* plist = findProperty(pData->id);
     
-    if (found == true)
+    if (plist)
     {
+      pData->type = plist->type;
       // How we decode the remainder of the property depends on the type
       switch (pData->type) {
         case SGPropertyNode::INT:        
@@ -740,10 +893,11 @@ FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
     else
     {
       // We failed to find the property. We'll try the next packet immediately.
-      //cout << " Unknown\n";
+      SG_LOG(SG_NETWORK, SG_WARN, "FGMultiplayMgr::ProcessPosMsg - "
+             << "found unknown property id" << pData->id); 
     }
   }
-  
+ noprops:
   FGAIMultiplayer* mp = getMultiplayer(MsgHdr->Callsign);
   if (!mp)
     mp = addMultiplayer(MsgHdr->Callsign, PosMsg->Model);
@@ -822,11 +976,8 @@ FGMultiplayMgr::addMultiplayer(const std::string& callsign,
     aiMgr->attach(mp);
 
     /// FIXME: that must follow the attach ATM ...
-    unsigned i = 0;
-    while (sIdPropertyList[i].name) {
+    for (unsigned i = 0; i < numProperties; ++i)
       mp->addPropertyId(sIdPropertyList[i].id, sIdPropertyList[i].name);
-      ++i;
-    }
   }
 
   return mp;