1getaddrinfo_a(3)           Library Functions Manual           getaddrinfo_a(3)
2
3
4

NAME

6       getaddrinfo_a,  gai_suspend,  gai_error, gai_cancel - asynchronous net‐
7       work address and service translation
8

LIBRARY

10       Asynchronous name lookup library (libanl, -lanl)
11

SYNOPSIS

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

DESCRIPTION

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

RETURN VALUE

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

ATTRIBUTES

168       For an  explanation  of  the  terms  used  in  this  section,  see  at‐
169       tributes(7).
170
171       ┌────────────────────────────────────────────┬───────────────┬─────────┐
172Interface                                   Attribute     Value   
173       ├────────────────────────────────────────────┼───────────────┼─────────┤
174getaddrinfo_a(), gai_suspend(),             │ Thread safety │ MT-Safe │
175gai_error(), gai_cancel()                   │               │         │
176       └────────────────────────────────────────────┴───────────────┴─────────┘
177

STANDARDS

179       GNU.
180

HISTORY

182       glibc 2.2.3.
183
184       The interface of getaddrinfo_a() was modeled  after  the  lio_listio(3)
185       interface.
186

EXAMPLES

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

SEE ALSO

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)
Impressum