2. The server receives the request, interprets it, and manipulates its resources in
11.4.7 Host and Service Conversion
Linux provides some powerful functions, called getaddrinfo and getnameinf o, for converting back and forth between'binary socket address structures and the string representations of, hostnames, host addresses, service names, and port numbers. When used in conjunction with the sockets interface, they allow us to write network programs that are independent of any particular version of the ãIP protocol.
The getaddrinfo Function '
The getaddrinfo func_tion converts string representa_tions of hostnallles, host addresses, service .names, and.port numbJ'rs into socket iiddress stru,tàr~s.,lt is the modern replacement for the. obsolete gethostbyname and getservbyname functions. Unlil>l: "these "functions, it is reentrant (see Section 12.7.2) and works with any protocol!
#include <sys/types.h>
#,include <sys/socket.h>
. #include <netdb .'h>
..
int getaddrinfo(const char *host, const ch'ar'*service, const stDuct addrinfo *hints,
struct addrinfo **result);
Returns: 0 if OK, nonzero error code o'n error yoid freeaddrinfo(struct ~ddrinfo *result);
Returns: nothing const char 'J'gai._sitrel'ror (int errcode);
Returns: error message
938 Chapter 11 Network Programming
Figure 11.15 addrinf o structs
' r
Data structure returned by getaddrinfo.
[ result
r . . ... .,
]
,, J
.. ã~.~- ...,,..
' Socket address stru cts .,. ... ~~ ~ ai_canonname
J "•ã" ' ~]
p.i_addr L~'""u ,.~
c .f1 ai_next ., ' ' '
NULL
J ~
.1 l
ai_addr
1 '
fl ai_next <Jo l
,
NULL ._., '
J• ~ ' ~
ai_addr 1ô, ~ ""\<' •
NULL
Given host apd.servic;e (the, two components of a socket adc,lress/, getaddrinfo returns a result that points to a linked list of addrinfo structures, each of which points to a socket address structure that corresponds to host and service (Figure 11.15).
After a client calls getaddrinfo, it walks this list, trying each socket address in turn ãuntil the calls to' socket and connect succeed and the connection is established. Similarly,- a server tries each socket atldtess on tlre list until the calls to sos;ltet and bind succeed and the descriptor is bound to•a valid socket address.
To 'avoidã memory leaks, the application must eventually free the list b}'<calling freeaddrinfo. If getaddrinfo returns a nonzero error code, tlie application can call gai_strerror to convert the code to a message string.
The host argument to getaddrinfo Can be either a dOlpain name or a numeric address (e.g., a dotted-decimal IP address). The service argument can be either a service name (e.g., http) or a decimal port number. If we are not interested in converting the ~ostname to an address, we can set host to NULL. The same hol'ds for service. However, at leaslãone of them must be specified.
The optional hints argument is an addrinfo .structure (Figure 11.16) that provides finer control over the list of socket addresses that getaddrinfo re- turns. When passed as a hints argqment, only the ai_family, ai_socktype, ai_protocol, and ai_flags fields can be set. 'D!e other fields must be set to zero (or NULL). In practice, we use memset to zero the entire structure and then set a few selected fields:
• By default, getaddrinfo can return both IPv4 and I~6 ãsocket addresses.
Setting ai~f ainily to AF _INET restricts the list to IPv4 addresses. Setting it to AF _INET6 restricts the list to IPv6 addresses.
.section. 11.4 The Sockets Interface 939
--~"'---'---"'-' -'-' - - - code/netp/netpfragments.c
"
struct addrihfo { int
fut
int int char size_t
str1;.ct sockaddr
ai~flags;
ai~family;
ai_sock.type;
ai_protocol;
*ai_Canonllame;
ai_ttdd~len;
*ai:_addt!
struct addrinfo *ai_next;
}; <l <
I• Hints argument' 'flags >'/
/* First arg td"I socket flln'ction */
'/* second arg to sdcket function */
/* Third' arg to socket fundtion */
'/• Canorri'cal hbstname */
/* Size of ai_addr struct */
/* Ptr to socket~ adqress' Structure •/
/* Ptr to next item''in 'liriked list */
' "'
- - - code/netp/netpfragments.c Figure 11.16 The addrinfo structure used by getaddrinfo.
,,,
"
'"
.J 1.'1
• By default, for each unique address associated with host, the getaddrinfo function can return:up to three addrinfo structures, each with a different aL socktype field: one for connections, one for datagrams (not covered), and one for raw sockets (not covered). Setting ai_socktype to SOCK_:S'FREAM restricts ,th,<; list to at most one 11\ldrinfo structure for_,ei1;ch unique address, one whose socket address can be used as !he end point of a connection. This is the desired biohavior for ~of our example pr,ograms.
• The ai_flags field is a;bit mask that further modifies the default behavior.
"
You create it by oRing combinations of various values. Here11re some that we find useful:
. Al_ADD~CONFIG .. This flag is recommend~d if\ou are using conrn:,c- tions;r~4]. I~ ~sk~ g~taddr~nfo to,return I,Pv4 a.cJd,r~s~es Ol).(Y if t,he , ... local,hosi is con~gure<j for 1Pv4. Similarly ~or 1Pv6. ' "
,~l_CAN,ONNAME. By p~faul\, th~,ai_,canonname field is N.ULL. If this flag is set, it instructs getaddrinfo to point the ai_e<anonname field in
' { f I ) f " '
the first addr~nfo str,u,rtwe,i? ihe list to the caponical ( o\ficia) qame of host (see Figure 11.15).
• ' .< • ~ r )' ! ,
AI_NU:r.:rnRJCSERV. By defa':'lt, the servic<; argument c.;m.be a s9rvice i;iame or a port nuII\\Jer. 'J)n,s flag forces the, service argument to be a port number.
Al_PASSIVE. By default, getaddrinfo returns socket addresses that can be used by clients as active sockets.in calls to connes::t. This flag instructs, it to return socket address~srthat can be used by servers as listening sockets. In this case, the host argument should be NULL.
The address field in the resulting socket address structure(s) will be the wildcard address, which tells the kernei'that this serv~r will accept req'u~sis to'iny of the'JVaddresses for !his host. This is ilie desired 'behavior for all of our example servers.
I '
~
I j ,,
940 Chapter 11 Network Programming
When getaddrinfo creates an addrinfo structure in the output list, it fills in each field except for ai_flags. The ai_addr field points to a socket a~dress structure, the ai_addrlen field.gives the size of this socket address structure, and the ai_next field points to the next addrinf o structure in the list. The other fields describe various attributes of the socket address. <J
One of the elegant aspects of getaddrinfo is that the fields in an addrinfo structure are o'paque, in the sense that th~y can be passed directly to the functions in the sockets interface without any further manipulation by the application code.
For example, ai_family, ai_socktype, and airprotocol can be passed directly to socket. Similarly, ai_addr ai;id ai_addrlen can be pas~ed directly to connect and bind. This powerful property allows us to write clients and servers that are independent of any particular version of the IP protocol.
The getnameinfo Function
The getnameinfo function is the inverse of getaddrinfo. It converts a socket ad- dress structure to the corresponding host and service name strings. It is the modern replacement for the obsolete gethostbyaddr and getservbyport functions, and unlike those functions, it is reentrant and protocol-independent.
#incl~de <sys/socket.h>
.#inc~ude <ne~db.h>
"
int getnameinf6'(tonst struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen,
char *servic'~, size_t servlen, int flags);
Returns: 0 if dK, nonzeto error code on error
•,
The sa argument points to a socket addres~ structure of size si'len bytes, host to a buffer of size hostlen bytes, and service to a buffer of size servlen bytes.
The getnameinfo function converts the socket address structun: sa to the corre- sponding host and service name strings and copies ~hem tp ihe J:tost,and service buffers. If g:,-tnameinf a returns a nonzero error code, tne application can convert it to a string by calling gai_strerr6r.
if we don't want the hostname, we dm se\ho'st to N,ULL and hostlen to zero.
The same holds for the service fields. However, one or the other must be set.
The flags argum'ent is a bit mask that modifies the default behavior. You create it by oRing combi~ations of various values. Here are a couple of useful
ones: ;
NI_NUMERICHOST. By default, getnameinfo tries to return a domain name in host. Setting this'flfig will causeit to return a numeric address string instead.
NI_NU]'\1ERICSERV. By default,,getn"!.rneinfo will look in /etc/services 'anif if possible, return a service na,ri\e instead of a port number. Setting l:liis flag forbes it to skip the lo,okup a~d simply return the port number.
Section 11.4• The Socket~ Interface !14l
-~""---'---'---'--'---'-'----'-'~' c ---'--"'-'~ code/netp/hostinfo.c
#iriClude 11csa'pp.h11 '''
l2j ''fl
,)
4•
5 6 7 8
iJ.].t nUlin (irit arg!c, char **argv )~
{' "
struct addrinfo *P• *listp; hinis;
~h'ar tiuf[MAXLINE];
int re, flags;
' I
9 if (argc != 2) {
10 11
fprintf (stderr, 11usage: %s <domain name>\n", o;..argv [OJ);
exit(O);
12 }
13 14 15 16 17 18
19J "f(
20 21 22 23 24 25
26' 2i
28 29 30 31 32
I* Get a list of addrinfo records */
memset (&hints. 0, sizeof (struct ~dcit':i'.nfo)); '• ' -ã
1( hints. ai_family = AF _!NET;. r.l*-"'IPv4. only */
f<"C hint's-. ai_socktype = SOCK_STREAM; f,6• Connections only */
i f ((re.= getad11rinfo(argv[1], NULL,~&hints, &l'istp)) r•!= 0) '{
fpr,j_ntf(stderr, "getaddrinfoã error.: %s\n 11, gai~strerror(rc));
exit(1)i l:<
}
I* Walk the list and display each IP address */
flag~ = NI_NUMERJCHOST;:Jt~ •. D.isplay address string•.instea'.cf of domain name •/
for (p = listp; p; p = p->ai_next) {
t ãaetnatn~info(p->ai_!i'ddr, p->ai_addrl9n, buf, MAXLINE: NULL, o, flags);
piintf(11%s\D.11, buf)j .i r
1
}
I• Clean up •I Freeaddrinfo(listp)j
II
~ã >'
.l
33 exit(O);
34 }
- - - code/netp!hostinfo.c 1
Figure 11.17 HOST! N FO displays the mapping of a domain name to it; ass.:i-ciated IP addresses.
Figure H.l 7:shows a simple program, called HOSTINFO/,tliat uses getaddri-nfo and getnameinfoãtO'display the mapping.of a doJilainãname to its•associated IP addresses. It is.similar.to the NSLOOKUP. program from Sectio'.rull.3.2-
, 'First, we initialize. the.hints structure so tlial.getaddrihfo returns the ad- dresses we want. In this .case, we are looking for 3Q-bit ,Jp addresses (lineã 16)
• ijl1 I
942 Chapter 11 Network Programming
that can be used as end points of connections (line 17). Since we are only asking getaddrinfo to convert domain names, we call it with a N,ULJ;, service argument.
After the call to getaddrinfo, we walk the list of addrinfo structures, using getnameinfo to convert each socket address to a dotted-decimal aqdress string.
After walking the list, we are careful to free it by calling freeaddrinfo (although for this simple program it is not strictly necessary).
When we run HOSTINFO, we see that twitter. com maps to four IP addresses, which is what we saw using NSLOOKUP in Section 11.3.2.
linux> ./hostinfo twitter.com 199.16.156.102
199.16.156:230 199.16.156.6 199.16.156.70
fiiilti~e:.ei:2mem~mttftr;;tii8i:2m:rnã .i~;:r~:L:Xm?W~:l
The geti,ddrinfo and getnalneinfo functions subsume the functionality of inet_
pton and inet_ntop, respectively, and they provide a higher-level of abstraction that is independent of any.particular address format. To convince yourself how handy this is, write a version of HOSTINFO (Figure 11.17) that ns~s inet_ntop in- stead of getnameinfo to convert each socket address to a dotted-decimal address string.
.,.