2
votes

tl;dr I am unable to read floats from a an istream created from a boost::streambuf which is filled using the boost asio UDP socket interface. The data I have appears corrupt or processed incorrectly.

I am currently writing an interface that will implement the DIS (Distributed Interactive Simulation) protocol. I am using the boost::asio libraries to open a UDP socket and to receive the data. I am pulling the data off the wire and into a streambuf correctly, but I am unable to read floats.

Code for socket:

boost::asio::streambuf streamBuf;
boost::asio::streambuf::mutable_buffers_type buf = streamBuf.prepare(maxSize);

udp::endpoint senderEndpoint;
size_t packetLength;

try {
    packetLength = sock.receive_from(buf, senderEndpoint);
    streamBuf.commit(packetLength);
} catch(boost::system::system_error se) {
    std::cout << "ERROR: " << se.what() << std::endl;
}
std::istream stream(&streamBuf);

Code to read from istream

float       readFloat32(std::istream& stream) {
    float ret;
    stream.read((char*)&ret, sizeof(float));
    return ret;
}
double      readFloat64(std::istream& stream) {
    double ret;
    stream.read((char*)&ret, sizeof(double));
    return ret;
}

Now I have similar functions written for every data type I need (mostly uint8_t - uint32_t).

Parsing the PDU

//--Entity ID
    entityState.entityID.siteID = readUInt16(stream);
    entityState.entityID.appID = readUInt16(stream);
    entityState.entityID.entityID = readUInt16(stream);
...etc, etc.
//--Entity Linear Velocity
    entityState.entityLinearVelocity.x = readFloat32(stream);
    entityState.entityLinearVelocity.y = readFloat32(stream);
    entityState.entityLinearVelocity.z = readFloat32(stream);
...etc, etc.

The data I am trying to parse looks like the photo at the very end. I can parse everything just fine, but the when I get to the "Entity Linear Velocity" block which consists of 3 32-bit floating point numbers, my data become wrong. Using wireshark I have confirmed that the correct btyestream is being sent across the wire.

For the velocity I am sending this series of bytes:

 42 74 aa 97 c2 80 b3 8f 42 e2 dc 54

Which equates to 61.166592,-64.350700 and 113.430328. However, my application reads this as

42 72 ffffffaa ffffff97 ffffffc2 ffffff80 ffffffb3 ffffff8f 42 ffffffe2 ffffffdc 54

And my floats end up being -1.10153e-24, -1.77004e-29, and 7.58951e+12.

Does anyone have any idea why I can read all sorts of various sizes of uints using this implementation, but the float fails to make any sense?

enter image description here

1

1 Answers

0
votes

It is probably due to endianess issues. The following kind of code worked when tested with

std::string bin = {'\x42', '\x74', '\xaa', '\x97'};
std::istringstream raw(bin);

With byteswapping i.e. ntohl,

float readFloat32(std::istream& stream) {
    union {
       float fval;
       uint32_t ival;
    } ret;
    stream.read((char*)&ret, sizeof(float));
    ret.ival = ntohl(ret.ival);
    return ret.fval;
}

The value returned by readFloat was 61.1666 after adding byteswapping.