Address Conversion — Text to Binary and Back
People write 203.0.113.10. Sockets want four raw bytes inside an address structure. Config files, logs and admin screens live in the first world; sendto lives in the second. A small set of functions crosses between them, and the older ones in that set are a classic source of bugs.
The rule
Text in, binary out: pton parses, ntop prints, getaddrinfo resolves names.
The letters decode the names: p is for presentation, the text people read, and n is for network, the binary form sockets use.
- inet_pton turns text into binary. It returns 1 on success, 0 if the text is not a valid address for the chosen family, and −1 if the family itself is not supported.
- inet_ntop turns binary back into text, for logs, admin screens and error messages.
- getaddrinfo takes a host name (or an address written as text) and a port, does any DNS lookup needed, and returns a list of ready-made addresses with every structure already filled in.
struct addrinfo hints = {0}, *res, *p;
hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6, whichever exist */
hints.ai_socktype = SOCK_DGRAM; /* UDP */
if (getaddrinfo("mumbai.manja-arena.example", "7777", &hints, &res) == 0) {
for (p = res; p != NULL; p = p->ai_next) {
/* try socket(p->ai_family, ...) and sendto(..., p->ai_addr, p->ai_addrlen) */
}
freeaddrinfo(res); /* the list was allocated for you */
}Address structures come in different sizes: sockaddr_in for IPv4, sockaddr_in6 for IPv6, and sockaddr_storage, which is big enough for either. That last one is the right type for "whoever just sent me a datagram", when you cannot know in advance which kind it will be.
Avoid the older functions. inet_addr and inet_ntoa handle IPv4 only. inet_addr returns the same value for an error as for the perfectly valid address 255.255.255.255, and inet_ntoa returns a pointer to a static buffer that its next call overwrites.
The shortcut
To turn IPv4 text into bytes by hand, convert each of the four numbers into one byte, in order. The first number goes first on the wire.
198
198 = 12 × 16 + 6, so it is hex
C6.
Going the other way, inet_ntop reads the bytes in the same order, so C6 33 64 04 prints as 198.51.100.4. If a log ever shows 4.100.51.198 instead, something reversed the bytes along the way: a byte-order bug, which is the subject of the next lesson.
Drills
Answer fast — trust the rule.
In inet_pton, what do the "p" and the "n" stand for?
Which four bytes does inet_pton produce for 203.0.113.10?
inet_pton(AF_INET, "203.0.113.300", &addr) returns 0. What does that mean?
Why pass AF_UNSPEC to getaddrinfo when looking up the match server?
Why does printf("%s -> %s", inet_ntoa(a), inet_ntoa(b)) print the same address twice?
Remember
- Text in, binary out: pton parses, ntop prints, getaddrinfo resolves names into a list of addresses.
- Four numbers become four bytes, first number first.
- Trap: the old
inet_addrandinet_ntoa, which are IPv4-only and full of surprises.
