]> git.ipfire.org Git - thirdparty/man-pages.git/blob - man3/getaddrinfo_a.3
Many pages: Fix style issues reported by `make lint-groff`
[thirdparty/man-pages.git] / man3 / getaddrinfo_a.3
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 .\" SPDX-License-Identifier: Linux-man-pages-copyleft
6 .\"
7 .\" References: http://people.redhat.com/drepper/asynchnl.pdf,
8 .\" http://www.imperialviolet.org/2005/06/01/asynchronous-dns-lookups-with-glibc.html
9 .\"
10 .TH GETADDRINFO_A 3 2021-03-22 "GNU" "Linux Programmer's Manual"
11 .SH NAME
12 getaddrinfo_a, gai_suspend, gai_error, gai_cancel \- asynchronous
13 network address and service translation
14 .SH LIBRARY
15 Asynchronous name lookup library
16 .RI ( libanl ", " \-lanl )
17 .SH SYNOPSIS
18 .nf
19 .BR "#define _GNU_SOURCE" " /* See feature_test_macros(7) */"
20 .B #include <netdb.h>
21 .PP
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 );
26 .PP
27 .BI "int gai_error(struct gaicb *" req );
28 .BI "int gai_cancel(struct gaicb *" req );
29 .fi
30 .SH DESCRIPTION
31 The
32 .BR getaddrinfo_a ()
33 function performs the same task as
34 .BR getaddrinfo (3),
35 but allows multiple name look-ups to be performed asynchronously,
36 with optional notification on completion of look-up operations.
37 .PP
38 The
39 .I mode
40 argument has one of the following values:
41 .TP
42 .B GAI_WAIT
43 Perform the look-ups synchronously.
44 The call blocks until the look-ups have completed.
45 .TP
46 .B GAI_NOWAIT
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
51 .I sevp
52 argument below.
53 .PP
54 The array
55 .I list
56 specifies the look-up requests to process.
57 The
58 .I nitems
59 argument specifies the number of elements in
60 .IR list .
61 The requested look-up operations are started in parallel.
62 NULL elements in
63 .I list
64 are ignored.
65 Each request is described by a
66 .I gaicb
67 structure, defined as follows:
68 .PP
69 .in +4n
70 .EX
71 struct gaicb {
72 const char *ar_name;
73 const char *ar_service;
74 const struct addrinfo *ar_request;
75 struct addrinfo *ar_result;
76 };
77 .EE
78 .in
79 .PP
80 The elements of this structure correspond to the arguments of
81 .BR getaddrinfo (3).
82 Thus,
83 .I ar_name
84 corresponds to the
85 .I node
86 argument and
87 .I ar_service
88 to the
89 .I service
90 argument, identifying an Internet host and a service.
91 The
92 .I ar_request
93 element corresponds to the
94 .I hints
95 argument, specifying the criteria for selecting
96 the returned socket address structures.
97 Finally,
98 .I ar_result
99 corresponds to the
100 .I res
101 argument; you do not need to initialize this element,
102 it will be automatically set when the request
103 is resolved.
104 The
105 .I addrinfo
106 structure referenced by the last two elements is described in
107 .BR getaddrinfo (3).
108 .PP
109 When
110 .I mode
111 is specified as
112 .BR GAI_NOWAIT ,
113 notifications about resolved requests
114 can be obtained by employing the
115 .I sigevent
116 structure pointed to by the
117 .I sevp
118 argument.
119 For the definition and general details of this structure, see
120 .BR sigevent (7).
121 The
122 .I sevp\->sigev_notify
123 field can have the following values:
124 .TP
125 .B SIGEV_NONE
126 Don't provide any notification.
127 .TP
128 .B SIGEV_SIGNAL
129 When a look-up completes, generate the signal
130 .I sigev_signo
131 for the process.
132 See
133 .BR sigevent (7)
134 for general details.
135 The
136 .I si_code
137 field of the
138 .I siginfo_t
139 structure will be set to
140 .BR SI_ASYNCNL .
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.
143 .TP
144 .B SIGEV_THREAD
145 When a look-up completes, invoke
146 .I sigev_notify_function
147 as if it were the start function of a new thread.
148 See
149 .BR sigevent (7)
150 for details.
151 .PP
152 For
153 .B SIGEV_SIGNAL
154 and
155 .BR SIGEV_THREAD ,
156 it may be useful to point
157 .I sevp\->sigev_value.sival_ptr
158 to
159 .IR list .
160 .PP
161 The
162 .BR gai_suspend ()
163 function suspends execution of the calling thread,
164 waiting for the completion of one or more requests in the array
165 .IR list .
166 The
167 .I nitems
168 argument specifies the size of the array
169 .IR list .
170 The call blocks until one of the following occurs:
171 .IP * 3
172 One or more of the operations in
173 .I list
174 completes.
175 .IP *
176 The call is interrupted by a signal that is caught.
177 .IP *
178 The time interval specified in
179 .I timeout
180 elapses.
181 This argument specifies a timeout in seconds plus nanoseconds (see
182 .BR nanosleep (2)
183 for details of the
184 .I timespec
185 structure).
186 If
187 .I timeout
188 is NULL, then the call blocks indefinitely
189 (until one of the events above occurs).
190 .PP
191 No explicit indication of which request was completed is given;
192 you must determine which request(s) have completed by iterating with
193 .BR gai_error ()
194 over the list of requests.
195 .PP
196 The
197 .BR gai_error ()
198 function returns the status of the request
199 .IR req :
200 either
201 .B EAI_INPROGRESS
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.
205 .PP
206 The
207 .BR gai_cancel ()
208 function cancels the request
209 .IR req .
210 If the request has been canceled successfully,
211 the error status of the request will be set to
212 .B EAI_CANCELED
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
216 .BR gai_cancel ()
217 has never been called.
218 If
219 .I req
220 is NULL, an attempt is made to cancel all outstanding requests
221 that the process has made.
222 .SH RETURN VALUE
223 The
224 .BR getaddrinfo_a ()
225 function returns 0 if all of the requests have been enqueued successfully,
226 or one of the following nonzero error codes:
227 .TP
228 .B EAI_AGAIN
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.
232 .TP
233 .B EAI_MEMORY
234 Out of memory.
235 .TP
236 .B EAI_SYSTEM
237 .I mode
238 is invalid.
239 .PP
240 The
241 .BR gai_suspend ()
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:
244 .TP
245 .B EAI_AGAIN
246 The given timeout expired before any of the requests could be completed.
247 .TP
248 .B EAI_ALLDONE
249 There were no actual requests given to the function.
250 .TP
251 .B EAI_INTR
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.
255 .PP
256 The
257 .BR gai_error ()
258 function can return
259 .B EAI_INPROGRESS
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
263 .BR getaddrinfo (3),
264 or the error code
265 .B EAI_CANCELED
266 if the request has been canceled explicitly before it could be finished.
267 .PP
268 The
269 .BR gai_cancel ()
270 function can return one of these values:
271 .TP
272 .B EAI_CANCELED
273 The request has been canceled successfully.
274 .TP
275 .B EAI_NOTCANCELED
276 The request has not been canceled.
277 .TP
278 .B EAI_ALLDONE
279 The request has already completed.
280 .PP
281 The
282 .BR gai_strerror (3)
283 function translates these error codes to a human readable string,
284 suitable for error reporting.
285 .SH ATTRIBUTES
286 For an explanation of the terms used in this section, see
287 .BR attributes (7).
288 .ad l
289 .nh
290 .TS
291 allbox;
292 lbx lb lb
293 l l l.
294 Interface Attribute Value
295 T{
296 .BR getaddrinfo_a (),
297 .BR gai_suspend (),
298 .BR gai_error (),
299 .BR gai_cancel ()
300 T} Thread safety MT-Safe
301 .TE
302 .hy
303 .ad
304 .sp 1
305 .SH CONFORMING TO
306 These functions are GNU extensions;
307 they first appeared in glibc in version 2.2.3.
308 .SH NOTES
309 The interface of
310 .BR getaddrinfo_a ()
311 was modeled after the
312 .BR lio_listio (3)
313 interface.
314 .SH EXAMPLES
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
321 .BR getaddrinfo (3).
322 The program might be used like this:
323 .PP
324 .in +4n
325 .EX
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
330 .EE
331 .in
332 .PP
333 Here is the program source code
334 .PP
335 .EX
336 #define _GNU_SOURCE
337 #include <netdb.h>
338 #include <stdio.h>
339 #include <stdlib.h>
340 #include <string.h>
341
342 int
343 main(int argc, char *argv[])
344 {
345 int ret;
346 struct gaicb *reqs[argc \- 1];
347 char host[NI_MAXHOST];
348 struct addrinfo *res;
349
350 if (argc < 2) {
351 fprintf(stderr, "Usage: %s HOST...\en", argv[0]);
352 exit(EXIT_FAILURE);
353 }
354
355 for (int i = 0; i < argc \- 1; i++) {
356 reqs[i] = malloc(sizeof(*reqs[0]));
357 if (reqs[i] == NULL) {
358 perror("malloc");
359 exit(EXIT_FAILURE);
360 }
361 memset(reqs[i], 0, sizeof(*reqs[0]));
362 reqs[i]\->ar_name = argv[i + 1];
363 }
364
365 ret = getaddrinfo_a(GAI_WAIT, reqs, argc \- 1, NULL);
366 if (ret != 0) {
367 fprintf(stderr, "getaddrinfo_a() failed: %s\en",
368 gai_strerror(ret));
369 exit(EXIT_FAILURE);
370 }
371
372 for (int i = 0; i < argc \- 1; i++) {
373 printf("%s: ", reqs[i]\->ar_name);
374 ret = gai_error(reqs[i]);
375 if (ret == 0) {
376 res = reqs[i]\->ar_result;
377
378 ret = getnameinfo(res\->ai_addr, res\->ai_addrlen,
379 host, sizeof(host),
380 NULL, 0, NI_NUMERICHOST);
381 if (ret != 0) {
382 fprintf(stderr, "getnameinfo() failed: %s\en",
383 gai_strerror(ret));
384 exit(EXIT_FAILURE);
385 }
386 puts(host);
387
388 } else {
389 puts(gai_strerror(ret));
390 }
391 }
392 exit(EXIT_SUCCESS);
393 }
394 .EE
395 .SS Asynchronous example
396 This example shows a simple interactive
397 .BR getaddrinfo_a ()
398 front-end.
399 The notification facility is not demonstrated.
400 .PP
401 An example session might look like this:
402 .PP
403 .in +4n
404 .EX
405 $ \fB./a.out\fP
406 > a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
407 > c 2
408 [2] gnu.cz: Request not canceled
409 > w 0 1
410 [00] ftp.us.kernel.org: Finished
411 > l
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
415 > l
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
419 .EE
420 .in
421 .PP
422 The program source is as follows:
423 .PP
424 .EX
425 #define _GNU_SOURCE
426 #include <netdb.h>
427 #include <stdio.h>
428 #include <stdlib.h>
429 #include <string.h>
430
431 static struct gaicb **reqs = NULL;
432 static int nreqs = 0;
433
434 static char *
435 getcmd(void)
436 {
437 static char buf[256];
438
439 fputs("> ", stdout); fflush(stdout);
440 if (fgets(buf, sizeof(buf), stdin) == NULL)
441 return NULL;
442
443 if (buf[strlen(buf) \- 1] == \(aq\en\(aq)
444 buf[strlen(buf) \- 1] = 0;
445
446 return buf;
447 }
448
449 /* Add requests for specified hostnames. */
450 static void
451 add_requests(void)
452 {
453 int nreqs_base = nreqs;
454 char *host;
455 int ret;
456
457 while ((host = strtok(NULL, " "))) {
458 nreqs++;
459 reqs = realloc(reqs, sizeof(reqs[0]) * nreqs);
460
461 reqs[nreqs \- 1] = calloc(1, sizeof(*reqs[0]));
462 reqs[nreqs \- 1]\->ar_name = strdup(host);
463 }
464
465 /* Queue nreqs_base..nreqs requests. */
466
467 ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
468 nreqs \- nreqs_base, NULL);
469 if (ret) {
470 fprintf(stderr, "getaddrinfo_a() failed: %s\en",
471 gai_strerror(ret));
472 exit(EXIT_FAILURE);
473 }
474 }
475
476 /* Wait until at least one of specified requests completes. */
477 static void
478 wait_requests(void)
479 {
480 char *id;
481 int ret, n;
482 struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs));
483 /* NULL elements are ignored by gai_suspend(). */
484
485 while ((id = strtok(NULL, " ")) != NULL) {
486 n = atoi(id);
487
488 if (n >= nreqs) {
489 printf("Bad request number: %s\en", id);
490 return;
491 }
492
493 wait_reqs[n] = reqs[n];
494 }
495
496 ret = gai_suspend(wait_reqs, nreqs, NULL);
497 if (ret) {
498 printf("gai_suspend(): %s\en", gai_strerror(ret));
499 return;
500 }
501
502 for (int i = 0; i < nreqs; i++) {
503 if (wait_reqs[i] == NULL)
504 continue;
505
506 ret = gai_error(reqs[i]);
507 if (ret == EAI_INPROGRESS)
508 continue;
509
510 printf("[%02d] %s: %s\en", i, reqs[i]\->ar_name,
511 ret == 0 ? "Finished" : gai_strerror(ret));
512 }
513 }
514
515 /* Cancel specified requests. */
516 static void
517 cancel_requests(void)
518 {
519 char *id;
520 int ret, n;
521
522 while ((id = strtok(NULL, " ")) != NULL) {
523 n = atoi(id);
524
525 if (n >= nreqs) {
526 printf("Bad request number: %s\en", id);
527 return;
528 }
529
530 ret = gai_cancel(reqs[n]);
531 printf("[%s] %s: %s\en", id, reqs[atoi(id)]\->ar_name,
532 gai_strerror(ret));
533 }
534 }
535
536 /* List all requests. */
537 static void
538 list_requests(void)
539 {
540 int ret;
541 char host[NI_MAXHOST];
542 struct addrinfo *res;
543
544 for (int i = 0; i < nreqs; i++) {
545 printf("[%02d] %s: ", i, reqs[i]\->ar_name);
546 ret = gai_error(reqs[i]);
547
548 if (!ret) {
549 res = reqs[i]\->ar_result;
550
551 ret = getnameinfo(res\->ai_addr, res\->ai_addrlen,
552 host, sizeof(host),
553 NULL, 0, NI_NUMERICHOST);
554 if (ret) {
555 fprintf(stderr, "getnameinfo() failed: %s\en",
556 gai_strerror(ret));
557 exit(EXIT_FAILURE);
558 }
559 puts(host);
560 } else {
561 puts(gai_strerror(ret));
562 }
563 }
564 }
565
566 int
567 main(int argc, char *argv[])
568 {
569 char *cmdline;
570 char *cmd;
571
572 while ((cmdline = getcmd()) != NULL) {
573 cmd = strtok(cmdline, " ");
574
575 if (cmd == NULL) {
576 list_requests();
577 } else {
578 switch (cmd[0]) {
579 case \(aqa\(aq:
580 add_requests();
581 break;
582 case \(aqw\(aq:
583 wait_requests();
584 break;
585 case \(aqc\(aq:
586 cancel_requests();
587 break;
588 case \(aql\(aq:
589 list_requests();
590 break;
591 default:
592 fprintf(stderr, "Bad command: %c\en", cmd[0]);
593 break;
594 }
595 }
596 }
597 exit(EXIT_SUCCESS);
598 }
599 .EE
600 .SH SEE ALSO
601 .BR getaddrinfo (3),
602 .BR inet (3),
603 .BR lio_listio (3),
604 .BR hostname (7),
605 .BR ip (7),
606 .BR sigevent (7)