1GETADDRINFO_A(3) Linux Programmer's Manual GETADDRINFO_A(3)
2
3
4
6 getaddrinfo_a, gai_suspend, gai_error, gai_cancel - asynchronous net‐
7 work address and service translation
8
10 #define _GNU_SOURCE /* See feature_test_macros(7) */
11 #include <netdb.h>
12
13 int getaddrinfo_a(int mode, struct gaicb *list[],
14 int nitems, struct sigevent *sevp);
15
16 int gai_suspend(const struct gaicb * const list[], int nitems,
17 const struct timespec *timeout);
18
19 int gai_error(struct gaicb *req);
20
21 int gai_cancel(struct gaicb *req);
22
23 Link with -lanl.
24
26 The getaddrinfo_a() function performs the same task as getaddrinfo(3),
27 but allows multiple name look-ups to be performed asynchronously, with
28 optional notification on completion of look-up operations.
29
30 The mode argument has one of the following values:
31
32 GAI_WAIT
33 Perform the look-ups synchronously. The call blocks until the
34 look-ups have completed.
35
36 GAI_NOWAIT
37 Perform the look-ups asynchronously. The call returns immedi‐
38 ately, and the requests are resolved in the background. See the
39 discussion of the sevp argument below.
40
41 The array list specifies the look-up requests to process. The nitems
42 argument specifies the number of elements in list. The requested look-
43 up operations are started in parallel. NULL elements in list are
44 ignored. Each request is described by a gaicb structure, defined as
45 follows:
46
47 struct gaicb {
48 const char *ar_name;
49 const char *ar_service;
50 const struct addrinfo *ar_request;
51 struct addrinfo *ar_result;
52 };
53
54 The elements of this structure correspond to the arguments of getad‐
55 drinfo(3). Thus, ar_name corresponds to the node argument and ar_ser‐
56 vice to the service argument, identifying an Internet host and a ser‐
57 vice. The ar_request element corresponds to the hints argument, speci‐
58 fying the criteria for selecting the returned socket address struc‐
59 tures. Finally, ar_result corresponds to the res argument; you do not
60 need to initialize this element, it will be automatically set when the
61 request is resolved. The addrinfo structure referenced by the last two
62 elements is described in getaddrinfo(3).
63
64 When mode is specified as GAI_NOWAIT, notifications about resolved
65 requests can be obtained by employing the sigevent structure pointed to
66 by the sevp argument. For the definition and general details of this
67 structure, see sigevent(7). The sevp->sigev_notify field can have the
68 following values:
69
70 SIGEV_NONE
71 Don't provide any notification.
72
73 SIGEV_SIGNAL
74 When a look-up completes, generate the signal sigev_signo for
75 the process. See sigevent(7) for general details. The si_code
76 field of the siginfo_t structure will be set to SI_ASYNCNL.
77
78 SIGEV_THREAD
79 When a look-up completes, invoke sigev_notify_function as if it
80 were the start function of a new thread. See sigevent(7) for
81 details.
82
83 For SIGEV_SIGNAL and SIGEV_THREAD, it may be useful to point
84 sevp->sigev_value.sival_ptr to list.
85
86 The gai_suspend() function suspends execution of the calling thread,
87 waiting for the completion of one or more requests in the array list.
88 The nitems argument specifies the size of the array list. The call
89 blocks until one of the following occurs:
90
91 * One or more of the operations in list completes.
92
93 * The call is interrupted by a signal that is caught.
94
95 * The time interval specified in timeout elapses. This argument spec‐
96 ifies a timeout in seconds plus nanoseconds (see nanosleep(2) for
97 details of the timespec structure). If timeout is NULL, then the
98 call blocks indefinitely (until one of the events above occurs).
99
100 No explicit indication of which request was completed is given; you
101 must determine which request(s) have completed by iterating with
102 gai_error() over the list of requests.
103
104 The gai_error() function returns the status of the request req: either
105 EAI_INPROGRESS if the request was not completed yet, 0 if it was han‐
106 dled successfully, or an error code if the request could not be
107 resolved.
108
109 The gai_cancel() function cancels the request req. If the request has
110 been canceled successfully, the error status of the request will be set
111 to EAI_CANCELED and normal asynchronous notification will be performed.
112 The request cannot be canceled if it is currently being processed; in
113 that case, it will be handled as if gai_cancel() has never been called.
114 If req is NULL, an attempt is made to cancel all outstanding requests
115 that the process has made.
116
118 The getaddrinfo_a() function returns 0 if all of the requests have been
119 enqueued successfully, or one of the following nonzero error codes:
120
121 EAI_AGAIN
122 The resources necessary to enqueue the look-up requests were not
123 available. The application may check the error status of each
124 request to determine which ones failed.
125
126 EAI_MEMORY
127 Out of memory.
128
129 EAI_SYSTEM
130 mode is invalid.
131
132 The gai_suspend() function returns 0 if at least one of the listed
133 requests has been completed. Otherwise, it returns one of the follow‐
134 ing nonzero error codes:
135
136 EAI_AGAIN
137 The given timeout expired before any of the requests could be
138 completed.
139
140 EAI_ALLDONE
141 There were no actual requests given to the function.
142
143 EAI_INTR
144 A signal has interrupted the function. Note that this interrup‐
145 tion might have been caused by signal notification of some com‐
146 pleted look-up request.
147
148 The gai_error() function can return EAI_INPROGRESS for an unfinished
149 look-up request, 0 for a successfully completed look-up (as described
150 above), one of the error codes that could be returned by getad‐
151 drinfo(3), or the error code EAI_CANCELED if the request has been can‐
152 celed explicitly before it could be finished.
153
154 The gai_cancel() function can return one of these values:
155
156 EAI_CANCELED
157 The request has been canceled successfully.
158
159 EAI_NOTCANCELED
160 The request has not been canceled.
161
162 EAI_ALLDONE
163 The request has already completed.
164
165 The gai_strerror(3) function translates these error codes to a human
166 readable string, suitable for error reporting.
167
169 For an explanation of the terms used in this section, see
170 attributes(7).
171
172 ┌────────────────────────────────┬───────────────┬─────────┐
173 │Interface │ Attribute │ Value │
174 ├────────────────────────────────┼───────────────┼─────────┤
175 │getaddrinfo_a(), gai_suspend(), │ Thread safety │ MT-Safe │
176 │gai_error(), gai_cancel() │ │ │
177 └────────────────────────────────┴───────────────┴─────────┘
178
180 These functions are GNU extensions; they first appeared in glibc in
181 version 2.2.3.
182
184 The interface of getaddrinfo_a() was modeled after the lio_listio(3)
185 interface.
186
188 Two examples are provided: a simple example that resolves several
189 requests in parallel synchronously, and a complex example showing some
190 of the asynchronous capabilities.
191
192 Synchronous example
193 The program below simply resolves several hostnames in parallel, giving
194 a speed-up compared to resolving the hostnames sequentially using
195 getaddrinfo(3). The program might be used like this:
196
197 $ ./a.out ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
198 ftp.us.kernel.org: 128.30.2.36
199 enoent.linuxfoundation.org: Name or service not known
200 gnu.cz: 87.236.197.13
201
202 Here is the program source code
203
204 #define _GNU_SOURCE
205 #include <netdb.h>
206 #include <stdio.h>
207 #include <stdlib.h>
208 #include <string.h>
209
210 int
211 main(int argc, char *argv[])
212 {
213 int i, ret;
214 struct gaicb *reqs[argc - 1];
215 char host[NI_MAXHOST];
216 struct addrinfo *res;
217
218 if (argc < 2) {
219 fprintf(stderr, "Usage: %s HOST...\n", argv[0]);
220 exit(EXIT_FAILURE);
221 }
222
223 for (i = 0; i < argc - 1; i++) {
224 reqs[i] = malloc(sizeof(*reqs[0]));
225 if (reqs[i] == NULL) {
226 perror("malloc");
227 exit(EXIT_FAILURE);
228 }
229 memset(reqs[i], 0, sizeof(*reqs[0]));
230 reqs[i]->ar_name = argv[i + 1];
231 }
232
233 ret = getaddrinfo_a(GAI_WAIT, reqs, argc - 1, NULL);
234 if (ret != 0) {
235 fprintf(stderr, "getaddrinfo_a() failed: %s\n",
236 gai_strerror(ret));
237 exit(EXIT_FAILURE);
238 }
239
240 for (i = 0; i < argc - 1; i++) {
241 printf("%s: ", reqs[i]->ar_name);
242 ret = gai_error(reqs[i]);
243 if (ret == 0) {
244 res = reqs[i]->ar_result;
245
246 ret = getnameinfo(res->ai_addr, res->ai_addrlen,
247 host, sizeof(host),
248 NULL, 0, NI_NUMERICHOST);
249 if (ret != 0) {
250 fprintf(stderr, "getnameinfo() failed: %s\n",
251 gai_strerror(ret));
252 exit(EXIT_FAILURE);
253 }
254 puts(host);
255
256 } else {
257 puts(gai_strerror(ret));
258 }
259 }
260 exit(EXIT_SUCCESS);
261 }
262
263 Asynchronous example
264 This example shows a simple interactive getaddrinfo_a() front-end. The
265 notification facility is not demonstrated.
266
267 An example session might look like this:
268
269 $ ./a.out
270 > a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
271 > c 2
272 [2] gnu.cz: Request not canceled
273 > w 0 1
274 [00] ftp.us.kernel.org: Finished
275 > l
276 [00] ftp.us.kernel.org: 216.165.129.139
277 [01] enoent.linuxfoundation.org: Processing request in progress
278 [02] gnu.cz: 87.236.197.13
279 > l
280 [00] ftp.us.kernel.org: 216.165.129.139
281 [01] enoent.linuxfoundation.org: Name or service not known
282 [02] gnu.cz: 87.236.197.13
283
284 The program source is as follows:
285
286 #define _GNU_SOURCE
287 #include <netdb.h>
288 #include <stdio.h>
289 #include <stdlib.h>
290 #include <string.h>
291
292 static struct gaicb **reqs = NULL;
293 static int nreqs = 0;
294
295 static char *
296 getcmd(void)
297 {
298 static char buf[256];
299
300 fputs("> ", stdout); fflush(stdout);
301 if (fgets(buf, sizeof(buf), stdin) == NULL)
302 return NULL;
303
304 if (buf[strlen(buf) - 1] == '\n')
305 buf[strlen(buf) - 1] = 0;
306
307 return buf;
308 }
309
310 /* Add requests for specified hostnames */
311 static void
312 add_requests(void)
313 {
314 int nreqs_base = nreqs;
315 char *host;
316 int ret;
317
318 while ((host = strtok(NULL, " "))) {
319 nreqs++;
320 reqs = realloc(reqs, nreqs * sizeof(reqs[0]));
321
322 reqs[nreqs - 1] = calloc(1, sizeof(*reqs[0]));
323 reqs[nreqs - 1]->ar_name = strdup(host);
324 }
325
326 /* Queue nreqs_base..nreqs requests. */
327
328 ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
329 nreqs - nreqs_base, NULL);
330 if (ret) {
331 fprintf(stderr, "getaddrinfo_a() failed: %s\n",
332 gai_strerror(ret));
333 exit(EXIT_FAILURE);
334 }
335 }
336
337 /* Wait until at least one of specified requests completes */
338 static void
339 wait_requests(void)
340 {
341 char *id;
342 int i, ret, n;
343 struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs));
344 /* NULL elements are ignored by gai_suspend(). */
345
346 while ((id = strtok(NULL, " ")) != NULL) {
347 n = atoi(id);
348
349 if (n >= nreqs) {
350 printf("Bad request number: %s\n", id);
351 return;
352 }
353
354 wait_reqs[n] = reqs[n];
355 }
356
357 ret = gai_suspend(wait_reqs, nreqs, NULL);
358 if (ret) {
359 printf("gai_suspend(): %s\n", gai_strerror(ret));
360 return;
361 }
362
363 for (i = 0; i < nreqs; i++) {
364 if (wait_reqs[i] == NULL)
365 continue;
366
367 ret = gai_error(reqs[i]);
368 if (ret == EAI_INPROGRESS)
369 continue;
370
371 printf("[%02d] %s: %s\n", i, reqs[i]->ar_name,
372 ret == 0 ? "Finished" : gai_strerror(ret));
373 }
374 }
375
376 /* Cancel specified requests */
377 static void
378 cancel_requests(void)
379 {
380 char *id;
381 int ret, n;
382
383 while ((id = strtok(NULL, " ")) != NULL) {
384 n = atoi(id);
385
386 if (n >= nreqs) {
387 printf("Bad request number: %s\n", id);
388 return;
389 }
390
391 ret = gai_cancel(reqs[n]);
392 printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name,
393 gai_strerror(ret));
394 }
395 }
396
397 /* List all requests */
398 static void
399 list_requests(void)
400 {
401 int i, ret;
402 char host[NI_MAXHOST];
403 struct addrinfo *res;
404
405 for (i = 0; i < nreqs; i++) {
406 printf("[%02d] %s: ", i, reqs[i]->ar_name);
407 ret = gai_error(reqs[i]);
408
409 if (!ret) {
410 res = reqs[i]->ar_result;
411
412 ret = getnameinfo(res->ai_addr, res->ai_addrlen,
413 host, sizeof(host),
414 NULL, 0, NI_NUMERICHOST);
415 if (ret) {
416 fprintf(stderr, "getnameinfo() failed: %s\n",
417 gai_strerror(ret));
418 exit(EXIT_FAILURE);
419 }
420 puts(host);
421 } else {
422 puts(gai_strerror(ret));
423 }
424 }
425 }
426
427 int
428 main(int argc, char *argv[])
429 {
430 char *cmdline;
431 char *cmd;
432
433 while ((cmdline = getcmd()) != NULL) {
434 cmd = strtok(cmdline, " ");
435
436 if (cmd == NULL) {
437 list_requests();
438 } else {
439 switch (cmd[0]) {
440 case 'a':
441 add_requests();
442 break;
443 case 'w':
444 wait_requests();
445 break;
446 case 'c':
447 cancel_requests();
448 break;
449 case 'l':
450 list_requests();
451 break;
452 default:
453 fprintf(stderr, "Bad command: %c\n", cmd[0]);
454 break;
455 }
456 }
457 }
458 exit(EXIT_SUCCESS);
459 }
460
462 getaddrinfo(3), inet(3), lio_listio(3), hostname(7), ip(7), sigevent(7)
463
465 This page is part of release 5.04 of the Linux man-pages project. A
466 description of the project, information about reporting bugs, and the
467 latest version of this page, can be found at
468 https://www.kernel.org/doc/man-pages/.
469
470
471
472GNU 2019-03-06 GETADDRINFO_A(3)