Updated: April 19, 2023 |
Get socket address information
#include <sys/socket.h> #include <netdb.h> int getaddrinfo( const char * nodename, const char * servname, const struct addrinfo * hints, struct addrinfo ** res );
The getaddrinfo() function performs the functionality of gethostbyname() and getservbyname() but in a more sophisticated manner.
The nodename and servname arguments are either pointers to null-terminated strings or NULL. One or both of these two arguments must be a non-NULL pointer. Normally, a client scenario specifies both nodename and servname.
On success, the getaddrinfo() function stores, in the location pointed to by res, a pointer to a linked list of one or more addrinfo structures. You can process each addrinfo structure in this list by following the ai_next pointer until reaching a NULL pointer. Each addrinfo structure contains the corresponding ai_family, ai_socktype, and ai_protocol arguments for a call to the socket() function. The ai_addr argument of the addrinfo structure points to a filled-in socket address structure with a length specified by the ai_addrlen argument.
Using the hints argument
You can optionally pass an addrinfo structure, pointed to by the hints argument, that provides hints concerning the type of socket that your application supports.
In this structure, all members—except ai_flags, ai_family, ai_socktype, and ai_protocol—must be zero or a NULL pointer. The addrinfo structure of the hints argument can accept various types of sockets:
To accept: | Set: | To: |
---|---|---|
Any protocol family | ai_family | PF_UNSPEC |
Any socket type | ai_socktype | 0 |
Any protocol | ai_protocol | 0 |
All of the above (as well as setting ai_flags to 0) | hints | NULL |
The hints argument defaults to all possibilities, but you can also use it to limit choices:
Using the ai_flags argument in the hints structure
You can set the ai_flags argument to further configure the hints structure. Settings for ai_flags include:
If you don't set the AI_PASSIVE flag, you can use the returned addrinfo structure in a call to:
In this case, if the nodename argument is a NULL pointer, then the IP address portion of the socket address structure ai_addr is set to the loopback address.
Pitfalls
The arguments to getaddrinfo() must be sufficiently consistent and unambiguous or this function will return an error. Here are some problems you may encounter:
Use freeaddrinfo() to free the addrinfo structures, and gai_strerror() to decipher error codes.
Zero for success, or nonzero if an error occurs.
To get an explanation of any error code, use gai_strerror().
The following code tries to connect to www.kame.net service HTTP using a stream socket. It loops through all the addresses available, regardless of the address family. If the destination resolves to an IPv4 address, it uses a AF_INET socket. Similarly, it uses an AF_INET6 socket if it resolves to IPv6. Note that there aren't any hardcoded references to any particular address family; the code works even if getaddrinfo() returns addresses that aren't IPv4/v6.
struct addrinfo hints, *res, *res0; int error; int s; const char *cause = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo("www.kame.net", "http", &hints, &res0); if (error) { err1(1, "%s", gai_strerror(error)); /*NOTREACHED*/ } s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s); s = -1; continue; } break; /* okay we got one */ } if (s < 0) { err(1, cause); /*NOTREACHED*/ } freeaddrinfo(res0);
The following example tries to open a wildcard-listening socket onto the HTTP service for all of the available address families:
struct addrinfo hints, *res, *res0; int error; int s[MAXSOCK]; int nsock; const char *cause = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; error = getaddrinfo(NULL, "http", &hints, &res0); if (error) { err1(1, "%s", gai_strerror(error)); /*NOTREACHED*/ } nsock = 0; for (res = res0; res && nsock < MAXSOCK; res = res->ai_next) { s[nsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s[nsock] < 0) { cause = "socket"; continue; } if (connect(s[nsock], res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s[nsock]); continue; } nsock++; } if (nsock == 0) { err(1, cause); /*NOTREACHED*/ } freeaddrinfo(res0);
Safety: | |
---|---|
Cancellation point | Yes |
Interrupt handler | No |
Signal handler | No |
Thread | Yes |