Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is htonl(x) != ntohl(x) ? (Or when is converting to and from Network Byte Order not equivalent on the same machine?)

In regards to htonl and ntohl. When would either of these two lines of code evaluate to false.

 htonl(x) == ntohl(x);

 htonl(ntohl(x)) == htonl(htonl(x));

In other words, when are these two operations not equivalent on the same machine? The only scenario I can think of is a machine that does not work on 2's complement for representing integers.

Is the reason largely historical, for coding clarity, or for something else?

Do any modern architectures or environments exists today where these converting to and from network byte order on the same machine is not the same code in either direction?

like image 385
selbie Avatar asked Jul 23 '12 17:07

selbie


1 Answers

I wrote a TCP/IP stack for a UNIVAC 1100 series mainframe many years ago. This was a 36 bit, word addressable computer architecture with 1's complement arithmetic.

When this machine did communications I/O, 8 bit bytes arriving from the outside world would get put into the lower 8 bits of each 9 bit quarter-word. So on this system, ntohl() would squeeze 8 bits in each quarter word down into the lower 32 bits of the word (with the top 4 bits zero) so you could do arithmetic on it.

Likewise, htonl() would take the lower 32 bits in a word and undo this operation to put each 8 bit quantity into the lower 8 bits of each 9 bit quarter word.

So to answer the original question, the ntohl() and htonl() operations on this computer architecture were very different from each other.

For example:

COMP*                                 . COMPRESS A WORD
          LSSL      A0,36             . CLEAR OUT A0
          LSSL      A1,1              . THROW AWAY TOP BIT
          LDSL      A0,8              . GET 8 GOOD ONE'S
          LSSL      A1,1              .
          LDSL      A0,8              .
          LSSL      A1,1              .
          LDSL      A0,8              .
          LSSL      A1,1              .
          LDSL      A0,8              .
          J         0,X9              .
.
DCOMP*                                . DECOMPRESS A WORD
          LSSL      A0,36             . CLEAR A0
          LSSL      A1,4              . THROW OUT NOISE
          LDSL      A0,8              . MOVE 8 GOOD BITS
          LSSL      A0,1              . ADD 1 NOISE BIT
          LDSL      A0,8              . MOVE 8 GOOD BITS
          LSSL      A0,1              . ADD 1 NOISE BIT
          LDSL      A0,8              . MOVE 8 GOOD BITS
          LSSL      A0,1              . ADD 1 NOISE BIT
          LDSL      A0,8              . MOVE 8 GOOD BITS
          J         0,X9              .

COMP is the equivalent to ntohl() and DCOMP to htonl(). For those not familiar with UNIVAC 1100 assembly code :-) LSSL is "Left Single Shift Logical" a registers by a number of positions. LDSL is "Left Double Shift Logical" a pair of registers by the specified count. So LDSL A0,8 shifts the concatenated A0, A1 registers left 8 bits, shifting the high 8 bits of A1 into the lower 8 bits of A0.

This code was written in 1981 for a UNIVAC 1108. Some years later, when we had an 1100/90 and it grew a C compiler, I started a port of the BSD NET/2 TCP/IP implementation and implemented ntohl() and htonl() in a similar way. Sadly, I never completed that work..

If you wonder why some of the Internet RFCs use the term "octet", its because some computers in the day (like PDP-10s, Univacs, etc.) had "bytes" that were not 8 bits. An "octet" was defined specifically to be an 8 bit byte.

like image 50
Louis Mamakos Avatar answered Oct 02 '22 18:10

Louis Mamakos