Using getaddrinfo()

Although we've been using getaddrinfo() in previous chapters, we'll discuss it in more detail here.

The declaration for getaddrinfo() is shown in the following code:

int getaddrinfo(const char *node,
const char *service,
const struct addrinfo *hints,
struct addrinfo **res);

The preceding code snippet is explained as follows:

struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};

You should not assume that the fields are stored in the order listed in the previous code, or that additional fields aren't present. There is some variation between operating systems.

The call to getaddrinfo() looks at only four fields in *hints. The rest of the structure should be zeroed-out. The relevant fields are ai_family, ai_socktype, ai_protocol, and ai_flags:

Common flags you may use for the ai_flags field are:

All other fields in hints should be set to 0. You can also pass in 0 for the hints argument, but different operating systems implement different defaults in that case.

The final parameter to getaddrinfo(), res, is a pointer to a pointer to struct addrinfo and returns the address(es) found by getaddrinfo().

If the call to getaddrinfo() succeeds, then its return value is 0. In this case, you should call freeaddrinfo() on *res when you've finished using the address. Here is an example of using getaddrinfo() to find the address(es) for example.com:

struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_ALL;
struct addrinfo *peer_address;
if (getaddrinfo("example.com", 0, &hints, &peer_address)) {
fprintf(stderr, "getaddrinfo() failed. (%d)\n", GETSOCKETERRNO());
return 1;
}

Note that we first zero out hints using a call to memset(). We then set the AI_ALL flag, which specifies that we want both IPv4 and IPv6 addresses returned. This even returns addresses that we don't have a network adapter for. If you only want addresses that your machine can practically connect to, then use AI_ALL | AI_ADDRCONFIG for the ai_flags field. We can leave the other fields of hints as their defaults.

We then declare a pointer to hold the return address list: struct addrinfo *peer_address.

If the call to getaddrinfo() succeeds, then peer_address holds the first address result. The next result, if any, is in peer_address->ai_next.

We can loop through all the returned addresses with the following code:

struct addrinfo *address = peer_address;
do {
/* Work with address... */
} while ((address = address->ai_next));

When we've finished using peer_address, we should free it with the following code:

freeaddrinfo(peer_address);

Now that we can convert a text address or name into an addrinfo structure, it is useful to see how to convert the addrinfo structure back into a text format. Let's look at that now.