Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding htonl() and ntohl()

Tags:

I am trying to use unix sockets to test sending some udp packets to localhost.

It is my understanding that when setting ip address and port in order to send packets, I would fill my sockaddr_inwith values converted to network-byte order. I am on OSX and I'm astonished that this

printf("ntohl: %d\n", ntohl(4711));
printf("htonl: %d\n", htonl(4711));
printf("plain: %d\n", 4711);

Prints

ntohl: 1729232896
htonl: 1729232896
plain: 4711

So neither function actually returns the plain value. I would have expected to see either the results differ, as x86 is little-endian (afaik), or be identical and the same as the actual number 4711. Clearly I do not understand what htonl and ntohl and their variants do. What am I missing?

The relevant code is this:

int main(int argc, char *argv[])
{
   if (argc != 4)
   {
      fprintf(stderr, "%s\n", HELP);
      exit(-1);
   }

   in_addr_t rec_addr = inet_addr(argv[1]); // first arg is '127.0.0.1'
   in_port_t rec_port = atoi(argv[2]);      // second arg is port number
   printf("Address is %s\nPort is %d\n", argv[1], rec_port);
   char* inpath = argv[3];

   char* file_buf;
   unsigned long file_size = readFile(inpath, &file_buf); // I am trying to send a file
   if (file_size > 0)
   {
      struct sockaddr_in dest;
      dest.sin_family      = AF_INET;
      dest.sin_addr.s_addr = rec_addr; // here I would use htons
      dest.sin_port        = rec_port;
      printf("ntohs: %d\n", ntohl(4711));
      printf("htons: %d\n", htonl(4711));
      printf("plain: %d\n", 4711);
      int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
      if (socket_fd != -1)
      {
         int error;
         error = sendto(socket_fd, file_buf, file_size + 1, 0, (struct sockaddr*)&dest, sizeof(dest));
         if (error == -1)
            fprintf(stderr, "%s\n", strerror(errno));
         else printf("Sent %d bytes.\n", error);
      }
   }

   free(file_buf);
   return 0;
}
like image 712
oarfish Avatar asked Apr 28 '16 20:04

oarfish


People also ask

What are Htonl and Ntohl?

The htonl() function converts the unsigned integer hostlong from host byte order to network byte order. The htons() function converts the unsigned short integer hostshort from host byte order to network byte order. The ntohl() function converts the unsigned integer netlong from network byte order to host byte order.

Are Htonl and Ntohl the same?

I hope that no such architecture exists, but it could implement the sockets API thanks to the fact that htonl and ntohl are separate functions.

What is the use of Htonl?

The htonl() function translates a long integer from host byte order to network byte order. The unsigned long integer to be put into network byte order. Is typed to the unsigned long integer to be put into network byte order.

What is Ntohl?

The ntohl() function translates a long integer from network byte order to host byte order. Parameter Description a. The unsigned long integer to be put into host byte order. in_addr_t netlong. Is typed to the unsigned long integer to be put into host byte order.

What are htons and ntohs and how do they work?

As others have mentioned, both htons and ntohs reverse the byte order on a little-endian machine, and are no-ops on big-endian machines. What wasn't mentioned is that these functions take a 16-bit value and return a 16-bit value.

Is htonl 16 bit or 32 bit?

A short is typically 16-bit while on older systems long was 32-bit. In your code, you don't need to call htonl on rec_addr, because that value was returned by inet_addr, and that function returns the address in network byte order. You do however need to call htons on rec_port.

Is there a htonll () function for 64 bit INTs?

Note that the types involved are 32-bit (4 byte, probably int) and 16-bit (2 byte, very likely short ) numbers. 64-bit machines might have a htonll () for 64-bit ints, but I've not seen it. You'll just have to write your own.


2 Answers

As others have mentioned, both htons and ntohs reverse the byte order on a little-endian machine, and are no-ops on big-endian machines.

What wasn't mentioned is that these functions take a 16-bit value and return a 16-bit value. If you want to convert 32-bit values, you want to use htonl and ntohl instead.

The names of these functions come from the traditional sizes of certain datatypes. The s stands for short while the l stands for long. A short is typically 16-bit while on older systems long was 32-bit.

In your code, you don't need to call htonl on rec_addr, because that value was returned by inet_addr, and that function returns the address in network byte order.

You do however need to call htons on rec_port.

like image 82
dbush Avatar answered Oct 14 '22 19:10

dbush


"Network byte order" always means big endian.

"Host byte order" depends on architecture of host. Depending on CPU, host byte order may be little endian, big endian or something else. (g)libc adapts to host architecture.

Because Intel architecture is little endian, this means that both functions are doing the same: reversing byte order.

like image 25
gudok Avatar answered Oct 14 '22 19:10

gudok