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