mirror of https://github.com/mkerrisk/man-pages
gai_cancel.3, gai_error.3, gai_suspend.3: Make these into links
In the previous release, these files were accidentally made copies of getaddrinfo_a.3, instead of being made as link files. Reported-by: Sam Varshavchik <mrsam@courier-mta.com> Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
parent
ebd05fecfe
commit
cf97e6eff5
|
@ -1,606 +1 @@
|
||||||
.\" Copyright (c) 2009 Petr Baudis <pasky@suse.cz>
|
.so man3/getaddrinfo_a.3
|
||||||
.\" and clean-ups and additions (C) 2010 Michael Kerrisk <mtk.manpages@gmail.com>
|
|
||||||
.\"
|
|
||||||
.\" Permission is granted to make and distribute verbatim copies of this
|
|
||||||
.\" manual provided the copyright notice and this permission notice are
|
|
||||||
.\" preserved on all copies.
|
|
||||||
.\"
|
|
||||||
.\" Permission is granted to copy and distribute modified versions of this
|
|
||||||
.\" manual under the conditions for verbatim copying, provided that the
|
|
||||||
.\" entire resulting derived work is distributed under the terms of a
|
|
||||||
.\" permission notice identical to this one.
|
|
||||||
.\"
|
|
||||||
.\" Since the Linux kernel and libraries are constantly changing, this
|
|
||||||
.\" manual page may be incorrect or out-of-date. The author(s) assume no
|
|
||||||
.\" responsibility for errors or omissions, or for damages resulting from
|
|
||||||
.\" the use of the information contained herein. The author(s) may not
|
|
||||||
.\" have taken the same level of care in the production of this manual,
|
|
||||||
.\" which is licensed free of charge, as they might when working
|
|
||||||
.\" professionally.
|
|
||||||
.\"
|
|
||||||
.\" Formatted or processed versions of this manual, if unaccompanied by
|
|
||||||
.\" the source, must acknowledge the copyright and authors of this work.
|
|
||||||
.\"
|
|
||||||
.\" 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 2010-09-27 "GNU" "Linux Programmer's Manual"
|
|
||||||
.SH NAME
|
|
||||||
getaddrinfo_a, gai_suspend, gai_error, gai_cancel \- asynchronous
|
|
||||||
network address and service translation
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.nf
|
|
||||||
.B #define _GNU_SOURCE
|
|
||||||
.B #include <netdb.h>
|
|
||||||
.sp
|
|
||||||
.BI "int getaddrinfo_a(int " "mode" ", struct gaicb *" "list[]" ,
|
|
||||||
.BI " int " "nitems" ", struct sigevent *" "sevp" );
|
|
||||||
.sp
|
|
||||||
.BI "int gai_suspend(struct gaicb *" "list[]" ", int " "nitems" ,
|
|
||||||
.BI " struct timespec *" "timeout" );
|
|
||||||
.sp
|
|
||||||
.BI "int gai_error(struct gaicb *" "req" );
|
|
||||||
.sp
|
|
||||||
.BI "int gai_cancel(struct gaicb *" "req" );
|
|
||||||
.sp
|
|
||||||
Link with \fI\-lanl\fP.
|
|
||||||
.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.
|
|
||||||
|
|
||||||
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:
|
|
||||||
.sp
|
|
||||||
.in +4n
|
|
||||||
.nf
|
|
||||||
struct gaicb {
|
|
||||||
const char *ar_name;
|
|
||||||
const char *ar_service;
|
|
||||||
const struct addrinfo *ar_request;
|
|
||||||
struct addrinfo *ar_result;
|
|
||||||
};
|
|
||||||
.fi
|
|
||||||
.in
|
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
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
|
|
||||||
.BR SIGEV_NONE
|
|
||||||
Don't provide any notification.
|
|
||||||
.TP
|
|
||||||
.BR 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
|
|
||||||
.BR 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
|
|
||||||
.BR SIGEV_SIGNAL
|
|
||||||
and
|
|
||||||
.BR SIGEV_THREAD ,
|
|
||||||
it may be useful to point
|
|
||||||
.IR sevp\->sigev_value.sival_ptr
|
|
||||||
to
|
|
||||||
.IR list .
|
|
||||||
|
|
||||||
The
|
|
||||||
.BR gai_suspend ()
|
|
||||||
function suspends execution of the calling thread,
|
|
||||||
waiting for the completion of one or more requests in the array
|
|
||||||
.ID list .
|
|
||||||
The
|
|
||||||
.I nitems
|
|
||||||
argument specifies the size of the array
|
|
||||||
.IR list .
|
|
||||||
The call blocks until one of the following occurs:
|
|
||||||
.IP * 3
|
|
||||||
One or more of the operations in
|
|
||||||
.I list
|
|
||||||
completes.
|
|
||||||
.IP *
|
|
||||||
The call is interrupted by a signal that is caught.
|
|
||||||
.IP *
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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_CANCELLED
|
|
||||||
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_CANCELLED
|
|
||||||
if the request has been canceled explicitly before it could be finished.
|
|
||||||
|
|
||||||
The
|
|
||||||
.BR gai_cancel ()
|
|
||||||
function can return one of these values:
|
|
||||||
.TP
|
|
||||||
.B EAI_CANCELLED
|
|
||||||
The request has been canceled successfully.
|
|
||||||
.TP
|
|
||||||
.B EAI_NOTCANCELLED
|
|
||||||
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 "CONFORMING TO"
|
|
||||||
These functions are GNU extensions;
|
|
||||||
they first appeared in glibc in version 2.2.3.
|
|
||||||
.SH NOTES
|
|
||||||
The interface of
|
|
||||||
.BR getaddrinfo_a ()
|
|
||||||
was modeled after the
|
|
||||||
.BR lio_listio (3)
|
|
||||||
interface.
|
|
||||||
.SH EXAMPLE
|
|
||||||
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:
|
|
||||||
.in +4n
|
|
||||||
.nf
|
|
||||||
|
|
||||||
$ \fB./a.out ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz\fP
|
|
||||||
ftp.us.kernel.org: 128.30.2.36
|
|
||||||
enoent.linuxfoundation.org: Name or service not known
|
|
||||||
gnu.cz: 87.236.197.13
|
|
||||||
.fi
|
|
||||||
.in
|
|
||||||
.PP
|
|
||||||
Here is the program source code
|
|
||||||
.nf
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
struct gaicb *reqs[argc \- 1];
|
|
||||||
char host[NI_MAXHOST];
|
|
||||||
struct addrinfo *res;
|
|
||||||
|
|
||||||
if (argc < 2) {
|
|
||||||
fprintf(stderr, "Usage: %s HOST...\\n", argv[0]);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
puts(host);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
puts(gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
.fi
|
|
||||||
|
|
||||||
.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 like this:
|
|
||||||
.in +4n
|
|
||||||
.nf
|
|
||||||
|
|
||||||
$ \fB./a.out\fP
|
|
||||||
> a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
|
|
||||||
> c 2
|
|
||||||
[2] gnu.cz: Request not canceled
|
|
||||||
> w 0 1
|
|
||||||
[00] ftp.us.kernel.org: Finished
|
|
||||||
> l
|
|
||||||
[00] ftp.us.kernel.org: 216.165.129.139
|
|
||||||
[01] enoent.linuxfoundation.org: Processing request in progress
|
|
||||||
[02] gnu.cz: 87.236.197.13
|
|
||||||
> l
|
|
||||||
[00] ftp.us.kernel.org: 216.165.129.139
|
|
||||||
[01] enoent.linuxfoundation.org: Name or service not known
|
|
||||||
[02] gnu.cz: 87.236.197.13
|
|
||||||
.fi
|
|
||||||
.in
|
|
||||||
.PP
|
|
||||||
The program source goes as follows:
|
|
||||||
|
|
||||||
\&
|
|
||||||
.nf
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static struct gaicb **reqs = NULL;
|
|
||||||
static int 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\\n\(aq)
|
|
||||||
buf[strlen(buf) \- 1] = 0;
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add requests for specified hostnames */
|
|
||||||
static void
|
|
||||||
add_requests(void)
|
|
||||||
{
|
|
||||||
int nreqs_base = nreqs;
|
|
||||||
char *host;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while ((host = strtok(NULL, " "))) {
|
|
||||||
nreqs++;
|
|
||||||
reqs = realloc(reqs, nreqs * sizeof(reqs[0]));
|
|
||||||
|
|
||||||
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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait until at least one of specified requests completes */
|
|
||||||
static void
|
|
||||||
wait_requests(void)
|
|
||||||
{
|
|
||||||
char *id;
|
|
||||||
int i, ret, 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\\n", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_reqs[n] = reqs[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gai_suspend(wait_reqs, nreqs, NULL);
|
|
||||||
if (ret) {
|
|
||||||
printf("gai_suspend(): %s\\n", gai_strerror(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nreqs; i++) {
|
|
||||||
if (wait_reqs[i] == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = gai_error(reqs[i]);
|
|
||||||
if (ret == EAI_INPROGRESS)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
printf("[%02d] %s: %s\\n", i, reqs[i]\->ar_name,
|
|
||||||
ret == 0 ? "Finished" : gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cancel specified requests */
|
|
||||||
static void
|
|
||||||
cancel_requests(void)
|
|
||||||
{
|
|
||||||
char *id;
|
|
||||||
int ret, n;
|
|
||||||
|
|
||||||
while ((id = strtok(NULL, " ")) != NULL) {
|
|
||||||
n = atoi(id);
|
|
||||||
|
|
||||||
if (n >= nreqs) {
|
|
||||||
printf("Bad request number: %s\\n", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gai_cancel(reqs[n]);
|
|
||||||
printf("[%s] %s: %s\\n", id, reqs[atoi(id)]\->ar_name,
|
|
||||||
gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List all requests */
|
|
||||||
static void
|
|
||||||
list_requests(void)
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
char host[NI_MAXHOST];
|
|
||||||
struct addrinfo *res;
|
|
||||||
|
|
||||||
for (i = 0; i < nreqs; i++) {
|
|
||||||
printf("[%02d] %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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
puts(host);
|
|
||||||
} else {
|
|
||||||
puts(gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
char *cmdline;
|
|
||||||
char *cmd;
|
|
||||||
|
|
||||||
while ((cmdline = getcmd()) != NULL) {
|
|
||||||
cmd = strtok(cmdline, " ");
|
|
||||||
|
|
||||||
if (cmd == NULL) {
|
|
||||||
list_requests();
|
|
||||||
} else {
|
|
||||||
switch (cmd[0]) {
|
|
||||||
case \(aqa\(aq:
|
|
||||||
add_requests();
|
|
||||||
break;
|
|
||||||
case \(aqw\(aq:
|
|
||||||
wait_requests();
|
|
||||||
break;
|
|
||||||
case \(aqc\(aq:
|
|
||||||
cancel_requests();
|
|
||||||
break;
|
|
||||||
case \(aql\(aq:
|
|
||||||
list_requests();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Bad command: %c\\n", cmd[0]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
.fi
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
.BR getaddrinfo (3),
|
|
||||||
.BR inet (3),
|
|
||||||
.BR lio_listio (3),
|
|
||||||
.BR hostname (7),
|
|
||||||
.BR ip (7),
|
|
||||||
.BR sigevent (7)
|
|
||||||
|
|
607
man3/gai_error.3
607
man3/gai_error.3
|
@ -1,606 +1 @@
|
||||||
.\" Copyright (c) 2009 Petr Baudis <pasky@suse.cz>
|
.so man3/getaddrinfo_a.3
|
||||||
.\" and clean-ups and additions (C) 2010 Michael Kerrisk <mtk.manpages@gmail.com>
|
|
||||||
.\"
|
|
||||||
.\" Permission is granted to make and distribute verbatim copies of this
|
|
||||||
.\" manual provided the copyright notice and this permission notice are
|
|
||||||
.\" preserved on all copies.
|
|
||||||
.\"
|
|
||||||
.\" Permission is granted to copy and distribute modified versions of this
|
|
||||||
.\" manual under the conditions for verbatim copying, provided that the
|
|
||||||
.\" entire resulting derived work is distributed under the terms of a
|
|
||||||
.\" permission notice identical to this one.
|
|
||||||
.\"
|
|
||||||
.\" Since the Linux kernel and libraries are constantly changing, this
|
|
||||||
.\" manual page may be incorrect or out-of-date. The author(s) assume no
|
|
||||||
.\" responsibility for errors or omissions, or for damages resulting from
|
|
||||||
.\" the use of the information contained herein. The author(s) may not
|
|
||||||
.\" have taken the same level of care in the production of this manual,
|
|
||||||
.\" which is licensed free of charge, as they might when working
|
|
||||||
.\" professionally.
|
|
||||||
.\"
|
|
||||||
.\" Formatted or processed versions of this manual, if unaccompanied by
|
|
||||||
.\" the source, must acknowledge the copyright and authors of this work.
|
|
||||||
.\"
|
|
||||||
.\" 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 2010-09-27 "GNU" "Linux Programmer's Manual"
|
|
||||||
.SH NAME
|
|
||||||
getaddrinfo_a, gai_suspend, gai_error, gai_cancel \- asynchronous
|
|
||||||
network address and service translation
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.nf
|
|
||||||
.B #define _GNU_SOURCE
|
|
||||||
.B #include <netdb.h>
|
|
||||||
.sp
|
|
||||||
.BI "int getaddrinfo_a(int " "mode" ", struct gaicb *" "list[]" ,
|
|
||||||
.BI " int " "nitems" ", struct sigevent *" "sevp" );
|
|
||||||
.sp
|
|
||||||
.BI "int gai_suspend(struct gaicb *" "list[]" ", int " "nitems" ,
|
|
||||||
.BI " struct timespec *" "timeout" );
|
|
||||||
.sp
|
|
||||||
.BI "int gai_error(struct gaicb *" "req" );
|
|
||||||
.sp
|
|
||||||
.BI "int gai_cancel(struct gaicb *" "req" );
|
|
||||||
.sp
|
|
||||||
Link with \fI\-lanl\fP.
|
|
||||||
.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.
|
|
||||||
|
|
||||||
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:
|
|
||||||
.sp
|
|
||||||
.in +4n
|
|
||||||
.nf
|
|
||||||
struct gaicb {
|
|
||||||
const char *ar_name;
|
|
||||||
const char *ar_service;
|
|
||||||
const struct addrinfo *ar_request;
|
|
||||||
struct addrinfo *ar_result;
|
|
||||||
};
|
|
||||||
.fi
|
|
||||||
.in
|
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
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
|
|
||||||
.BR SIGEV_NONE
|
|
||||||
Don't provide any notification.
|
|
||||||
.TP
|
|
||||||
.BR 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
|
|
||||||
.BR 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
|
|
||||||
.BR SIGEV_SIGNAL
|
|
||||||
and
|
|
||||||
.BR SIGEV_THREAD ,
|
|
||||||
it may be useful to point
|
|
||||||
.IR sevp\->sigev_value.sival_ptr
|
|
||||||
to
|
|
||||||
.IR list .
|
|
||||||
|
|
||||||
The
|
|
||||||
.BR gai_suspend ()
|
|
||||||
function suspends execution of the calling thread,
|
|
||||||
waiting for the completion of one or more requests in the array
|
|
||||||
.ID list .
|
|
||||||
The
|
|
||||||
.I nitems
|
|
||||||
argument specifies the size of the array
|
|
||||||
.IR list .
|
|
||||||
The call blocks until one of the following occurs:
|
|
||||||
.IP * 3
|
|
||||||
One or more of the operations in
|
|
||||||
.I list
|
|
||||||
completes.
|
|
||||||
.IP *
|
|
||||||
The call is interrupted by a signal that is caught.
|
|
||||||
.IP *
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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_CANCELLED
|
|
||||||
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_CANCELLED
|
|
||||||
if the request has been canceled explicitly before it could be finished.
|
|
||||||
|
|
||||||
The
|
|
||||||
.BR gai_cancel ()
|
|
||||||
function can return one of these values:
|
|
||||||
.TP
|
|
||||||
.B EAI_CANCELLED
|
|
||||||
The request has been canceled successfully.
|
|
||||||
.TP
|
|
||||||
.B EAI_NOTCANCELLED
|
|
||||||
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 "CONFORMING TO"
|
|
||||||
These functions are GNU extensions;
|
|
||||||
they first appeared in glibc in version 2.2.3.
|
|
||||||
.SH NOTES
|
|
||||||
The interface of
|
|
||||||
.BR getaddrinfo_a ()
|
|
||||||
was modeled after the
|
|
||||||
.BR lio_listio (3)
|
|
||||||
interface.
|
|
||||||
.SH EXAMPLE
|
|
||||||
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:
|
|
||||||
.in +4n
|
|
||||||
.nf
|
|
||||||
|
|
||||||
$ \fB./a.out ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz\fP
|
|
||||||
ftp.us.kernel.org: 128.30.2.36
|
|
||||||
enoent.linuxfoundation.org: Name or service not known
|
|
||||||
gnu.cz: 87.236.197.13
|
|
||||||
.fi
|
|
||||||
.in
|
|
||||||
.PP
|
|
||||||
Here is the program source code
|
|
||||||
.nf
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
struct gaicb *reqs[argc \- 1];
|
|
||||||
char host[NI_MAXHOST];
|
|
||||||
struct addrinfo *res;
|
|
||||||
|
|
||||||
if (argc < 2) {
|
|
||||||
fprintf(stderr, "Usage: %s HOST...\\n", argv[0]);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
puts(host);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
puts(gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
.fi
|
|
||||||
|
|
||||||
.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 like this:
|
|
||||||
.in +4n
|
|
||||||
.nf
|
|
||||||
|
|
||||||
$ \fB./a.out\fP
|
|
||||||
> a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
|
|
||||||
> c 2
|
|
||||||
[2] gnu.cz: Request not canceled
|
|
||||||
> w 0 1
|
|
||||||
[00] ftp.us.kernel.org: Finished
|
|
||||||
> l
|
|
||||||
[00] ftp.us.kernel.org: 216.165.129.139
|
|
||||||
[01] enoent.linuxfoundation.org: Processing request in progress
|
|
||||||
[02] gnu.cz: 87.236.197.13
|
|
||||||
> l
|
|
||||||
[00] ftp.us.kernel.org: 216.165.129.139
|
|
||||||
[01] enoent.linuxfoundation.org: Name or service not known
|
|
||||||
[02] gnu.cz: 87.236.197.13
|
|
||||||
.fi
|
|
||||||
.in
|
|
||||||
.PP
|
|
||||||
The program source goes as follows:
|
|
||||||
|
|
||||||
\&
|
|
||||||
.nf
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static struct gaicb **reqs = NULL;
|
|
||||||
static int 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\\n\(aq)
|
|
||||||
buf[strlen(buf) \- 1] = 0;
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add requests for specified hostnames */
|
|
||||||
static void
|
|
||||||
add_requests(void)
|
|
||||||
{
|
|
||||||
int nreqs_base = nreqs;
|
|
||||||
char *host;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while ((host = strtok(NULL, " "))) {
|
|
||||||
nreqs++;
|
|
||||||
reqs = realloc(reqs, nreqs * sizeof(reqs[0]));
|
|
||||||
|
|
||||||
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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait until at least one of specified requests completes */
|
|
||||||
static void
|
|
||||||
wait_requests(void)
|
|
||||||
{
|
|
||||||
char *id;
|
|
||||||
int i, ret, 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\\n", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_reqs[n] = reqs[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gai_suspend(wait_reqs, nreqs, NULL);
|
|
||||||
if (ret) {
|
|
||||||
printf("gai_suspend(): %s\\n", gai_strerror(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nreqs; i++) {
|
|
||||||
if (wait_reqs[i] == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = gai_error(reqs[i]);
|
|
||||||
if (ret == EAI_INPROGRESS)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
printf("[%02d] %s: %s\\n", i, reqs[i]\->ar_name,
|
|
||||||
ret == 0 ? "Finished" : gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cancel specified requests */
|
|
||||||
static void
|
|
||||||
cancel_requests(void)
|
|
||||||
{
|
|
||||||
char *id;
|
|
||||||
int ret, n;
|
|
||||||
|
|
||||||
while ((id = strtok(NULL, " ")) != NULL) {
|
|
||||||
n = atoi(id);
|
|
||||||
|
|
||||||
if (n >= nreqs) {
|
|
||||||
printf("Bad request number: %s\\n", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gai_cancel(reqs[n]);
|
|
||||||
printf("[%s] %s: %s\\n", id, reqs[atoi(id)]\->ar_name,
|
|
||||||
gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List all requests */
|
|
||||||
static void
|
|
||||||
list_requests(void)
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
char host[NI_MAXHOST];
|
|
||||||
struct addrinfo *res;
|
|
||||||
|
|
||||||
for (i = 0; i < nreqs; i++) {
|
|
||||||
printf("[%02d] %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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
puts(host);
|
|
||||||
} else {
|
|
||||||
puts(gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
char *cmdline;
|
|
||||||
char *cmd;
|
|
||||||
|
|
||||||
while ((cmdline = getcmd()) != NULL) {
|
|
||||||
cmd = strtok(cmdline, " ");
|
|
||||||
|
|
||||||
if (cmd == NULL) {
|
|
||||||
list_requests();
|
|
||||||
} else {
|
|
||||||
switch (cmd[0]) {
|
|
||||||
case \(aqa\(aq:
|
|
||||||
add_requests();
|
|
||||||
break;
|
|
||||||
case \(aqw\(aq:
|
|
||||||
wait_requests();
|
|
||||||
break;
|
|
||||||
case \(aqc\(aq:
|
|
||||||
cancel_requests();
|
|
||||||
break;
|
|
||||||
case \(aql\(aq:
|
|
||||||
list_requests();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Bad command: %c\\n", cmd[0]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
.fi
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
.BR getaddrinfo (3),
|
|
||||||
.BR inet (3),
|
|
||||||
.BR lio_listio (3),
|
|
||||||
.BR hostname (7),
|
|
||||||
.BR ip (7),
|
|
||||||
.BR sigevent (7)
|
|
||||||
|
|
|
@ -1,606 +1 @@
|
||||||
.\" Copyright (c) 2009 Petr Baudis <pasky@suse.cz>
|
.so man3/getaddrinfo_a.3
|
||||||
.\" and clean-ups and additions (C) 2010 Michael Kerrisk <mtk.manpages@gmail.com>
|
|
||||||
.\"
|
|
||||||
.\" Permission is granted to make and distribute verbatim copies of this
|
|
||||||
.\" manual provided the copyright notice and this permission notice are
|
|
||||||
.\" preserved on all copies.
|
|
||||||
.\"
|
|
||||||
.\" Permission is granted to copy and distribute modified versions of this
|
|
||||||
.\" manual under the conditions for verbatim copying, provided that the
|
|
||||||
.\" entire resulting derived work is distributed under the terms of a
|
|
||||||
.\" permission notice identical to this one.
|
|
||||||
.\"
|
|
||||||
.\" Since the Linux kernel and libraries are constantly changing, this
|
|
||||||
.\" manual page may be incorrect or out-of-date. The author(s) assume no
|
|
||||||
.\" responsibility for errors or omissions, or for damages resulting from
|
|
||||||
.\" the use of the information contained herein. The author(s) may not
|
|
||||||
.\" have taken the same level of care in the production of this manual,
|
|
||||||
.\" which is licensed free of charge, as they might when working
|
|
||||||
.\" professionally.
|
|
||||||
.\"
|
|
||||||
.\" Formatted or processed versions of this manual, if unaccompanied by
|
|
||||||
.\" the source, must acknowledge the copyright and authors of this work.
|
|
||||||
.\"
|
|
||||||
.\" 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 2010-09-27 "GNU" "Linux Programmer's Manual"
|
|
||||||
.SH NAME
|
|
||||||
getaddrinfo_a, gai_suspend, gai_error, gai_cancel \- asynchronous
|
|
||||||
network address and service translation
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.nf
|
|
||||||
.B #define _GNU_SOURCE
|
|
||||||
.B #include <netdb.h>
|
|
||||||
.sp
|
|
||||||
.BI "int getaddrinfo_a(int " "mode" ", struct gaicb *" "list[]" ,
|
|
||||||
.BI " int " "nitems" ", struct sigevent *" "sevp" );
|
|
||||||
.sp
|
|
||||||
.BI "int gai_suspend(struct gaicb *" "list[]" ", int " "nitems" ,
|
|
||||||
.BI " struct timespec *" "timeout" );
|
|
||||||
.sp
|
|
||||||
.BI "int gai_error(struct gaicb *" "req" );
|
|
||||||
.sp
|
|
||||||
.BI "int gai_cancel(struct gaicb *" "req" );
|
|
||||||
.sp
|
|
||||||
Link with \fI\-lanl\fP.
|
|
||||||
.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.
|
|
||||||
|
|
||||||
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:
|
|
||||||
.sp
|
|
||||||
.in +4n
|
|
||||||
.nf
|
|
||||||
struct gaicb {
|
|
||||||
const char *ar_name;
|
|
||||||
const char *ar_service;
|
|
||||||
const struct addrinfo *ar_request;
|
|
||||||
struct addrinfo *ar_result;
|
|
||||||
};
|
|
||||||
.fi
|
|
||||||
.in
|
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
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
|
|
||||||
.BR SIGEV_NONE
|
|
||||||
Don't provide any notification.
|
|
||||||
.TP
|
|
||||||
.BR 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
|
|
||||||
.BR 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
|
|
||||||
.BR SIGEV_SIGNAL
|
|
||||||
and
|
|
||||||
.BR SIGEV_THREAD ,
|
|
||||||
it may be useful to point
|
|
||||||
.IR sevp\->sigev_value.sival_ptr
|
|
||||||
to
|
|
||||||
.IR list .
|
|
||||||
|
|
||||||
The
|
|
||||||
.BR gai_suspend ()
|
|
||||||
function suspends execution of the calling thread,
|
|
||||||
waiting for the completion of one or more requests in the array
|
|
||||||
.ID list .
|
|
||||||
The
|
|
||||||
.I nitems
|
|
||||||
argument specifies the size of the array
|
|
||||||
.IR list .
|
|
||||||
The call blocks until one of the following occurs:
|
|
||||||
.IP * 3
|
|
||||||
One or more of the operations in
|
|
||||||
.I list
|
|
||||||
completes.
|
|
||||||
.IP *
|
|
||||||
The call is interrupted by a signal that is caught.
|
|
||||||
.IP *
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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_CANCELLED
|
|
||||||
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_CANCELLED
|
|
||||||
if the request has been canceled explicitly before it could be finished.
|
|
||||||
|
|
||||||
The
|
|
||||||
.BR gai_cancel ()
|
|
||||||
function can return one of these values:
|
|
||||||
.TP
|
|
||||||
.B EAI_CANCELLED
|
|
||||||
The request has been canceled successfully.
|
|
||||||
.TP
|
|
||||||
.B EAI_NOTCANCELLED
|
|
||||||
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 "CONFORMING TO"
|
|
||||||
These functions are GNU extensions;
|
|
||||||
they first appeared in glibc in version 2.2.3.
|
|
||||||
.SH NOTES
|
|
||||||
The interface of
|
|
||||||
.BR getaddrinfo_a ()
|
|
||||||
was modeled after the
|
|
||||||
.BR lio_listio (3)
|
|
||||||
interface.
|
|
||||||
.SH EXAMPLE
|
|
||||||
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:
|
|
||||||
.in +4n
|
|
||||||
.nf
|
|
||||||
|
|
||||||
$ \fB./a.out ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz\fP
|
|
||||||
ftp.us.kernel.org: 128.30.2.36
|
|
||||||
enoent.linuxfoundation.org: Name or service not known
|
|
||||||
gnu.cz: 87.236.197.13
|
|
||||||
.fi
|
|
||||||
.in
|
|
||||||
.PP
|
|
||||||
Here is the program source code
|
|
||||||
.nf
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
struct gaicb *reqs[argc \- 1];
|
|
||||||
char host[NI_MAXHOST];
|
|
||||||
struct addrinfo *res;
|
|
||||||
|
|
||||||
if (argc < 2) {
|
|
||||||
fprintf(stderr, "Usage: %s HOST...\\n", argv[0]);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
puts(host);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
puts(gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
.fi
|
|
||||||
|
|
||||||
.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 like this:
|
|
||||||
.in +4n
|
|
||||||
.nf
|
|
||||||
|
|
||||||
$ \fB./a.out\fP
|
|
||||||
> a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
|
|
||||||
> c 2
|
|
||||||
[2] gnu.cz: Request not canceled
|
|
||||||
> w 0 1
|
|
||||||
[00] ftp.us.kernel.org: Finished
|
|
||||||
> l
|
|
||||||
[00] ftp.us.kernel.org: 216.165.129.139
|
|
||||||
[01] enoent.linuxfoundation.org: Processing request in progress
|
|
||||||
[02] gnu.cz: 87.236.197.13
|
|
||||||
> l
|
|
||||||
[00] ftp.us.kernel.org: 216.165.129.139
|
|
||||||
[01] enoent.linuxfoundation.org: Name or service not known
|
|
||||||
[02] gnu.cz: 87.236.197.13
|
|
||||||
.fi
|
|
||||||
.in
|
|
||||||
.PP
|
|
||||||
The program source goes as follows:
|
|
||||||
|
|
||||||
\&
|
|
||||||
.nf
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static struct gaicb **reqs = NULL;
|
|
||||||
static int 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\\n\(aq)
|
|
||||||
buf[strlen(buf) \- 1] = 0;
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add requests for specified hostnames */
|
|
||||||
static void
|
|
||||||
add_requests(void)
|
|
||||||
{
|
|
||||||
int nreqs_base = nreqs;
|
|
||||||
char *host;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while ((host = strtok(NULL, " "))) {
|
|
||||||
nreqs++;
|
|
||||||
reqs = realloc(reqs, nreqs * sizeof(reqs[0]));
|
|
||||||
|
|
||||||
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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait until at least one of specified requests completes */
|
|
||||||
static void
|
|
||||||
wait_requests(void)
|
|
||||||
{
|
|
||||||
char *id;
|
|
||||||
int i, ret, 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\\n", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_reqs[n] = reqs[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gai_suspend(wait_reqs, nreqs, NULL);
|
|
||||||
if (ret) {
|
|
||||||
printf("gai_suspend(): %s\\n", gai_strerror(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nreqs; i++) {
|
|
||||||
if (wait_reqs[i] == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = gai_error(reqs[i]);
|
|
||||||
if (ret == EAI_INPROGRESS)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
printf("[%02d] %s: %s\\n", i, reqs[i]\->ar_name,
|
|
||||||
ret == 0 ? "Finished" : gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cancel specified requests */
|
|
||||||
static void
|
|
||||||
cancel_requests(void)
|
|
||||||
{
|
|
||||||
char *id;
|
|
||||||
int ret, n;
|
|
||||||
|
|
||||||
while ((id = strtok(NULL, " ")) != NULL) {
|
|
||||||
n = atoi(id);
|
|
||||||
|
|
||||||
if (n >= nreqs) {
|
|
||||||
printf("Bad request number: %s\\n", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gai_cancel(reqs[n]);
|
|
||||||
printf("[%s] %s: %s\\n", id, reqs[atoi(id)]\->ar_name,
|
|
||||||
gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List all requests */
|
|
||||||
static void
|
|
||||||
list_requests(void)
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
char host[NI_MAXHOST];
|
|
||||||
struct addrinfo *res;
|
|
||||||
|
|
||||||
for (i = 0; i < nreqs; i++) {
|
|
||||||
printf("[%02d] %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\\n",
|
|
||||||
gai_strerror(ret));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
puts(host);
|
|
||||||
} else {
|
|
||||||
puts(gai_strerror(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
char *cmdline;
|
|
||||||
char *cmd;
|
|
||||||
|
|
||||||
while ((cmdline = getcmd()) != NULL) {
|
|
||||||
cmd = strtok(cmdline, " ");
|
|
||||||
|
|
||||||
if (cmd == NULL) {
|
|
||||||
list_requests();
|
|
||||||
} else {
|
|
||||||
switch (cmd[0]) {
|
|
||||||
case \(aqa\(aq:
|
|
||||||
add_requests();
|
|
||||||
break;
|
|
||||||
case \(aqw\(aq:
|
|
||||||
wait_requests();
|
|
||||||
break;
|
|
||||||
case \(aqc\(aq:
|
|
||||||
cancel_requests();
|
|
||||||
break;
|
|
||||||
case \(aql\(aq:
|
|
||||||
list_requests();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Bad command: %c\\n", cmd[0]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
.fi
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
.BR getaddrinfo (3),
|
|
||||||
.BR inet (3),
|
|
||||||
.BR lio_listio (3),
|
|
||||||
.BR hostname (7),
|
|
||||||
.BR ip (7),
|
|
||||||
.BR sigevent (7)
|
|
||||||
|
|
Loading…
Reference in New Issue