mount_setattr.2: Further tweaks after feedback from Christian Brauner
[man-pages.git] / man3 / getaddrinfo_a.3
blob7973b2640c44a4c0061d0a02c260b7b55f702bc9
1 .\" Copyright (c) 2009 Petr Baudis <pasky@suse.cz>
2 .\" and clean-ups and additions (C) Copyright 2010 Michael Kerrisk
3 .\"                                 <mtk.manpages@gmail.com>
4 .\"
5 .\" %%%LICENSE_START(VERBATIM)
6 .\" Permission is granted to make and distribute verbatim copies of this
7 .\" manual provided the copyright notice and this permission notice are
8 .\" preserved on all copies.
9 .\"
10 .\" Permission is granted to copy and distribute modified versions of this
11 .\" manual under the conditions for verbatim copying, provided that the
12 .\" entire resulting derived work is distributed under the terms of a
13 .\" permission notice identical to this one.
14 .\"
15 .\" Since the Linux kernel and libraries are constantly changing, this
16 .\" manual page may be incorrect or out-of-date.  The author(s) assume no
17 .\" responsibility for errors or omissions, or for damages resulting from
18 .\" the use of the information contained herein.  The author(s) may not
19 .\" have taken the same level of care in the production of this manual,
20 .\" which is licensed free of charge, as they might when working
21 .\" professionally.
22 .\"
23 .\" Formatted or processed versions of this manual, if unaccompanied by
24 .\" the source, must acknowledge the copyright and authors of this work.
25 .\" %%%LICENSE_END
26 .\"
27 .\" References: http://people.redhat.com/drepper/asynchnl.pdf,
28 .\"     http://www.imperialviolet.org/2005/06/01/asynchronous-dns-lookups-with-glibc.html
29 .\"
30 .TH GETADDRINFO_A 3 2021-03-22 "GNU" "Linux Programmer's Manual"
31 .SH NAME
32 getaddrinfo_a, gai_suspend, gai_error, gai_cancel \- asynchronous
33 network address and service translation
34 .SH SYNOPSIS
35 .nf
36 .BR "#define _GNU_SOURCE" "         /* See feature_test_macros(7) */"
37 .B #include <netdb.h>
38 .PP
39 .BI "int getaddrinfo_a(int " mode ", struct gaicb *" list [restrict],
40 .BI "                  int " nitems ", struct sigevent *restrict " sevp );
41 .BI "int gai_suspend(const struct gaicb *const " list "[], int " nitems ,
42 .BI "                  const struct timespec *" timeout );
43 .PP
44 .BI "int gai_error(struct gaicb *" req );
45 .BI "int gai_cancel(struct gaicb *" req );
46 .PP
47 Link with \fI\-lanl\fP.
48 .fi
49 .SH DESCRIPTION
50 The
51 .BR getaddrinfo_a ()
52 function performs the same task as
53 .BR getaddrinfo (3),
54 but allows multiple name look-ups to be performed asynchronously,
55 with optional notification on completion of look-up operations.
56 .PP
57 The
58 .I mode
59 argument has one of the following values:
60 .TP
61 .B GAI_WAIT
62 Perform the look-ups synchronously.
63 The call blocks until the look-ups have completed.
64 .TP
65 .B GAI_NOWAIT
66 Perform the look-ups asynchronously.
67 The call returns immediately,
68 and the requests are resolved in the background.
69 See the discussion of the
70 .I sevp
71 argument below.
72 .PP
73 The array
74 .I list
75 specifies the look-up requests to process.
76 The
77 .I nitems
78 argument specifies the number of elements in
79 .IR list .
80 The requested look-up operations are started in parallel.
81 NULL elements in
82 .I list
83 are ignored.
84 Each request is described by a
85 .I gaicb
86 structure, defined as follows:
87 .PP
88 .in +4n
89 .EX
90 struct gaicb {
91     const char            *ar_name;
92     const char            *ar_service;
93     const struct addrinfo *ar_request;
94     struct addrinfo       *ar_result;
96 .EE
97 .in
98 .PP
99 The elements of this structure correspond to the arguments of
100 .BR getaddrinfo (3).
101 Thus,
102 .I ar_name
103 corresponds to the
104 .I node
105 argument and
106 .I ar_service
107 to the
108 .I service
109 argument, identifying an Internet host and a service.
111 .I ar_request
112 element corresponds to the
113 .I hints
114 argument, specifying the criteria for selecting
115 the returned socket address structures.
116 Finally,
117 .I ar_result
118 corresponds to the
119 .I res
120 argument; you do not need to initialize this element,
121 it will be automatically set when the request
122 is resolved.
124 .I addrinfo
125 structure referenced by the last two elements is described in
126 .BR getaddrinfo (3).
128 When
129 .I mode
130 is specified as
131 .BR GAI_NOWAIT ,
132 notifications about resolved requests
133 can be obtained by employing the
134 .I sigevent
135 structure pointed to by the
136 .I sevp
137 argument.
138 For the definition and general details of this structure, see
139 .BR sigevent (7).
141 .I sevp\->sigev_notify
142 field can have the following values:
144 .BR SIGEV_NONE
145 Don't provide any notification.
147 .BR SIGEV_SIGNAL
148 When a look-up completes, generate the signal
149 .I sigev_signo
150 for the process.
152 .BR sigevent (7)
153 for general details.
155 .I si_code
156 field of the
157 .I siginfo_t
158 structure will be set to
159 .BR SI_ASYNCNL .
160 .\" si_pid and si_uid are also set, to the values of the calling process,
161 .\" which doesn't provide useful information, so we'll skip mentioning it.
163 .BR SIGEV_THREAD
164 When a look-up completes, invoke
165 .I sigev_notify_function
166 as if it were the start function of a new thread.
168 .BR sigevent (7)
169 for details.
172 .BR SIGEV_SIGNAL
174 .BR SIGEV_THREAD ,
175 it may be useful to point
176 .IR sevp\->sigev_value.sival_ptr
178 .IR list .
181 .BR gai_suspend ()
182 function suspends execution of the calling thread,
183 waiting for the completion of one or more requests in the array
184 .IR list .
186 .I nitems
187 argument specifies the size of the array
188 .IR list .
189 The call blocks until one of the following occurs:
190 .IP * 3
191 One or more of the operations in
192 .I list
193 completes.
194 .IP *
195 The call is interrupted by a signal that is caught.
196 .IP *
197 The time interval specified in
198 .I timeout
199 elapses.
200 This argument specifies a timeout in seconds plus nanoseconds (see
201 .BR nanosleep (2)
202 for details of the
203 .I timespec
204 structure).
206 .I timeout
207 is NULL, then the call blocks indefinitely
208 (until one of the events above occurs).
210 No explicit indication of which request was completed is given;
211 you must determine which request(s) have completed by iterating with
212 .BR gai_error ()
213 over the list of requests.
216 .BR gai_error ()
217 function returns the status of the request
218 .IR req :
219 either
220 .B EAI_INPROGRESS
221 if the request was not completed yet,
222 0 if it was handled successfully,
223 or an error code if the request could not be resolved.
226 .BR gai_cancel ()
227 function cancels the request
228 .IR req .
229 If the request has been canceled successfully,
230 the error status of the request will be set to
231 .B EAI_CANCELED
232 and normal asynchronous notification will be performed.
233 The request cannot be canceled if it is currently being processed;
234 in that case, it will be handled as if
235 .BR gai_cancel ()
236 has never been called.
238 .I req
239 is NULL, an attempt is made to cancel all outstanding requests
240 that the process has made.
241 .SH RETURN VALUE
243 .BR getaddrinfo_a ()
244 function returns 0 if all of the requests have been enqueued successfully,
245 or one of the following nonzero error codes:
247 .B EAI_AGAIN
248 The resources necessary to enqueue the look-up requests were not available.
249 The application may check the error status of each
250 request to determine which ones failed.
252 .B EAI_MEMORY
253 Out of memory.
255 .B EAI_SYSTEM
256 .I mode
257 is invalid.
260 .BR gai_suspend ()
261 function returns 0 if at least one of the listed requests has been completed.
262 Otherwise, it returns one of the following nonzero error codes:
264 .B EAI_AGAIN
265 The given timeout expired before any of the requests could be completed.
267 .B EAI_ALLDONE
268 There were no actual requests given to the function.
270 .B EAI_INTR
271 A signal has interrupted the function.
272 Note that this interruption might have been
273 caused by signal notification of some completed look-up request.
276 .BR gai_error ()
277 function can return
278 .B EAI_INPROGRESS
279 for an unfinished look-up request,
280 0 for a successfully completed look-up
281 (as described above), one of the error codes that could be returned by
282 .BR getaddrinfo (3),
283 or the error code
284 .B EAI_CANCELED
285 if the request has been canceled explicitly before it could be finished.
288 .BR gai_cancel ()
289 function can return one of these values:
291 .B EAI_CANCELED
292 The request has been canceled successfully.
294 .B EAI_NOTCANCELED
295 The request has not been canceled.
297 .B EAI_ALLDONE
298 The request has already completed.
301 .BR gai_strerror (3)
302 function translates these error codes to a human readable string,
303 suitable for error reporting.
304 .SH ATTRIBUTES
305 For an explanation of the terms used in this section, see
306 .BR attributes (7).
307 .ad l
310 allbox;
311 lbx lb lb
312 l l l.
313 Interface       Attribute       Value
315 .BR getaddrinfo_a (),
316 .BR gai_suspend (),
317 .BR gai_error (),
318 .BR gai_cancel ()
319 T}      Thread safety   MT-Safe
323 .sp 1
324 .SH CONFORMING TO
325 These functions are GNU extensions;
326 they first appeared in glibc in version 2.2.3.
327 .SH NOTES
328 The interface of
329 .BR getaddrinfo_a ()
330 was modeled after the
331 .BR lio_listio (3)
332 interface.
333 .SH EXAMPLES
334 Two examples are provided: a simple example that resolves
335 several requests in parallel synchronously, and a complex example
336 showing some of the asynchronous capabilities.
337 .SS Synchronous example
338 The program below simply resolves several hostnames in parallel,
339 giving a speed-up compared to resolving the hostnames sequentially using
340 .BR getaddrinfo (3).
341 The program might be used like this:
343 .in +4n
345 $ \fB./a.out ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz\fP
346 ftp.us.kernel.org: 128.30.2.36
347 enoent.linuxfoundation.org: Name or service not known
348 gnu.cz: 87.236.197.13
352 Here is the program source code
355 #define _GNU_SOURCE
356 #include <netdb.h>
357 #include <stdio.h>
358 #include <stdlib.h>
359 #include <string.h>
362 main(int argc, char *argv[])
364     int ret;
365     struct gaicb *reqs[argc \- 1];
366     char host[NI_MAXHOST];
367     struct addrinfo *res;
369     if (argc < 2) {
370         fprintf(stderr, "Usage: %s HOST...\en", argv[0]);
371         exit(EXIT_FAILURE);
372     }
374     for (int i = 0; i < argc \- 1; i++) {
375         reqs[i] = malloc(sizeof(*reqs[0]));
376         if (reqs[i] == NULL) {
377             perror("malloc");
378             exit(EXIT_FAILURE);
379         }
380         memset(reqs[i], 0, sizeof(*reqs[0]));
381         reqs[i]\->ar_name = argv[i + 1];
382     }
384     ret = getaddrinfo_a(GAI_WAIT, reqs, argc \- 1, NULL);
385     if (ret != 0) {
386         fprintf(stderr, "getaddrinfo_a() failed: %s\en",
387                 gai_strerror(ret));
388         exit(EXIT_FAILURE);
389     }
391     for (int i = 0; i < argc \- 1; i++) {
392         printf("%s: ", reqs[i]\->ar_name);
393         ret = gai_error(reqs[i]);
394         if (ret == 0) {
395             res = reqs[i]\->ar_result;
397             ret = getnameinfo(res\->ai_addr, res\->ai_addrlen,
398                     host, sizeof(host),
399                     NULL, 0, NI_NUMERICHOST);
400             if (ret != 0) {
401                 fprintf(stderr, "getnameinfo() failed: %s\en",
402                         gai_strerror(ret));
403                 exit(EXIT_FAILURE);
404             }
405             puts(host);
407         } else {
408             puts(gai_strerror(ret));
409         }
410     }
411     exit(EXIT_SUCCESS);
414 .SS Asynchronous example
415 This example shows a simple interactive
416 .BR getaddrinfo_a ()
417 front-end.
418 The notification facility is not demonstrated.
420 An example session might look like this:
422 .in +4n
424 $ \fB./a.out\fP
425 > a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
426 > c 2
427 [2] gnu.cz: Request not canceled
428 > w 0 1
429 [00] ftp.us.kernel.org: Finished
430 > l
431 [00] ftp.us.kernel.org: 216.165.129.139
432 [01] enoent.linuxfoundation.org: Processing request in progress
433 [02] gnu.cz: 87.236.197.13
434 > l
435 [00] ftp.us.kernel.org: 216.165.129.139
436 [01] enoent.linuxfoundation.org: Name or service not known
437 [02] gnu.cz: 87.236.197.13
441 The program source is as follows:
444 #define _GNU_SOURCE
445 #include <netdb.h>
446 #include <stdio.h>
447 #include <stdlib.h>
448 #include <string.h>
450 static struct gaicb **reqs = NULL;
451 static int nreqs = 0;
453 static char *
454 getcmd(void)
456     static char buf[256];
458     fputs("> ", stdout); fflush(stdout);
459     if (fgets(buf, sizeof(buf), stdin) == NULL)
460         return NULL;
462     if (buf[strlen(buf) \- 1] == \(aq\en\(aq)
463         buf[strlen(buf) \- 1] = 0;
465     return buf;
468 /* Add requests for specified hostnames. */
469 static void
470 add_requests(void)
472     int nreqs_base = nreqs;
473     char *host;
474     int ret;
476     while ((host = strtok(NULL, " "))) {
477         nreqs++;
478         reqs = realloc(reqs, sizeof(reqs[0]) * nreqs);
480         reqs[nreqs \- 1] = calloc(1, sizeof(*reqs[0]));
481         reqs[nreqs \- 1]\->ar_name = strdup(host);
482     }
484     /* Queue nreqs_base..nreqs requests. */
486     ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
487                         nreqs \- nreqs_base, NULL);
488     if (ret) {
489         fprintf(stderr, "getaddrinfo_a() failed: %s\en",
490                 gai_strerror(ret));
491         exit(EXIT_FAILURE);
492     }
495 /* Wait until at least one of specified requests completes. */
496 static void
497 wait_requests(void)
499     char *id;
500     int ret, n;
501     struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs));
502                 /* NULL elements are ignored by gai_suspend(). */
504     while ((id = strtok(NULL, " ")) != NULL) {
505         n = atoi(id);
507         if (n >= nreqs) {
508             printf("Bad request number: %s\en", id);
509             return;
510         }
512         wait_reqs[n] = reqs[n];
513     }
515     ret = gai_suspend(wait_reqs, nreqs, NULL);
516     if (ret) {
517         printf("gai_suspend(): %s\en", gai_strerror(ret));
518         return;
519     }
521     for (int i = 0; i < nreqs; i++) {
522         if (wait_reqs[i] == NULL)
523             continue;
525         ret = gai_error(reqs[i]);
526         if (ret == EAI_INPROGRESS)
527             continue;
529         printf("[%02d] %s: %s\en", i, reqs[i]\->ar_name,
530                ret == 0 ? "Finished" : gai_strerror(ret));
531     }
534 /* Cancel specified requests. */
535 static void
536 cancel_requests(void)
538     char *id;
539     int ret, n;
541     while ((id = strtok(NULL, " ")) != NULL) {
542         n = atoi(id);
544         if (n >= nreqs) {
545             printf("Bad request number: %s\en", id);
546             return;
547         }
549         ret = gai_cancel(reqs[n]);
550         printf("[%s] %s: %s\en", id, reqs[atoi(id)]\->ar_name,
551                gai_strerror(ret));
552     }
555 /* List all requests. */
556 static void
557 list_requests(void)
559     int ret;
560     char host[NI_MAXHOST];
561     struct addrinfo *res;
563     for (int i = 0; i < nreqs; i++) {
564         printf("[%02d] %s: ", i, reqs[i]\->ar_name);
565         ret = gai_error(reqs[i]);
567         if (!ret) {
568             res = reqs[i]\->ar_result;
570             ret = getnameinfo(res\->ai_addr, res\->ai_addrlen,
571                               host, sizeof(host),
572                               NULL, 0, NI_NUMERICHOST);
573             if (ret) {
574                 fprintf(stderr, "getnameinfo() failed: %s\en",
575                         gai_strerror(ret));
576                 exit(EXIT_FAILURE);
577             }
578             puts(host);
579         } else {
580             puts(gai_strerror(ret));
581         }
582     }
586 main(int argc, char *argv[])
588     char *cmdline;
589     char *cmd;
591     while ((cmdline = getcmd()) != NULL) {
592         cmd = strtok(cmdline, " ");
594         if (cmd == NULL) {
595             list_requests();
596         } else {
597             switch (cmd[0]) {
598             case \(aqa\(aq:
599                 add_requests();
600                 break;
601             case \(aqw\(aq:
602                 wait_requests();
603                 break;
604             case \(aqc\(aq:
605                 cancel_requests();
606                 break;
607             case \(aql\(aq:
608                 list_requests();
609                 break;
610             default:
611                 fprintf(stderr, "Bad command: %c\en", cmd[0]);
612                 break;
613             }
614         }
615     }
616     exit(EXIT_SUCCESS);
619 .SH SEE ALSO
620 .BR getaddrinfo (3),
621 .BR inet (3),
622 .BR lio_listio (3),
623 .BR hostname (7),
624 .BR ip (7),
625 .BR sigevent (7)