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>
|
||||
.\" 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)
|
||||
.so man3/getaddrinfo_a.3
|
||||
|
|
607
man3/gai_error.3
607
man3/gai_error.3
|
@ -1,606 +1 @@
|
|||
.\" Copyright (c) 2009 Petr Baudis <pasky@suse.cz>
|
||||
.\" 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)
|
||||
.so man3/getaddrinfo_a.3
|
||||
|
|
|
@ -1,606 +1 @@
|
|||
.\" Copyright (c) 2009 Petr Baudis <pasky@suse.cz>
|
||||
.\" 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)
|
||||
.so man3/getaddrinfo_a.3
|
||||
|
|
Loading…
Reference in New Issue