quote:
Original post by Zoomby
...
if you don't know if a bit-field will be in the high or low section of a byte, you can't know how to mask and shift to get the right bits!? That would mean, that such code is never portable? Or am I wrong?
You're not entirely wrong, but you're not exactly right (not to sound like a politician).
DigitalFiend's method isn't actually portable
as-is , but can easily be made somewhat portable by appropriate use of hton/ntoh functions. This would be a lot harder to do if you use bit fields.
Bit fields are nice, however, and you should at least consider using them (I'm not necessarily saying
to use them, but I challenge you to at least consider if they are the right solution). Especially on little endian machines such as the one you're likely working with, bit fields are easier to "see" than DigitalFiend's method. e.g.:
// WARNING: DO NOT USE this code! Each of these structures// contains a bug. The point is to find out how easy it is// to find the bug in each version.struct TcpHeaderBits{ //-- RFC 752 Figure 3 row 1 unsigned SrcPort : 16; unsigned DstPort : 16; //-- RFC 752 Figure 3 row 2 unsigned Sequence : 32; //-- RFC 752 Figure 3 row 3 unsigned AckNum : 32; //-- RFC 752 Figure 3 row 4 unsigned DataOffset : 3; : 6; unsigned URG : 1; unsigned ACK : 1; unsigned PSH : 1; unsigned RST : 1; unsigned SYN : 1; unsigned FIN : 1; unsigned Window : 16; //-- RFC 752 Figure 3 row 5 unsigned Checksum : 16; unsigned UrgentPtr : 16; //-- RFC 752 Figure 3 row 6 unsigned Options : 24; : 8;};// not shown--helper #define's for uint#'s and ucharstruct TcpHeaderMethods{ uint32 Row1; uint32 Row2; uint32 Row3; uint32 Row4; uint32 Row5; uint32 Row6; inline uint16 SrcPort() {return (Row1>>16) & 0x0ffff;} inline uint16 DstPort() {return (Row1) & 0x0ffff;} inline uint32 Sequence() {return Row2;} inline uint32 AckNum() {return Row3;} inline uchar DataOffset(){return (Row4>>29) & 0x0f;} inline uchar URG() {return (Row4>>21) & 0x01;} inline uchar ACK() {return (Row4>>20) & 0x01;} inline uchar PSH() {return (Row4>>19) & 0x01;} inline uchar RST() {return (Row4>>18) & 0x01;} inline uchar SYN() {return (Row4>>17) & 0x01;} inline uchar FIN() {return (Row4>>16) & 0x01;} inline uint16 CheckSum() {return (Row5>>16) & 0x0ffff;} inline uint16 UrgentPtr(){return (Row5) & 0x0ffff;} inline uint32 Options() {return (Row6>>8) & 0x0ffffff;}};
(side note:
RFC 752 happens to define bit ordering in such a way to make this layout easy to compare to Figure 3).
BTW, for the record, I will re-iterate that a working TcpHeaderMethod struct can be more easily incorporated into portable code.
On another topic, it's insane to memcpy to either of these structs in order to interpret raw data... just assign a pointer to one of these structures to the location you need to interpret:
TcpHeaderMethod *Header = (TcpHeaderMethod*)buffer;if (Header->SYN()>0) blah();// instead of:// TcpHeaderMethod Header;// memcpy(buffer, Header, sizeof(TcpHeaderMethod));// if (Header.SYN()>0) blah();
[edited by - yy2bggggs on March 13, 2003 9:42:39 PM][edited by - yy2bggggs on March 14, 2003 9:40:16 AM]