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>
5 .\" SPDX-License-Identifier: Linux-man-pages-copyleft
7 .\" References: http://people.redhat.com/drepper/asynchnl.pdf,
8 .\" http://www.imperialviolet.org/2005/06/01/asynchronous-dns-lookups-with-glibc.html
10 .TH GETADDRINFO_A 3 2021-03-22 "GNU" "Linux Programmer's Manual"
12 getaddrinfo_a, gai_suspend, gai_error, gai_cancel \- asynchronous
13 network address and service translation
15 Asynchronous name lookup library
16 .RI ( libanl ", " \-lanl )
19 .BR "#define _GNU_SOURCE" " /* See feature_test_macros(7) */"
22 .BI "int getaddrinfo_a(int " mode ", struct gaicb *" list [restrict],
23 .BI " int " nitems ", struct sigevent *restrict " sevp );
24 .BI "int gai_suspend(const struct gaicb *const " list "[], int " nitems ,
25 .BI " const struct timespec *" timeout );
27 .BI "int gai_error(struct gaicb *" req );
28 .BI "int gai_cancel(struct gaicb *" req );
33 function performs the same task as
35 but allows multiple name look-ups to be performed asynchronously,
36 with optional notification on completion of look-up operations.
40 argument has one of the following values:
43 Perform the look-ups synchronously.
44 The call blocks until the look-ups have completed.
47 Perform the look-ups asynchronously.
48 The call returns immediately,
49 and the requests are resolved in the background.
50 See the discussion of the
56 specifies the look-up requests to process.
59 argument specifies the number of elements in
61 The requested look-up operations are started in parallel.
65 Each request is described by a
67 structure, defined as follows:
73 const char *ar_service;
74 const struct addrinfo *ar_request;
75 struct addrinfo *ar_result;
80 The elements of this structure correspond to the arguments of
90 argument, identifying an Internet host and a service.
93 element corresponds to the
95 argument, specifying the criteria for selecting
96 the returned socket address structures.
101 argument; you do not need to initialize this element,
102 it will be automatically set when the request
106 structure referenced by the last two elements is described in
113 notifications about resolved requests
114 can be obtained by employing the
116 structure pointed to by the
119 For the definition and general details of this structure, see
122 .I sevp\->sigev_notify
123 field can have the following values:
126 Don't provide any notification.
129 When a look-up completes, generate the signal
139 structure will be set to
141 .\" si_pid and si_uid are also set, to the values of the calling process,
142 .\" which doesn't provide useful information, so we'll skip mentioning it.
145 When a look-up completes, invoke
146 .I sigev_notify_function
147 as if it were the start function of a new thread.
156 it may be useful to point
157 .I sevp\->sigev_value.sival_ptr
163 function suspends execution of the calling thread,
164 waiting for the completion of one or more requests in the array
168 argument specifies the size of the array
170 The call blocks until one of the following occurs:
172 One or more of the operations in
176 The call is interrupted by a signal that is caught.
178 The time interval specified in
181 This argument specifies a timeout in seconds plus nanoseconds (see
188 is NULL, then the call blocks indefinitely
189 (until one of the events above occurs).
191 No explicit indication of which request was completed is given;
192 you must determine which request(s) have completed by iterating with
194 over the list of requests.
198 function returns the status of the request
202 if the request was not completed yet,
203 0 if it was handled successfully,
204 or an error code if the request could not be resolved.
208 function cancels the request
210 If the request has been canceled successfully,
211 the error status of the request will be set to
213 and normal asynchronous notification will be performed.
214 The request cannot be canceled if it is currently being processed;
215 in that case, it will be handled as if
217 has never been called.
220 is NULL, an attempt is made to cancel all outstanding requests
221 that the process has made.
225 function returns 0 if all of the requests have been enqueued successfully,
226 or one of the following nonzero error codes:
229 The resources necessary to enqueue the look-up requests were not available.
230 The application may check the error status of each
231 request to determine which ones failed.
242 function returns 0 if at least one of the listed requests has been completed.
243 Otherwise, it returns one of the following nonzero error codes:
246 The given timeout expired before any of the requests could be completed.
249 There were no actual requests given to the function.
252 A signal has interrupted the function.
253 Note that this interruption might have been
254 caused by signal notification of some completed look-up request.
260 for an unfinished look-up request,
261 0 for a successfully completed look-up
262 (as described above), one of the error codes that could be returned by
266 if the request has been canceled explicitly before it could be finished.
270 function can return one of these values:
273 The request has been canceled successfully.
276 The request has not been canceled.
279 The request has already completed.
283 function translates these error codes to a human readable string,
284 suitable for error reporting.
286 For an explanation of the terms used in this section, see
294 Interface Attribute Value
296 .BR getaddrinfo_a (),
300 T} Thread safety MT-Safe
306 These functions are GNU extensions;
307 they first appeared in glibc in version 2.2.3.
311 was modeled after the
315 Two examples are provided: a simple example that resolves
316 several requests in parallel synchronously, and a complex example
317 showing some of the asynchronous capabilities.
318 .SS Synchronous example
319 The program below simply resolves several hostnames in parallel,
320 giving a speed-up compared to resolving the hostnames sequentially using
322 The program might be used like this:
326 $ \fB./a.out ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz\fP
327 ftp.us.kernel.org: 128.30.2.36
328 enoent.linuxfoundation.org: Name or service not known
329 gnu.cz: 87.236.197.13
333 Here is the program source code
343 main(int argc, char *argv[])
346 struct gaicb *reqs[argc \- 1];
347 char host[NI_MAXHOST];
348 struct addrinfo *res;
351 fprintf(stderr, "Usage: %s HOST...\en", argv[0]);
355 for (int i = 0; i < argc \- 1; i++) {
356 reqs[i] = malloc(sizeof(*reqs[0]));
357 if (reqs[i] == NULL) {
361 memset(reqs[i], 0, sizeof(*reqs[0]));
362 reqs[i]\->ar_name = argv[i + 1];
365 ret = getaddrinfo_a(GAI_WAIT, reqs, argc \- 1, NULL);
367 fprintf(stderr, "getaddrinfo_a() failed: %s\en",
372 for (int i = 0; i < argc \- 1; i++) {
373 printf("%s: ", reqs[i]\->ar_name);
374 ret = gai_error(reqs[i]);
376 res = reqs[i]\->ar_result;
378 ret = getnameinfo(res\->ai_addr, res\->ai_addrlen,
380 NULL, 0, NI_NUMERICHOST);
382 fprintf(stderr, "getnameinfo() failed: %s\en",
389 puts(gai_strerror(ret));
395 .SS Asynchronous example
396 This example shows a simple interactive
399 The notification facility is not demonstrated.
401 An example session might look like this:
406 > a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
408 [2] gnu.cz: Request not canceled
410 [00] ftp.us.kernel.org: Finished
412 [00] ftp.us.kernel.org: 216.165.129.139
413 [01] enoent.linuxfoundation.org: Processing request in progress
414 [02] gnu.cz: 87.236.197.13
416 [00] ftp.us.kernel.org: 216.165.129.139
417 [01] enoent.linuxfoundation.org: Name or service not known
418 [02] gnu.cz: 87.236.197.13
422 The program source is as follows:
431 static struct gaicb **reqs = NULL;
432 static int nreqs = 0;
437 static char buf[256];
439 fputs("> ", stdout); fflush(stdout);
440 if (fgets(buf, sizeof(buf), stdin) == NULL)
443 if (buf[strlen(buf) \- 1] == \(aq\en\(aq)
444 buf[strlen(buf) \- 1] = 0;
449 /* Add requests for specified hostnames. */
453 int nreqs_base = nreqs;
457 while ((host = strtok(NULL, " "))) {
459 reqs = realloc(reqs, sizeof(reqs[0]) * nreqs);
461 reqs[nreqs \- 1] = calloc(1, sizeof(*reqs[0]));
462 reqs[nreqs \- 1]\->ar_name = strdup(host);
465 /* Queue nreqs_base..nreqs requests. */
467 ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
468 nreqs \- nreqs_base, NULL);
470 fprintf(stderr, "getaddrinfo_a() failed: %s\en",
476 /* Wait until at least one of specified requests completes. */
482 struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs));
483 /* NULL elements are ignored by gai_suspend(). */
485 while ((id = strtok(NULL, " ")) != NULL) {
489 printf("Bad request number: %s\en", id);
493 wait_reqs[n] = reqs[n];
496 ret = gai_suspend(wait_reqs, nreqs, NULL);
498 printf("gai_suspend(): %s\en", gai_strerror(ret));
502 for (int i = 0; i < nreqs; i++) {
503 if (wait_reqs[i] == NULL)
506 ret = gai_error(reqs[i]);
507 if (ret == EAI_INPROGRESS)
510 printf("[%02d] %s: %s\en", i, reqs[i]\->ar_name,
511 ret == 0 ? "Finished" : gai_strerror(ret));
515 /* Cancel specified requests. */
517 cancel_requests(void)
522 while ((id = strtok(NULL, " ")) != NULL) {
526 printf("Bad request number: %s\en", id);
530 ret = gai_cancel(reqs[n]);
531 printf("[%s] %s: %s\en", id, reqs[atoi(id)]\->ar_name,
536 /* List all requests. */
541 char host[NI_MAXHOST];
542 struct addrinfo *res;
544 for (int i = 0; i < nreqs; i++) {
545 printf("[%02d] %s: ", i, reqs[i]\->ar_name);
546 ret = gai_error(reqs[i]);
549 res = reqs[i]\->ar_result;
551 ret = getnameinfo(res\->ai_addr, res\->ai_addrlen,
553 NULL, 0, NI_NUMERICHOST);
555 fprintf(stderr, "getnameinfo() failed: %s\en",
561 puts(gai_strerror(ret));
567 main(int argc, char *argv[])
572 while ((cmdline = getcmd()) != NULL) {
573 cmd = strtok(cmdline, " ");
592 fprintf(stderr, "Bad command: %c\en", cmd[0]);