1getaddrinfo_a(3) Library Functions 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 Asynchronous name lookup library (libanl, -lanl)
11
13 #define _GNU_SOURCE /* See feature_test_macros(7) */
14 #include <netdb.h>
15
16 int getaddrinfo_a(int mode, struct gaicb *list[restrict],
17 int nitems, struct sigevent *restrict sevp);
18 int gai_suspend(const struct gaicb *const list[], int nitems,
19 const struct timespec *timeout);
20
21 int gai_error(struct gaicb *req);
22 int gai_cancel(struct gaicb *req);
23
25 The getaddrinfo_a() function performs the same task as getaddrinfo(3),
26 but allows multiple name look-ups to be performed asynchronously, with
27 optional notification on completion of look-up operations.
28
29 The mode argument has one of the following values:
30
31 GAI_WAIT
32 Perform the look-ups synchronously. The call blocks until the
33 look-ups have completed.
34
35 GAI_NOWAIT
36 Perform the look-ups asynchronously. The call returns immedi‐
37 ately, and the requests are resolved in the background. See the
38 discussion of the sevp argument below.
39
40 The array list specifies the look-up requests to process. The nitems
41 argument specifies the number of elements in list. The requested look-
42 up operations are started in parallel. NULL elements in list are ig‐
43 nored. Each request is described by a gaicb structure, defined as fol‐
44 lows:
45
46 struct gaicb {
47 const char *ar_name;
48 const char *ar_service;
49 const struct addrinfo *ar_request;
50 struct addrinfo *ar_result;
51 };
52
53 The elements of this structure correspond to the arguments of getad‐
54 drinfo(3). Thus, ar_name corresponds to the node argument and ar_ser‐
55 vice to the service argument, identifying an Internet host and a ser‐
56 vice. The ar_request element corresponds to the hints argument, speci‐
57 fying the criteria for selecting the returned socket address struc‐
58 tures. Finally, ar_result corresponds to the res argument; you do not
59 need to initialize this element, it will be automatically set when the
60 request is resolved. The addrinfo structure referenced by the last two
61 elements is described in getaddrinfo(3).
62
63 When mode is specified as GAI_NOWAIT, notifications about resolved re‐
64 quests can be obtained by employing the sigevent structure pointed to
65 by the sevp argument. For the definition and general details of this
66 structure, see sigevent(7). The sevp->sigev_notify field can have the
67 following values:
68
69 SIGEV_NONE
70 Don't provide any notification.
71
72 SIGEV_SIGNAL
73 When a look-up completes, generate the signal sigev_signo for
74 the process. See sigevent(7) for general details. The si_code
75 field of the siginfo_t structure will be set to SI_ASYNCNL.
76
77 SIGEV_THREAD
78 When a look-up completes, invoke sigev_notify_function as if it
79 were the start function of a new thread. See sigevent(7) for
80 details.
81
82 For SIGEV_SIGNAL and SIGEV_THREAD, it may be useful to point
83 sevp->sigev_value.sival_ptr to list.
84
85 The gai_suspend() function suspends execution of the calling thread,
86 waiting for the completion of one or more requests in the array list.
87 The nitems argument specifies the size of the array list. The call
88 blocks until one of the following occurs:
89
90 • One or more of the operations in list completes.
91
92 • The call is interrupted by a signal that is caught.
93
94 • The time interval specified in timeout elapses. This argument spec‐
95 ifies a timeout in seconds plus nanoseconds (see nanosleep(2) for
96 details of the timespec structure). If timeout is NULL, then the
97 call blocks indefinitely (until one of the events above occurs).
98
99 No explicit indication of which request was completed is given; you
100 must determine which request(s) have completed by iterating with
101 gai_error() over the list of requests.
102
103 The gai_error() function returns the status of the request req: either
104 EAI_INPROGRESS if the request was not completed yet, 0 if it was han‐
105 dled successfully, or an error code if the request could not be re‐
106 solved.
107
108 The gai_cancel() function cancels the request req. If the request has
109 been canceled successfully, the error status of the request will be set
110 to EAI_CANCELED and normal asynchronous notification will be performed.
111 The request cannot be canceled if it is currently being processed; in
112 that case, it will be handled as if gai_cancel() has never been called.
113 If req is NULL, an attempt is made to cancel all outstanding requests
114 that the process has made.
115
117 The getaddrinfo_a() function returns 0 if all of the requests have been
118 enqueued successfully, or one of the following nonzero error codes:
119
120 EAI_AGAIN
121 The resources necessary to enqueue the look-up requests were not
122 available. The application may check the error status of each
123 request to determine which ones failed.
124
125 EAI_MEMORY
126 Out of memory.
127
128 EAI_SYSTEM
129 mode is invalid.
130
131 The gai_suspend() function returns 0 if at least one of the listed re‐
132 quests has been completed. Otherwise, it returns one of the following
133 nonzero error codes:
134
135 EAI_AGAIN
136 The given timeout expired before any of the requests could be
137 completed.
138
139 EAI_ALLDONE
140 There were no actual requests given to the function.
141
142 EAI_INTR
143 A signal has interrupted the function. Note that this interrup‐
144 tion might have been caused by signal notification of some com‐
145 pleted look-up request.
146
147 The gai_error() function can return EAI_INPROGRESS for an unfinished
148 look-up request, 0 for a successfully completed look-up (as described
149 above), one of the error codes that could be returned by getad‐
150 drinfo(3), or the error code EAI_CANCELED if the request has been can‐
151 celed explicitly before it could be finished.
152
153 The gai_cancel() function can return one of these values:
154
155 EAI_CANCELED
156 The request has been canceled successfully.
157
158 EAI_NOTCANCELED
159 The request has not been canceled.
160
161 EAI_ALLDONE
162 The request has already completed.
163
164 The gai_strerror(3) function translates these error codes to a human
165 readable string, suitable for error reporting.
166
168 For an explanation of the terms used in this section, see at‐
169 tributes(7).
170
171 ┌────────────────────────────────────────────┬───────────────┬─────────┐
172 │Interface │ Attribute │ Value │
173 ├────────────────────────────────────────────┼───────────────┼─────────┤
174 │getaddrinfo_a(), gai_suspend(), │ Thread safety │ MT-Safe │
175 │gai_error(), gai_cancel() │ │ │
176 └────────────────────────────────────────────┴───────────────┴─────────┘
177
179 GNU.
180
182 glibc 2.2.3.
183
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 mirrors.kernel.org enoent.linuxfoundation.org gnu.org
198 mirrors.kernel.org: 139.178.88.99
199 enoent.linuxfoundation.org: Name or service not known
200 gnu.org: 209.51.188.116
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 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 (size_t 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 (size_t 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 mirrors.kernel.org enoent.linuxfoundation.org gnu.org
271 > c 2
272 [2] gnu.org: Request not canceled
273 > w 0 1
274 [00] mirrors.kernel.org: Finished
275 > l
276 [00] mirrors.kernel.org: 139.178.88.99
277 [01] enoent.linuxfoundation.org: Processing request in progress
278 [02] gnu.org: 209.51.188.116
279 > l
280 [00] mirrors.kernel.org: 139.178.88.99
281 [01] enoent.linuxfoundation.org: Name or service not known
282 [02] gnu.org: 209.51.188.116
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 size_t 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 size_t nreqs_base = nreqs;
315 char *host;
316 int ret;
317
318 while ((host = strtok(NULL, " "))) {
319 nreqs++;
320 reqs = realloc(reqs, sizeof(reqs[0]) * nreqs);
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 ret;
343 size_t n;
344 struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs));
345 /* NULL elements are ignored by gai_suspend(). */
346
347 while ((id = strtok(NULL, " ")) != NULL) {
348 n = atoi(id);
349
350 if (n >= nreqs) {
351 printf("Bad request number: %s\n", id);
352 return;
353 }
354
355 wait_reqs[n] = reqs[n];
356 }
357
358 ret = gai_suspend(wait_reqs, nreqs, NULL);
359 if (ret) {
360 printf("gai_suspend(): %s\n", gai_strerror(ret));
361 return;
362 }
363
364 for (size_t i = 0; i < nreqs; i++) {
365 if (wait_reqs[i] == NULL)
366 continue;
367
368 ret = gai_error(reqs[i]);
369 if (ret == EAI_INPROGRESS)
370 continue;
371
372 printf("[%02zu] %s: %s\n", i, reqs[i]->ar_name,
373 ret == 0 ? "Finished" : gai_strerror(ret));
374 }
375 }
376
377 /* Cancel specified requests. */
378 static void
379 cancel_requests(void)
380 {
381 char *id;
382 int ret;
383 size_t n;
384
385 while ((id = strtok(NULL, " ")) != NULL) {
386 n = atoi(id);
387
388 if (n >= nreqs) {
389 printf("Bad request number: %s\n", id);
390 return;
391 }
392
393 ret = gai_cancel(reqs[n]);
394 printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name,
395 gai_strerror(ret));
396 }
397 }
398
399 /* List all requests. */
400 static void
401 list_requests(void)
402 {
403 int ret;
404 char host[NI_MAXHOST];
405 struct addrinfo *res;
406
407 for (size_t i = 0; i < nreqs; i++) {
408 printf("[%02zu] %s: ", i, reqs[i]->ar_name);
409 ret = gai_error(reqs[i]);
410
411 if (!ret) {
412 res = reqs[i]->ar_result;
413
414 ret = getnameinfo(res->ai_addr, res->ai_addrlen,
415 host, sizeof(host),
416 NULL, 0, NI_NUMERICHOST);
417 if (ret) {
418 fprintf(stderr, "getnameinfo() failed: %s\n",
419 gai_strerror(ret));
420 exit(EXIT_FAILURE);
421 }
422 puts(host);
423 } else {
424 puts(gai_strerror(ret));
425 }
426 }
427 }
428
429 int
430 main(void)
431 {
432 char *cmdline;
433 char *cmd;
434
435 while ((cmdline = getcmd()) != NULL) {
436 cmd = strtok(cmdline, " ");
437
438 if (cmd == NULL) {
439 list_requests();
440 } else {
441 switch (cmd[0]) {
442 case 'a':
443 add_requests();
444 break;
445 case 'w':
446 wait_requests();
447 break;
448 case 'c':
449 cancel_requests();
450 break;
451 case 'l':
452 list_requests();
453 break;
454 default:
455 fprintf(stderr, "Bad command: %c\n", cmd[0]);
456 break;
457 }
458 }
459 }
460 exit(EXIT_SUCCESS);
461 }
462
464 getaddrinfo(3), inet(3), lio_listio(3), hostname(7), ip(7), sigevent(7)
465
466
467
468Linux man-pages 6.05 2023-07-20 getaddrinfo_a(3)