summaryrefslogtreecommitdiffstats
path: root/man/man3/getaddrinfo_a.3
diff options
context:
space:
mode:
Diffstat (limited to 'man/man3/getaddrinfo_a.3')
-rw-r--r--man/man3/getaddrinfo_a.3645
1 files changed, 645 insertions, 0 deletions
diff --git a/man/man3/getaddrinfo_a.3 b/man/man3/getaddrinfo_a.3
new file mode 100644
index 000000000..e7792fd76
--- /dev/null
+++ b/man/man3/getaddrinfo_a.3
@@ -0,0 +1,645 @@
+'\" 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 (date) "Linux man-pages (unreleased)"
+.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>
+.P
+.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 );
+.P
+.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.
+.P
+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.
+.P
+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:
+.P
+.in +4n
+.EX
+struct gaicb {
+ const char *ar_name;
+ const char *ar_service;
+ const struct addrinfo *ar_request;
+ struct addrinfo *ar_result;
+};
+.EE
+.in
+.P
+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).
+.P
+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 (3type).
+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 (3type)
+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 (3type)
+for details.
+.P
+For
+.B SIGEV_SIGNAL
+and
+.BR SIGEV_THREAD ,
+it may be useful to point
+.I sevp\->sigev_value.sival_ptr
+to
+.IR list .
+.P
+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).
+.P
+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.
+.P
+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.
+.P
+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.
+.P
+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.
+.P
+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.
+.P
+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.
+.P
+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
+.SH STANDARDS
+GNU.
+.SH HISTORY
+glibc 2.2.3.
+.P
+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:
+.P
+.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
+.P
+Here is the program source code
+.P
+.\" SRC BEGIN (sync.c)
+.EX
+#define _GNU_SOURCE
+#include <err.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+\&
+#define MALLOC(n, type) ((type *) reallocarray(NULL, n, sizeof(type)))
+\&
+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(1, struct gaicb);
+ if (reqs[i] == NULL)
+ err(EXIT_FAILURE, "malloc");
+\&
+ 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.
+.P
+An example session might look like this:
+.P
+.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
+.P
+The program source is as follows:
+.P
+.\" SRC BEGIN (async.c)
+.EX
+#define _GNU_SOURCE
+#include <assert.h>
+#include <err.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+\&
+#define CALLOC(n, type) ((type *) calloc(n, sizeof(type)))
+\&
+#define REALLOCF(ptr, n, type) \e
+({ \e
+ static_assert(__builtin_types_compatible_p(typeof(ptr), type *)); \e
+ \e
+ (type *) reallocarrayf(ptr, n, sizeof(type)); \e
+})
+\&
+static struct gaicb **reqs = NULL;
+static size_t nreqs = 0;
+\&
+static inline void *
+reallocarrayf(void *p, size_t nmemb, size_t size)
+{
+ void *q;
+\&
+ q = reallocarray(p, nmemb, size);
+ if (q == NULL && nmemb != 0 && size != 0)
+ free(p);
+ return q;
+}
+\&
+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 = REALLOCF(reqs, nreqs, struct gaicb *);
+ if (reqs == NULL)
+ err(EXIT_FAILURE, "reallocf");
+\&
+ reqs[nreqs \- 1] = CALLOC(1, struct gaicb);
+ if (reqs[nreqs \- 1] == NULL)
+ err(EXIT_FAILURE, "calloc");
+\&
+ 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;
+\&
+ wait_reqs = CALLOC(nreqs, const struct gaicb *);
+ if (wait_reqs == NULL)
+ err(EXIT_FAILURE, "calloc");
+\&
+ /* 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 (3type)