1
0
Fork 0

Fix various mp bugs.

In multiplaymgr.cxx:
The length of a string property that is too big was written out in the message
even though the string was truncated. Also, it was possible to overrun the
message buffer.

In incoming  messages, null-terminate the callsign to prevent any funny
business. Don't believe invalid string lengths. Turn the warning about unknown
properties from a warning into info; there are too many buggy clients out there,
not to mention people who add their own MP properties (hi vivian :)
This commit is contained in:
Tim Moore 2009-02-05 23:18:26 +01:00
parent bfc059aa03
commit e83caa6321

View file

@ -302,19 +302,18 @@ namespace
// 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;
}
// Old versions truncated the string but left the length
// unadjusted.
if (length > MAX_TEXT_SIZE)
length = MAX_TEXT_SIZE;
xdr += length;
// Now handle the padding
while ((length % 4) != 0)
{
xdr++;
length++;
//cout << "0";
}
}
break;
default:
@ -480,37 +479,38 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
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));
char Msg[MAX_PACKET_SIZE];
memcpy(Msg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
// ensure alignment of message buffer
union {
xdr_data2_t double_val;
char Msg[MAX_PACKET_SIZE];
} msgBuf;
memcpy(msgBuf.Msg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
char* ptr = Msg + sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
xdr_data_t* ptr = reinterpret_cast<xdr_data_t*>(msgBuf.Msg + sizeof(T_MsgHdr)
+ sizeof(T_PositionMsg));
std::vector<FGPropertyData*>::const_iterator it;
it = motionInfo.properties.begin();
//cout << "OUTPUT PROPERTIES\n";
while (it != motionInfo.properties.end()
&& ptr + 2 * sizeof(xdr_data_t) < (Msg + MAX_PACKET_SIZE)) {
// First elements is the ID
xdr_data_t xdr = XDR_encode_uint32((*it)->id);
memcpy(ptr, &xdr, sizeof(xdr_data_t));
ptr += sizeof(xdr_data_t);
xdr_data_t* msgEnd = reinterpret_cast<xdr_data_t*>(msgBuf.Msg
+ MAX_PACKET_SIZE);
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 SGPropertyNode::INT:
case SGPropertyNode::BOOL:
case SGPropertyNode::LONG:
xdr = XDR_encode_uint32((*it)->int_value);
memcpy(ptr, &xdr, sizeof(xdr_data_t));
ptr += sizeof(xdr_data_t);
case SGPropertyNode::LONG:
*ptr++ = id;
*ptr++ = XDR_encode_uint32((*it)->int_value);
//cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->int_value << "\n";
break;
case SGPropertyNode::FLOAT:
case SGPropertyNode::DOUBLE:
xdr = XDR_encode_float((*it)->float_value);;
memcpy(ptr, &xdr, sizeof(xdr_data_t));
ptr += sizeof(xdr_data_t);
*ptr++ = id;
*ptr++ = XDR_encode_float((*it)->float_value);
//cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->float_value << "\n";
break;
case SGPropertyNode::STRING:
@ -527,26 +527,24 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
// 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 (ptr + (1 + len + (4 - len % 4)) * sizeof (xdr_data_t)
>= (Msg + MAX_PACKET_SIZE))
// 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";
xdr = XDR_encode_uint32(len);
memcpy(ptr, &xdr, sizeof(xdr_data_t));
ptr += sizeof(xdr_data_t);
*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))
{
xdr = XDR_encode_int8(*lcharptr);
memcpy(ptr, &xdr, sizeof(xdr_data_t));
ptr += sizeof(xdr_data_t);
*ptr++ = XDR_encode_int8(*lcharptr);
lcharptr++;
lcount++;
}
@ -556,9 +554,7 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
// Now pad if required
while ((lcount % 4) != 0)
{
xdr = XDR_encode_int8(0);
memcpy(ptr, &xdr, sizeof(xdr_data_t));
ptr += sizeof(xdr_data_t);
*ptr++ = XDR_encode_int8(0);
lcount++;
//cout << "0";
}
@ -569,20 +565,17 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
else
{
// Nothing to encode
xdr = XDR_encode_uint32(0);
memcpy(ptr, &xdr, sizeof(xdr_data_t));
ptr += sizeof(xdr_data_t);
*ptr++ = id;
*ptr++ = XDR_encode_uint32(0);
//cout << "Prop:" << (*it)->id << " " << (*it)->type << " 0\n";
}
}
break;
default:
//cout << " Unknown Type: " << (*it)->type << "\n";
xdr = XDR_encode_float((*it)->float_value);;
memcpy(ptr, &xdr, sizeof(xdr_data_t));
ptr += sizeof(xdr_data_t);
*ptr++ = id;
*ptr++ = XDR_encode_float((*it)->float_value);;
//cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->float_value << "\n";
break;
}
@ -592,10 +585,11 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
escape:
T_MsgHdr MsgHdr;
FillMsgHdr(&MsgHdr, POS_DATA_ID, ptr - Msg);
memcpy(Msg, &MsgHdr, sizeof(T_MsgHdr));
unsigned msgLen = reinterpret_cast<char*>(ptr) - msgBuf.Msg;
FillMsgHdr(&MsgHdr, POS_DATA_ID, msgLen);
memcpy(msgBuf.Msg, &MsgHdr, sizeof(T_MsgHdr));
mSocket->sendto(Msg, ptr - Msg, 0, &mServer);
mSocket->sendto(msgBuf.Msg, msgLen, 0, &mServer);
SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::SendMyPosition");
} // FGMultiplayMgr::SendMyPosition()
//////////////////////////////////////////////////////////////////////
@ -663,7 +657,11 @@ FGMultiplayMgr::Update(void)
//////////////////////////////////////////////////
int bytes;
do {
char Msg[MAX_PACKET_SIZE];
// ensure alignment
union {
xdr_data2_t doubleVal;
char Msg[MAX_PACKET_SIZE];
} msgBuf;
//////////////////////////////////////////////////
// Although the recv call asks for
// MAX_PACKET_SIZE of data, the number of bytes
@ -671,7 +669,8 @@ FGMultiplayMgr::Update(void)
// packet waiting to be processed.
//////////////////////////////////////////////////
netAddress SenderAddress;
bytes = mSocket->recvfrom(Msg, sizeof(Msg), 0, &SenderAddress);
bytes = mSocket->recvfrom(msgBuf.Msg, sizeof(msgBuf.Msg), 0,
&SenderAddress);
//////////////////////////////////////////////////
// no Data received
//////////////////////////////////////////////////
@ -688,12 +687,13 @@ FGMultiplayMgr::Update(void)
//////////////////////////////////////////////////
// Read header
//////////////////////////////////////////////////
T_MsgHdr* MsgHdr = (T_MsgHdr *)Msg;
T_MsgHdr* MsgHdr = reinterpret_cast<T_MsgHdr *>(msgBuf.Msg);
MsgHdr->Magic = XDR_decode_uint32 (MsgHdr->Magic);
MsgHdr->Version = XDR_decode_uint32 (MsgHdr->Version);
MsgHdr->MsgId = XDR_decode_uint32 (MsgHdr->MsgId);
MsgHdr->MsgLen = XDR_decode_uint32 (MsgHdr->MsgLen);
MsgHdr->ReplyPort = XDR_decode_uint32 (MsgHdr->ReplyPort);
MsgHdr->Callsign[MAX_CALLSIGN_LEN -1] = '\0';
if (MsgHdr->Magic != MSG_MAGIC) {
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
<< "message has invalid magic number!" );
@ -705,8 +705,8 @@ FGMultiplayMgr::Update(void)
break;
}
if (MsgHdr->MsgLen != bytes) {
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
<< "message has invalid length!" );
SG_LOG(SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
<< "message from " << MsgHdr->Callsign << " has invalid length!");
break;
}
//////////////////////////////////////////////////
@ -714,10 +714,10 @@ FGMultiplayMgr::Update(void)
//////////////////////////////////////////////////
switch (MsgHdr->MsgId) {
case CHAT_MSG_ID:
ProcessChatMsg(Msg, SenderAddress);
ProcessChatMsg(msgBuf.Msg, SenderAddress);
break;
case POS_DATA_ID:
ProcessPosMsg(Msg, SenderAddress, bytes, stamp);
ProcessPosMsg(msgBuf.Msg, SenderAddress, bytes, stamp);
break;
case UNUSABLE_POS_DATA_ID:
case OLD_OLD_POS_DATA_ID:
@ -754,13 +754,14 @@ void
FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
unsigned len, long stamp)
{
T_MsgHdr* MsgHdr = (T_MsgHdr *)Msg;
const T_MsgHdr* MsgHdr = reinterpret_cast<const T_MsgHdr *>(Msg);
if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
<< "Position message received with insufficient data" );
return;
}
T_PositionMsg* PosMsg = (T_PositionMsg *)(Msg + sizeof(T_MsgHdr));
const T_PositionMsg* PosMsg
= reinterpret_cast<const T_PositionMsg *>(Msg + sizeof(T_MsgHdr));
FGExternalMotionData motionInfo;
motionInfo.time = XDR_decode_double(PosMsg->time);
motionInfo.lag = XDR_decode_double(PosMsg->lag);
@ -781,8 +782,7 @@ 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));
const 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,
@ -846,35 +846,27 @@ FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
uint32_t length = XDR_decode_uint32(*xdr);
xdr++;
//cout << length << " ";
if ((length > 0) && (length < MAX_TEXT_SIZE))
{
pData->string_value = new char[length + 1];
//cout << " String: ";
for (int i = 0; i < length; i++)
// Old versions truncated the string but left the length unadjusted.
if (length > MAX_TEXT_SIZE)
length = MAX_TEXT_SIZE;
pData->string_value = new char[length + 1];
//cout << " String: ";
for (int i = 0; i < length; i++)
{
pData->string_value[i] = (char) XDR_decode_int8(*xdr);
xdr++;
//cout << pData->string_value[i];
}
pData->string_value[length] = '\0';
pData->string_value[length] = '\0';
// Now handle the padding
while ((length % 4) != 0)
// Now handle the padding
while ((length % 4) != 0)
{
xdr++;
length++;
//cout << "0";
}
}
else
{
pData->string_value = new char[1];
pData->string_value[0] = '\0';
}
//cout << "\n";
}
break;
@ -891,8 +883,9 @@ FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
else
{
// We failed to find the property. We'll try the next packet immediately.
SG_LOG(SG_NETWORK, SG_WARN, "FGMultiplayMgr::ProcessPosMsg - "
<< "found unknown property id" << pData->id);
SG_LOG(SG_NETWORK, SG_INFO, "FGMultiplayMgr::ProcessPosMsg - "
"message from " << MsgHdr->Callsign << " has unknown property id "
<< pData->id);
}
}
noprops: