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(struct gaicb *list[], int nitems,
17 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_CANCELLED and normal asynchronous notification will be per‐
112 formed. The request cannot be canceled if it is currently being pro‐
113 cessed; in that case, it will be handled as if gai_cancel() has never
114 been called. If req is NULL, an attempt is made to cancel all out‐
115 standing requests 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_CANCELLED 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_CANCELLED
157 The request has been canceled successfully.
158
159 EAI_NOTCANCELLED
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 These functions are GNU extensions; they first appeared in glibc in
170 version 2.2.3.
171
173 The interface of getaddrinfo_a() was modeled after the lio_listio(3)
174 interface.
175
177 Two examples are provided: a simple example that resolves several
178 requests in parallel synchronously, and a complex example showing some
179 of the asynchronous capabilities.
180
181 Synchronous example
182 The program below simply resolves several hostnames in parallel, giving
183 a speed-up compared to resolving the hostnames sequentially using
184 getaddrinfo(3). The program might be used like this:
185
186 $ ./a.out ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
187 ftp.us.kernel.org: 128.30.2.36
188 enoent.linuxfoundation.org: Name or service not known
189 gnu.cz: 87.236.197.13
190
191 Here is the program source code
192
193 #define _GNU_SOURCE
194 #include <netdb.h>
195 #include <stdio.h>
196 #include <stdlib.h>
197 #include <string.h>
198
199 int
200 main(int argc, char *argv[])
201 {
202 int i, ret;
203 struct gaicb *reqs[argc - 1];
204 char host[NI_MAXHOST];
205 struct addrinfo *res;
206
207 if (argc < 2) {
208 fprintf(stderr, "Usage: %s HOST...\n", argv[0]);
209 exit(EXIT_FAILURE);
210 }
211
212 for (i = 0; i < argc - 1; i++) {
213 reqs[i] = malloc(sizeof(*reqs[0]));
214 if (reqs[i] == NULL) {
215 perror("malloc");
216 exit(EXIT_FAILURE);
217 }
218 memset(reqs[i], 0, sizeof(*reqs[0]));
219 reqs[i]->ar_name = argv[i + 1];
220 }
221
222 ret = getaddrinfo_a(GAI_WAIT, reqs, argc - 1, NULL);
223 if (ret != 0) {
224 fprintf(stderr, "getaddrinfo_a() failed: %s\n",
225 gai_strerror(ret));
226 exit(EXIT_FAILURE);
227 }
228
229 for (i = 0; i < argc - 1; i++) {
230 printf("%s: ", reqs[i]->ar_name);
231 ret = gai_error(reqs[i]);
232 if (ret == 0) {
233 res = reqs[i]->ar_result;
234
235 ret = getnameinfo(res->ai_addr, res->ai_addrlen,
236 host, sizeof(host),
237 NULL, 0, NI_NUMERICHOST);
238 if (ret != 0) {
239 fprintf(stderr, "getnameinfo() failed: %s\n",
240 gai_strerror(ret));
241 exit(EXIT_FAILURE);
242 }
243 puts(host);
244
245 } else {
246 puts(gai_strerror(ret));
247 }
248 }
249 exit(EXIT_SUCCESS);
250 }
251
252 Asynchronous example
253 This example shows a simple interactive getaddrinfo_a() front-end. The
254 notification facility is not demonstrated.
255
256 An example session might look like this:
257
258 $ ./a.out
259 > a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
260 > c 2
261 [2] gnu.cz: Request not canceled
262 > w 0 1
263 [00] ftp.us.kernel.org: Finished
264 > l
265 [00] ftp.us.kernel.org: 216.165.129.139
266 [01] enoent.linuxfoundation.org: Processing request in progress
267 [02] gnu.cz: 87.236.197.13
268 > l
269 [00] ftp.us.kernel.org: 216.165.129.139
270 [01] enoent.linuxfoundation.org: Name or service not known
271 [02] gnu.cz: 87.236.197.13
272
273 The program source is as follows:
274
275 #define _GNU_SOURCE
276 #include <netdb.h>
277 #include <stdio.h>
278 #include <stdlib.h>
279 #include <string.h>
280
281 static struct gaicb **reqs = NULL;
282 static int nreqs = 0;
283
284 static char *
285 getcmd(void)
286 {
287 static char buf[256];
288
289 fputs("> ", stdout); fflush(stdout);
290 if (fgets(buf, sizeof(buf), stdin) == NULL)
291 return NULL;
292
293 if (buf[strlen(buf) - 1] == '\n')
294 buf[strlen(buf) - 1] = 0;
295
296 return buf;
297 }
298
299 /* Add requests for specified hostnames */
300 static void
301 add_requests(void)
302 {
303 int nreqs_base = nreqs;
304 char *host;
305 int ret;
306
307 while ((host = strtok(NULL, " "))) {
308 nreqs++;
309 reqs = realloc(reqs, nreqs * sizeof(reqs[0]));
310
311 reqs[nreqs - 1] = calloc(1, sizeof(*reqs[0]));
312 reqs[nreqs - 1]->ar_name = strdup(host);
313 }
314
315 /* Queue nreqs_base..nreqs requests. */
316
317 ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
318 nreqs - nreqs_base, NULL);
319 if (ret) {
320 fprintf(stderr, "getaddrinfo_a() failed: %s\n",
321 gai_strerror(ret));
322 exit(EXIT_FAILURE);
323 }
324 }
325
326 /* Wait until at least one of specified requests completes */
327 static void
328 wait_requests(void)
329 {
330 char *id;
331 int i, ret, n;
332 struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs));
333 /* NULL elements are ignored by gai_suspend(). */
334
335 while ((id = strtok(NULL, " ")) != NULL) {
336 n = atoi(id);
337
338 if (n >= nreqs) {
339 printf("Bad request number: %s\n", id);
340 return;
341 }
342
343 wait_reqs[n] = reqs[n];
344 }
345
346 ret = gai_suspend(wait_reqs, nreqs, NULL);
347 if (ret) {
348 printf("gai_suspend(): %s\n", gai_strerror(ret));
349 return;
350 }
351
352 for (i = 0; i < nreqs; i++) {
353 if (wait_reqs[i] == NULL)
354 continue;
355
356 ret = gai_error(reqs[i]);
357 if (ret == EAI_INPROGRESS)
358 continue;
359
360 printf("[%02d] %s: %s\n", i, reqs[i]->ar_name,
361 ret == 0 ? "Finished" : gai_strerror(ret));
362 }
363 }
364
365 /* Cancel specified requests */
366 static void
367 cancel_requests(void)
368 {
369 char *id;
370 int ret, n;
371
372 while ((id = strtok(NULL, " ")) != NULL) {
373 n = atoi(id);
374
375 if (n >= nreqs) {
376 printf("Bad request number: %s\n", id);
377 return;
378 }
379
380 ret = gai_cancel(reqs[n]);
381 printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name,
382 gai_strerror(ret));
383 }
384 }
385
386 /* List all requests */
387 static void
388 list_requests(void)
389 {
390 int i, ret;
391 char host[NI_MAXHOST];
392 struct addrinfo *res;
393
394 for (i = 0; i < nreqs; i++) {
395 printf("[%02d] %s: ", i, reqs[i]->ar_name);
396 ret = gai_error(reqs[i]);
397
398 if (!ret) {
399 res = reqs[i]->ar_result;
400
401 ret = getnameinfo(res->ai_addr, res->ai_addrlen,
402 host, sizeof(host),
403 NULL, 0, NI_NUMERICHOST);
404 if (ret) {
405 fprintf(stderr, "getnameinfo() failed: %s\n",
406 gai_strerror(ret));
407 exit(EXIT_FAILURE);
408 }
409 puts(host);
410 } else {
411 puts(gai_strerror(ret));
412 }
413 }
414 }
415
416 int
417 main(int argc, char *argv[])
418 {
419 char *cmdline;
420 char *cmd;
421
422 while ((cmdline = getcmd()) != NULL) {
423 cmd = strtok(cmdline, " ");
424
425 if (cmd == NULL) {
426 list_requests();
427 } else {
428 switch (cmd[0]) {
429 case 'a':
430 add_requests();
431 break;
432 case 'w':
433 wait_requests();
434 break;
435 case 'c':
436 cancel_requests();
437 break;
438 case 'l':
439 list_requests();
440 break;
441 default:
442 fprintf(stderr, "Bad command: %c\n", cmd[0]);
443 break;
444 }
445 }
446 }
447 exit(EXIT_SUCCESS);
448 }
449
451 getaddrinfo(3), inet(3), lio_listio(3), hostname(7), ip(7), sigevent(7)
452
454 This page is part of release 3.53 of the Linux man-pages project. A
455 description of the project, and information about reporting bugs, can
456 be found at http://www.kernel.org/doc/man-pages/.
457
458
459
460GNU 2010-09-27 GETADDRINFO_A(3)