Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe, efficient way to access unaligned data in a network packet from C

I'm writing a program in C for Linux on an ARM9 processor. The program is to access network packets which include a sequence of tagged data like:

<fieldID><length><data><fieldID><length><data> ...

The fieldID and length fields are both uint16_t. The data can be 1 or more bytes (up to 64k if the full length was used, but it's not).

As long as <data> has an even number of bytes, I don't see a problem. But if I have a 1- or 3- or 5-byte <data> section then the next 16-bit fieldID ends up not on a 16-bit boundary and I anticipate alignment issues. It's been a while since I've done any thing like this from scratch so I'm a little unsure of the details. Any feedback welcome. Thanks.

like image 382
Chris Nelson Avatar asked Dec 08 '22 08:12

Chris Nelson


2 Answers

To avoid alignment issues in this case, access all data as an unsigned char *. So:

unsigned char *p;
//...
uint16_t id = p[0] | (p[1] << 8);
p += 2;

The above example assumes "little endian" data layout, where the least significant byte comes first in a multi-byte number.

like image 100
Greg Hewgill Avatar answered Dec 09 '22 22:12

Greg Hewgill


You should have functions (inline and/or templated if the language you're using supports those features) that will read the potentially unaligned data and return the data type you're interested in. Something like:

uint16_t unaligned_uint16( void* p)
{
    // this assumes big-endian values in data stream
    //  (which is common, but not universal in network
    //  communications) - this may or may not be 
    //  appropriate in your case

    unsigned char* pByte = (unsigned char*) p;

    uint16_t val = (pByte[0] << 8) | pByte[1];

    return val;
}
like image 36
Michael Burr Avatar answered Dec 09 '22 21:12

Michael Burr