1
0
Fork 0

Merge branch 'maint' into next

This commit is contained in:
Tim Moore 2009-01-15 16:16:08 +01:00
commit 8a756eee54
4 changed files with 154 additions and 27 deletions

View file

@ -108,6 +108,12 @@ struct T_PositionMsg {
// angular acceleration wrt the earth centered frame measured in // angular acceleration wrt the earth centered frame measured in
// the earth centered frame // the earth centered frame
xdr_data_t angularAccel[3]; xdr_data_t angularAccel[3];
// Padding. The alignment is 8 bytes on x86_64 because there are
// 8-byte types in the message, so the size should be explicitly
// rounded out to a multiple of 8. Of course, it's a bad idea to
// put a C struct directly on the wire, but that's a fight for
// another day...
xdr_data_t pad;
}; };
struct FGPropertyData { struct FGPropertyData {

View file

@ -32,6 +32,8 @@
#endif #endif
#include <iostream> #include <iostream>
#include <algorithm>
#include <osg/Math> // isNaN
#include <plib/netSocket.h> #include <plib/netSocket.h>
#include <simgear/misc/stdint.hxx> #include <simgear/misc/stdint.hxx>
@ -58,7 +60,7 @@ const char sMULTIPLAYMGR_HID[] = MULTIPLAYTXMGR_HID;
// This should be extendable dynamically for every specific aircraft ... // This should be extendable dynamically for every specific aircraft ...
// For now only that static list // For now only that static list
FGMultiplayMgr::IdPropertyList FGMultiplayMgr::IdPropertyList
FGMultiplayMgr::sIdPropertyList[] = { const FGMultiplayMgr::sIdPropertyList[] = {
{100, "surface-positions/left-aileron-pos-norm", SGPropertyNode::FLOAT}, {100, "surface-positions/left-aileron-pos-norm", SGPropertyNode::FLOAT},
{101, "surface-positions/right-aileron-pos-norm", SGPropertyNode::FLOAT}, {101, "surface-positions/right-aileron-pos-norm", SGPropertyNode::FLOAT},
{102, "surface-positions/elevator-pos-norm", SGPropertyNode::FLOAT}, {102, "surface-positions/elevator-pos-norm", SGPropertyNode::FLOAT},
@ -222,11 +224,115 @@ FGMultiplayMgr::sIdPropertyList[] = {
{10317, "sim/multiplay/generic/int[17]", SGPropertyNode::INT}, {10317, "sim/multiplay/generic/int[17]", SGPropertyNode::INT},
{10318, "sim/multiplay/generic/int[18]", SGPropertyNode::INT}, {10318, "sim/multiplay/generic/int[18]", SGPropertyNode::INT},
{10319, "sim/multiplay/generic/int[19]", SGPropertyNode::INT}, {10319, "sim/multiplay/generic/int[19]", SGPropertyNode::INT},
/// termination
{0, 0, SGPropertyNode::UNSPECIFIED}
}; };
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 // MultiplayMgr constructor
@ -355,6 +461,8 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
} }
T_PositionMsg PosMsg; T_PositionMsg PosMsg;
memset(&PosMsg, 0, sizeof(PosMsg));
strncpy(PosMsg.Model, fgGetString("/sim/model/path"), MAX_MODEL_NAME_LEN); strncpy(PosMsg.Model, fgGetString("/sim/model/path"), MAX_MODEL_NAME_LEN);
PosMsg.Model[MAX_MODEL_NAME_LEN - 1] = '\0'; PosMsg.Model[MAX_MODEL_NAME_LEN - 1] = '\0';
@ -677,6 +785,29 @@ FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
//cout << "INPUT MESSAGE\n"; //cout << "INPUT MESSAGE\n";
xdr_data_t* xdr = (xdr_data_t*) xdr_data_t* xdr = (xdr_data_t*)
(Msg + sizeof(T_MsgHdr) + sizeof(T_PositionMsg)); (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) { while ((char*)xdr < Msg + len) {
FGPropertyData* pData = new FGPropertyData; FGPropertyData* pData = new FGPropertyData;
SGPropertyNode::Type type = SGPropertyNode::UNSPECIFIED; SGPropertyNode::Type type = SGPropertyNode::UNSPECIFIED;
@ -687,21 +818,11 @@ FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
xdr++; xdr++;
// Check the ID actually exists and get the type // Check the ID actually exists and get the type
unsigned i = 0; const IdPropertyList* plist = findProperty(pData->id);
bool found = false;
while (FGMultiplayMgr::sIdPropertyList[i].name)
{
if (sIdPropertyList[i].id == pData->id)
{
found = true;
pData->type = sIdPropertyList[i].type;
}
i++; if (plist)
}
if (found == true)
{ {
pData->type = plist->type;
// How we decode the remainder of the property depends on the type // How we decode the remainder of the property depends on the type
switch (pData->type) { switch (pData->type) {
case SGPropertyNode::INT: case SGPropertyNode::INT:
@ -772,10 +893,11 @@ FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
else else
{ {
// We failed to find the property. We'll try the next packet immediately. // 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); FGAIMultiplayer* mp = getMultiplayer(MsgHdr->Callsign);
if (!mp) if (!mp)
mp = addMultiplayer(MsgHdr->Callsign, PosMsg->Model); mp = addMultiplayer(MsgHdr->Callsign, PosMsg->Model);
@ -854,11 +976,8 @@ FGMultiplayMgr::addMultiplayer(const std::string& callsign,
aiMgr->attach(mp); aiMgr->attach(mp);
/// FIXME: that must follow the attach ATM ... /// FIXME: that must follow the attach ATM ...
unsigned i = 0; for (unsigned i = 0; i < numProperties; ++i)
while (sIdPropertyList[i].name) {
mp->addPropertyId(sIdPropertyList[i].id, sIdPropertyList[i].name); mp->addPropertyId(sIdPropertyList[i].id, sIdPropertyList[i].name);
++i;
}
} }
return mp; return mp;

View file

@ -60,7 +60,10 @@ public:
const char* name; const char* name;
SGPropertyNode::Type type; SGPropertyNode::Type type;
}; };
static IdPropertyList sIdPropertyList[]; static const IdPropertyList sIdPropertyList[];
static const unsigned numProperties;
static const IdPropertyList* findProperty(unsigned id);
FGMultiplayMgr(); FGMultiplayMgr();
~FGMultiplayMgr(); ~FGMultiplayMgr();

View file

@ -101,13 +101,12 @@ bool FGMultiplay::open() {
SGPropertyNode* root = globals->get_props(); SGPropertyNode* root = globals->get_props();
/// Build up the id to property map /// Build up the id to property map
unsigned i = 0;
while (FGMultiplayMgr::sIdPropertyList[i].name) { for (unsigned i = 0; i < FGMultiplayMgr::numProperties; ++i) {
const char* name = FGMultiplayMgr::sIdPropertyList[i].name; const char* name = FGMultiplayMgr::sIdPropertyList[i].name;
SGPropertyNode* pNode = root->getNode(name); SGPropertyNode* pNode = root->getNode(name);
if (pNode) if (pNode)
mPropertyMap[FGMultiplayMgr::sIdPropertyList[i].id] = pNode; mPropertyMap[FGMultiplayMgr::sIdPropertyList[i].id] = pNode;
++i;
} }
return is_enabled(); return is_enabled();