getaddrinfo

From Wikipedia, the free encyclopedia
Jump to: navigation, search

The getaddrinfo() and getnameinfo() functions are part of the POSIX standard application programming interface (API) for converting domain name system (DNS) hostnames and IP addresses between their human-readable text representations and structured binary formats for the operating system's networking API.

getaddrinfo() and getnameinfo() are inverse functions of each other.

This set of functions is fully network protocol agnostic and supports both IPv4 and IPv6. It is the recommended interface for name resolution in building protocol independent applications and for transitioning legacy IPv4 code to the IPv6 Internet.

Internally, the function needs to perform some form of DNS lookup by calling other, lower level function like gethostbyname(). The file resolv.conf determines the behaviour of this lookup and can be modified by the system user.

struct addrinfo[edit]

The C data structure used to represent addresses and hostnames within the networking API is the following:

struct addrinfo {
    int     ai_flags;
    int     ai_family;
    int     ai_socktype;
    int     ai_protocol;
    size_t  ai_addrlen;
    struct  sockaddr *ai_addr;
    char    *ai_canonname;     /* canonical name */
    struct  addrinfo *ai_next; /* this struct can form a linked list */
};

In recent operating systems the type of ai_addrlen has been changed from size_t to socklen_t. Most socket functions, such as accept and getpeername, require a socklen_t* parameter and programmers often pass the address to the ai_addrlen element of the addrinfo structure. If the types are incompatible, e.g., on a big-endian 64-bit Solaris 9 system where size_t is 8 bytes and socklen_t is 4 bytes, then run-time errors may result.

It is interesting to note that the structure contains an ai_family and a sockaddr structure with its own sa_family field. These are set to the same value when the structure is created with the getaddrinfo() function in some implementations.

getaddrinfo()[edit]

getaddrinfo() converts human-readable text strings representing hostnames or IP addresses into a dynamically allocated linked list of struct addrinfo structures. The function prototypes for these functions are specified as follows:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
 
int getaddrinfo(const char *hostname,
                const char *service,
                const struct addrinfo *hints,
                struct addrinfo **res);
  • hostname can be either a domain name like "nice.com", an address string like "127.0.0.1" or NULL in which case an address of either 0.0.0.0 or 127.0.0.1 is assigned depending on the hints flags.
  • service can be a port number passed as string like "80" or a service name like "echo" (which should map to port 7 by default). In the latter case, gethostbyname() is used to query /etc/services.
  • hints can be either NULL or an addrinfo structure with the type of service we are interested (ex. a socket can be available for both TCP and UDP so we can assert our interest in the former only)
  • res is a pointer that will point to a new addrinfo structure with the information requested upon successful completion of the function.

The function returns 0 upon success and negative if it fails along the way.[1]

Although implementations vary among platforms, the function will first try and get a port number usually by branching on service. If the string value is a number, it will convert it to an integer using htons(). If it is a service name like www it will lookup the service by calling getservbyname(), using the protocol derived from hints->ai_socktype as the second parameter to that function. Then, If a hostname is given (not NULL), It will also call gethostbyname() to do a name-to-IP resolution otherwise it will assign an address of 0.0.0.0 if the hints->ai_flags is set to AI_PASSIVE and 127.0.0.1 otherwise. It will then call malloc_ai in one of these conditions and pass the port retrieved at the beginning to allocate an addrinfo structure filled with the appropriate sockaddr_in. It will finally dereference the **res parameter to make it point to a newly allocated addrinfo structure.[2] In some implementations (like the Unix version for Mac OS), the hints->ai_protocol will override the hints->ai_socktype value while in others it is the opposite, so both need to be defined with equivalent values for the code to be cross platform.

getnameinfo()[edit]

getnameinfo() converts the internal binary representation of an IP address in the form of a struct sockaddr pointer into text strings consisting of the hostname or, if the address cannot be resolved into a name, a textual IP address representation, as well as the service port name or number. The function prototype is specified as follows:

#include <sys/socket.h>
#include <netdb.h>
 
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                char *host, size_t hostlen,
                char *serv, size_t servlen,
                int flags);

freeaddrinfo()[edit]

This function will free the memory allocated by the getaddrinfo() function. As the result of the latter is a link list of addrinfo structures, freeaddrinfo() will loop through the list and free each one it turn

#include <sys/socket.h>
#include <netdb.h>
 
void freeaddrinfo(struct addrinfo *ai);
  • ai is the head of the addinfo list

Example[edit]

The following example uses getaddrinfo() to resolve the domain name www.example.com into its list of addresses and then calls getnameinfo() on each result to return the canonical name for the address. In general, this will produce the original hostname, unless the particular address has multiple names, in which case the canonical name is returned. In this example, the domain name will be printed three times, once for each of the three results obtained.

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
 
#ifndef   NI_MAXHOST
#define   NI_MAXHOST 1025
#endif
 
int main(void)
{
    struct addrinfo *result;
    struct addrinfo *res;
    int error;
 
    /* resolve the domain name into a list of addresses */
    error = getaddrinfo("www.example.com", NULL, NULL, &result);
    if (error != 0)
    {   
        if (error == EAI_SYSTEM)
        {
            perror("getaddrinfo");
        }
        else
        {
            fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
        }   
        exit(EXIT_FAILURE);
    }   
 
    /* loop over all returned results and do inverse lookup */
    for (res = result; res != NULL; res = res->ai_next)
    {   
        char hostname[NI_MAXHOST] = "";
 
        error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0); 
        if (error != 0)
        {
            fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
            continue;
        }
        if (*hostname != '\0')
            printf("hostname: %s\n", hostname);
    }   
 
    freeaddrinfo(result);
    return 0;
}

See also[edit]

External links[edit]

  • RFC 3493, Basic Socket Interface Extensions for IPv6

References[edit]

  1. ^ Stevens R., Fenner, Rudoff [2003] UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking API. Publisher: Addison-Wesley Professional. Pub. Date: November 14, 2003 p. 256
  2. ^ Hajimu UMEMOTO [2000] getaddrinfo.c Accessed from: http://www.opensource.apple.com/source/passwordserver_sasl/passwordserver_sasl-14/cyrus_sasl/lib/getaddrinfo.c