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