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_in
with 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;
}
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.
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.
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.
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.
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.
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.
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.
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
.
"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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With