diff options
Diffstat (limited to '')
-rw-r--r-- | man3/getaddrinfo_a.3 | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/man3/getaddrinfo_a.3 b/man3/getaddrinfo_a.3 new file mode 100644 index 0000000..4b891ab --- /dev/null +++ b/man3/getaddrinfo_a.3 @@ -0,0 +1,612 @@ +'\" t +.\" Copyright (c) 2009 Petr Baudis <pasky@suse.cz> +.\" and clean-ups and additions (C) Copyright 2010 Michael Kerrisk +.\" <mtk.manpages@gmail.com> +.\" +.\" SPDX-License-Identifier: Linux-man-pages-copyleft +.\" +.\" References: http://people.redhat.com/drepper/asynchnl.pdf, +.\" http://www.imperialviolet.org/2005/06/01/asynchronous-dns-lookups-with-glibc.html +.\" +.TH getaddrinfo_a 3 2023-07-20 "Linux man-pages 6.05.01" +.SH NAME +getaddrinfo_a, gai_suspend, gai_error, gai_cancel \- asynchronous +network address and service translation +.SH LIBRARY +Asynchronous name lookup library +.RI ( libanl ", " \-lanl ) +.SH SYNOPSIS +.nf +.BR "#define _GNU_SOURCE" " /* See feature_test_macros(7) */" +.B #include <netdb.h> +.PP +.BI "int getaddrinfo_a(int " mode ", struct gaicb *" list [restrict], +.BI " int " nitems ", struct sigevent *restrict " sevp ); +.BI "int gai_suspend(const struct gaicb *const " list "[], int " nitems , +.BI " const struct timespec *" timeout ); +.PP +.BI "int gai_error(struct gaicb *" req ); +.BI "int gai_cancel(struct gaicb *" req ); +.fi +.SH DESCRIPTION +The +.BR getaddrinfo_a () +function performs the same task as +.BR getaddrinfo (3), +but allows multiple name look-ups to be performed asynchronously, +with optional notification on completion of look-up operations. +.PP +The +.I mode +argument has one of the following values: +.TP +.B GAI_WAIT +Perform the look-ups synchronously. +The call blocks until the look-ups have completed. +.TP +.B GAI_NOWAIT +Perform the look-ups asynchronously. +The call returns immediately, +and the requests are resolved in the background. +See the discussion of the +.I sevp +argument below. +.PP +The array +.I list +specifies the look-up requests to process. +The +.I nitems +argument specifies the number of elements in +.IR list . +The requested look-up operations are started in parallel. +NULL elements in +.I list +are ignored. +Each request is described by a +.I gaicb +structure, defined as follows: +.PP +.in +4n +.EX +struct gaicb { + const char *ar_name; + const char *ar_service; + const struct addrinfo *ar_request; + struct addrinfo *ar_result; +}; +.EE +.in +.PP +The elements of this structure correspond to the arguments of +.BR getaddrinfo (3). +Thus, +.I ar_name +corresponds to the +.I node +argument and +.I ar_service +to the +.I service +argument, identifying an Internet host and a service. +The +.I ar_request +element corresponds to the +.I hints +argument, specifying the criteria for selecting +the returned socket address structures. +Finally, +.I ar_result +corresponds to the +.I res +argument; you do not need to initialize this element, +it will be automatically set when the request +is resolved. +The +.I addrinfo +structure referenced by the last two elements is described in +.BR getaddrinfo (3). +.PP +When +.I mode +is specified as +.BR GAI_NOWAIT , +notifications about resolved requests +can be obtained by employing the +.I sigevent +structure pointed to by the +.I sevp +argument. +For the definition and general details of this structure, see +.BR sigevent (7). +The +.I sevp\->sigev_notify +field can have the following values: +.TP +.B SIGEV_NONE +Don't provide any notification. +.TP +.B SIGEV_SIGNAL +When a look-up completes, generate the signal +.I sigev_signo +for the process. +See +.BR sigevent (7) +for general details. +The +.I si_code +field of the +.I siginfo_t +structure will be set to +.BR SI_ASYNCNL . +.\" si_pid and si_uid are also set, to the values of the calling process, +.\" which doesn't provide useful information, so we'll skip mentioning it. +.TP +.B SIGEV_THREAD +When a look-up completes, invoke +.I sigev_notify_function +as if it were the start function of a new thread. +See +.BR sigevent (7) +for details. +.PP +For +.B SIGEV_SIGNAL +and +.BR SIGEV_THREAD , +it may be useful to point +.I sevp\->sigev_value.sival_ptr +to +.IR list . +.PP +The +.BR gai_suspend () +function suspends execution of the calling thread, +waiting for the completion of one or more requests in the array +.IR list . +The +.I nitems +argument specifies the size of the array +.IR list . +The call blocks until one of the following occurs: +.IP \[bu] 3 +One or more of the operations in +.I list +completes. +.IP \[bu] +The call is interrupted by a signal that is caught. +.IP \[bu] +The time interval specified in +.I timeout +elapses. +This argument specifies a timeout in seconds plus nanoseconds (see +.BR nanosleep (2) +for details of the +.I timespec +structure). +If +.I timeout +is NULL, then the call blocks indefinitely +(until one of the events above occurs). +.PP +No explicit indication of which request was completed is given; +you must determine which request(s) have completed by iterating with +.BR gai_error () +over the list of requests. +.PP +The +.BR gai_error () +function returns the status of the request +.IR req : +either +.B EAI_INPROGRESS +if the request was not completed yet, +0 if it was handled successfully, +or an error code if the request could not be resolved. +.PP +The +.BR gai_cancel () +function cancels the request +.IR req . +If the request has been canceled successfully, +the error status of the request will be set to +.B EAI_CANCELED +and normal asynchronous notification will be performed. +The request cannot be canceled if it is currently being processed; +in that case, it will be handled as if +.BR gai_cancel () +has never been called. +If +.I req +is NULL, an attempt is made to cancel all outstanding requests +that the process has made. +.SH RETURN VALUE +The +.BR getaddrinfo_a () +function returns 0 if all of the requests have been enqueued successfully, +or one of the following nonzero error codes: +.TP +.B EAI_AGAIN +The resources necessary to enqueue the look-up requests were not available. +The application may check the error status of each +request to determine which ones failed. +.TP +.B EAI_MEMORY +Out of memory. +.TP +.B EAI_SYSTEM +.I mode +is invalid. +.PP +The +.BR gai_suspend () +function returns 0 if at least one of the listed requests has been completed. +Otherwise, it returns one of the following nonzero error codes: +.TP +.B EAI_AGAIN +The given timeout expired before any of the requests could be completed. +.TP +.B EAI_ALLDONE +There were no actual requests given to the function. +.TP +.B EAI_INTR +A signal has interrupted the function. +Note that this interruption might have been +caused by signal notification of some completed look-up request. +.PP +The +.BR gai_error () +function can return +.B EAI_INPROGRESS +for an unfinished look-up request, +0 for a successfully completed look-up +(as described above), one of the error codes that could be returned by +.BR getaddrinfo (3), +or the error code +.B EAI_CANCELED +if the request has been canceled explicitly before it could be finished. +.PP +The +.BR gai_cancel () +function can return one of these values: +.TP +.B EAI_CANCELED +The request has been canceled successfully. +.TP +.B EAI_NOTCANCELED +The request has not been canceled. +.TP +.B EAI_ALLDONE +The request has already completed. +.PP +The +.BR gai_strerror (3) +function translates these error codes to a human readable string, +suitable for error reporting. +.SH ATTRIBUTES +For an explanation of the terms used in this section, see +.BR attributes (7). +.TS +allbox; +lbx lb lb +l l l. +Interface Attribute Value +T{ +.na +.nh +.BR getaddrinfo_a (), +.BR gai_suspend (), +.BR gai_error (), +.BR gai_cancel () +T} Thread safety MT-Safe +.TE +.sp 1 +.SH STANDARDS +GNU. +.SH HISTORY +glibc 2.2.3. +.PP +The interface of +.BR getaddrinfo_a () +was modeled after the +.BR lio_listio (3) +interface. +.SH EXAMPLES +Two examples are provided: a simple example that resolves +several requests in parallel synchronously, and a complex example +showing some of the asynchronous capabilities. +.SS Synchronous example +The program below simply resolves several hostnames in parallel, +giving a speed-up compared to resolving the hostnames sequentially using +.BR getaddrinfo (3). +The program might be used like this: +.PP +.in +4n +.EX +$ \fB./a.out mirrors.kernel.org enoent.linuxfoundation.org gnu.org\fP +mirrors.kernel.org: 139.178.88.99 +enoent.linuxfoundation.org: Name or service not known +gnu.org: 209.51.188.116 +.EE +.in +.PP +Here is the program source code +.PP +.\" SRC BEGIN (sync.c) +.EX +#define _GNU_SOURCE +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +\& +int +main(int argc, char *argv[]) +{ + int ret; + struct gaicb *reqs[argc \- 1]; + char host[NI_MAXHOST]; + struct addrinfo *res; +\& + if (argc < 2) { + fprintf(stderr, "Usage: %s HOST...\en", argv[0]); + exit(EXIT_FAILURE); + } +\& + for (size_t i = 0; i < argc \- 1; i++) { + reqs[i] = malloc(sizeof(*reqs[0])); + if (reqs[i] == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(reqs[i], 0, sizeof(*reqs[0])); + reqs[i]\->ar_name = argv[i + 1]; + } +\& + ret = getaddrinfo_a(GAI_WAIT, reqs, argc \- 1, NULL); + if (ret != 0) { + fprintf(stderr, "getaddrinfo_a() failed: %s\en", + gai_strerror(ret)); + exit(EXIT_FAILURE); + } +\& + for (size_t i = 0; i < argc \- 1; i++) { + printf("%s: ", reqs[i]\->ar_name); + ret = gai_error(reqs[i]); + if (ret == 0) { + res = reqs[i]\->ar_result; +\& + ret = getnameinfo(res\->ai_addr, res\->ai_addrlen, + host, sizeof(host), + NULL, 0, NI_NUMERICHOST); + if (ret != 0) { + fprintf(stderr, "getnameinfo() failed: %s\en", + gai_strerror(ret)); + exit(EXIT_FAILURE); + } + puts(host); +\& + } else { + puts(gai_strerror(ret)); + } + } + exit(EXIT_SUCCESS); +} +.EE +.\" SRC END +.SS Asynchronous example +This example shows a simple interactive +.BR getaddrinfo_a () +front-end. +The notification facility is not demonstrated. +.PP +An example session might look like this: +.PP +.in +4n +.EX +$ \fB./a.out\fP +> a mirrors.kernel.org enoent.linuxfoundation.org gnu.org +> c 2 +[2] gnu.org: Request not canceled +> w 0 1 +[00] mirrors.kernel.org: Finished +> l +[00] mirrors.kernel.org: 139.178.88.99 +[01] enoent.linuxfoundation.org: Processing request in progress +[02] gnu.org: 209.51.188.116 +> l +[00] mirrors.kernel.org: 139.178.88.99 +[01] enoent.linuxfoundation.org: Name or service not known +[02] gnu.org: 209.51.188.116 +.EE +.in +.PP +The program source is as follows: +.PP +.\" SRC BEGIN (async.c) +.EX +#define _GNU_SOURCE +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +\& +static struct gaicb **reqs = NULL; +static size_t nreqs = 0; +\& +static char * +getcmd(void) +{ + static char buf[256]; +\& + fputs("> ", stdout); fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) + return NULL; +\& + if (buf[strlen(buf) \- 1] == \[aq]\en\[aq]) + buf[strlen(buf) \- 1] = 0; +\& + return buf; +} +\& +/* Add requests for specified hostnames. */ +static void +add_requests(void) +{ + size_t nreqs_base = nreqs; + char *host; + int ret; +\& + while ((host = strtok(NULL, " "))) { + nreqs++; + reqs = realloc(reqs, sizeof(reqs[0]) * nreqs); +\& + reqs[nreqs \- 1] = calloc(1, sizeof(*reqs[0])); + reqs[nreqs \- 1]\->ar_name = strdup(host); + } +\& + /* Queue nreqs_base..nreqs requests. */ +\& + ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base], + nreqs \- nreqs_base, NULL); + if (ret) { + fprintf(stderr, "getaddrinfo_a() failed: %s\en", + gai_strerror(ret)); + exit(EXIT_FAILURE); + } +} +\& +/* Wait until at least one of specified requests completes. */ +static void +wait_requests(void) +{ + char *id; + int ret; + size_t n; + struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs)); + /* NULL elements are ignored by gai_suspend(). */ +\& + while ((id = strtok(NULL, " ")) != NULL) { + n = atoi(id); +\& + if (n >= nreqs) { + printf("Bad request number: %s\en", id); + return; + } +\& + wait_reqs[n] = reqs[n]; + } +\& + ret = gai_suspend(wait_reqs, nreqs, NULL); + if (ret) { + printf("gai_suspend(): %s\en", gai_strerror(ret)); + return; + } +\& + for (size_t i = 0; i < nreqs; i++) { + if (wait_reqs[i] == NULL) + continue; +\& + ret = gai_error(reqs[i]); + if (ret == EAI_INPROGRESS) + continue; +\& + printf("[%02zu] %s: %s\en", i, reqs[i]\->ar_name, + ret == 0 ? "Finished" : gai_strerror(ret)); + } +} +\& +/* Cancel specified requests. */ +static void +cancel_requests(void) +{ + char *id; + int ret; + size_t n; +\& + while ((id = strtok(NULL, " ")) != NULL) { + n = atoi(id); +\& + if (n >= nreqs) { + printf("Bad request number: %s\en", id); + return; + } +\& + ret = gai_cancel(reqs[n]); + printf("[%s] %s: %s\en", id, reqs[atoi(id)]\->ar_name, + gai_strerror(ret)); + } +} +\& +/* List all requests. */ +static void +list_requests(void) +{ + int ret; + char host[NI_MAXHOST]; + struct addrinfo *res; +\& + for (size_t i = 0; i < nreqs; i++) { + printf("[%02zu] %s: ", i, reqs[i]\->ar_name); + ret = gai_error(reqs[i]); +\& + if (!ret) { + res = reqs[i]\->ar_result; +\& + ret = getnameinfo(res\->ai_addr, res\->ai_addrlen, + host, sizeof(host), + NULL, 0, NI_NUMERICHOST); + if (ret) { + fprintf(stderr, "getnameinfo() failed: %s\en", + gai_strerror(ret)); + exit(EXIT_FAILURE); + } + puts(host); + } else { + puts(gai_strerror(ret)); + } + } +} +\& +int +main(void) +{ + char *cmdline; + char *cmd; +\& + while ((cmdline = getcmd()) != NULL) { + cmd = strtok(cmdline, " "); +\& + if (cmd == NULL) { + list_requests(); + } else { + switch (cmd[0]) { + case \[aq]a\[aq]: + add_requests(); + break; + case \[aq]w\[aq]: + wait_requests(); + break; + case \[aq]c\[aq]: + cancel_requests(); + break; + case \[aq]l\[aq]: + list_requests(); + break; + default: + fprintf(stderr, "Bad command: %c\en", cmd[0]); + break; + } + } + } + exit(EXIT_SUCCESS); +} +.EE +.\" SRC END +.SH SEE ALSO +.BR getaddrinfo (3), +.BR inet (3), +.BR lio_listio (3), +.BR hostname (7), +.BR ip (7), +.BR sigevent (7) |