diff options
| author | Petr Baudis <pasky@suse.cz> | 2010-09-27 07:45:28 +0200 |
|---|---|---|
| committer | Michael Kerrisk <mtk.manpages@gmail.com> | 2010-09-27 07:52:54 +0200 |
| commit | b5ae78a107cdee34bd8387c51eab8e538b86c16c (patch) | |
| tree | 63c1432b209616b8aa2daca36852ca3201f62ce7 /man3 | |
| parent | 0f848cbcde20faeecdc86d597df8412c08111859 (diff) | |
| download | man-pages-b5ae78a107cdee34bd8387c51eab8e538b86c16c.tar.gz | |
gai_cancel.3, gai_error.3, gai_suspend.3: New links to new getaddrinfo_a.3 page
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
Diffstat (limited to 'man3')
| -rw-r--r-- | man3/gai_cancel.3 | 606 | ||||
| -rw-r--r-- | man3/gai_error.3 | 606 | ||||
| -rw-r--r-- | man3/gai_suspend.3 | 606 |
3 files changed, 1818 insertions, 0 deletions
diff --git a/man3/gai_cancel.3 b/man3/gai_cancel.3 new file mode 100644 index 0000000000..b39fd07ebe --- /dev/null +++ b/man3/gai_cancel.3 @@ -0,0 +1,606 @@ +.\" 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) diff --git a/man3/gai_error.3 b/man3/gai_error.3 new file mode 100644 index 0000000000..b39fd07ebe --- /dev/null +++ b/man3/gai_error.3 @@ -0,0 +1,606 @@ +.\" 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) diff --git a/man3/gai_suspend.3 b/man3/gai_suspend.3 new file mode 100644 index 0000000000..b39fd07ebe --- /dev/null +++ b/man3/gai_suspend.3 @@ -0,0 +1,606 @@ +.\" 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) |
