diff options
Diffstat (limited to 'libasyncns')
-rw-r--r-- | libasyncns/asyncns-test.c | 56 | ||||
-rw-r--r-- | libasyncns/asyncns.c | 80 | ||||
-rw-r--r-- | libasyncns/asyncns.h | 94 |
3 files changed, 188 insertions, 42 deletions
diff --git a/libasyncns/asyncns-test.c b/libasyncns/asyncns-test.c index 18f5aaf..6eb0a0d 100644 --- a/libasyncns/asyncns-test.c +++ b/libasyncns/asyncns-test.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of libasyncns. + + libasyncns is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + libasyncns is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libasyncns; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include <string.h> #include <sys/types.h> #include <sys/socket.h> @@ -14,31 +35,39 @@ int main(int argc, char *argv[]) { struct sockaddr_in sa; char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = ""; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - if (!(asyncns = asyncns_new(5))) { fprintf(stderr, "asyncns_new() failed\n"); goto fail; } + /* Make a name -> address query */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + q1 = asyncns_getaddrinfo(asyncns, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints); + + + /* Make an address -> name query */ + memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; - sa.sin_addr.s_addr = inet_addr("192.168.50.1"); + sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71"); sa.sin_port = htons(80); - q1 = asyncns_getaddrinfo(asyncns, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints); q2 = asyncns_getnameinfo(asyncns, (struct sockaddr*) &sa, sizeof(sa), 0, 1, 1); + + /* Wait until the two queries are completed */ + while (!asyncns_isdone(asyncns, q1) || !asyncns_isdone(asyncns, q2)) { if (asyncns_wait(asyncns, 1) < 0) goto fail; } - ret = asyncns_getaddrinfo_done(asyncns, q1, &ai); - - if (ret) + /* Interpret the result of the name -> addr query */ + if ((ret = asyncns_getaddrinfo_done(asyncns, q1, &ai))) fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret); else { struct addrinfo *i; @@ -58,14 +87,11 @@ int main(int argc, char *argv[]) { asyncns_freeaddrinfo(ai); } - ret = asyncns_getnameinfo_done(asyncns, q2, host, sizeof(host), serv, sizeof(serv)); - - if (ret) + /* Interpret the result of the addr -> name query */ + if ((ret = asyncns_getnameinfo_done(asyncns, q2, host, sizeof(host), serv, sizeof(serv)))) fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret); - else { + else printf("%s -- %s\n", host, serv); - } - r = 0; diff --git a/libasyncns/asyncns.c b/libasyncns/asyncns.c index 409de2c..fd74133 100644 --- a/libasyncns/asyncns.c +++ b/libasyncns/asyncns.c @@ -1,5 +1,27 @@ -#define HAVE_PR_SET_PDEATHSIG -#define HAVE_SETRESUID +/* $Id$ */ + +/*** + This file is part of libasyncns. + + libasyncns is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + libasyncns is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libasyncns; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif #include <assert.h> #include <fcntl.h> @@ -14,7 +36,7 @@ #include <sys/types.h> #include <pwd.h> -#ifdef HAVE_PR_SET_PDEATHSIG +#ifdef HAVE_SYS_PRCTL_H #include <sys/prctl.h> #endif @@ -143,9 +165,9 @@ static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *leng } static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai) { - assert(out_fd >= 0); uint8_t data[BUFSIZE]; addrinfo_response_t *resp = (addrinfo_response_t*) data; + assert(out_fd >= 0); resp->header.type = RESPONSE_ADDRINFO; resp->header.id = id; @@ -165,11 +187,12 @@ static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo } static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv) { - assert(out_fd >= 0); uint8_t data[BUFSIZE]; size_t hl, sl; nameinfo_response_t *resp = (nameinfo_response_t*) data; + assert(out_fd >= 0); + sl = serv ? strlen(serv)+1 : 0; hl = host ? strlen(host)+1 : 0; @@ -257,6 +280,7 @@ static int handle_request(int out_fd, const rheader_t *req, size_t length) { static int worker(int in_fd, int out_fd) { int r = 0; + int have_death_sig = 0; assert(in_fd > 2); assert(out_fd > 2); @@ -293,29 +317,31 @@ static int worker(int in_fd, int out_fd) { signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); -#ifdef HAVE_PR_SET_PDEATHSIG - prctl(PR_SET_PDEATHSIG, SIGTERM); -#else - fd_nonblock(in_fd); +#ifdef PR_SET_PDEATHSIG + if (prctl(PR_SET_PDEATHSIG, SIGTERM) >= 0) + have_death_sig = 1; #endif + + if (!have_death_sig) + fd_nonblock(in_fd); - while (getppid() != 1) { /* if the parent PID is 1 our parent process died. */ + while (getppid() > 1) { /* if the parent PID is 1 our parent process died. */ char buf[BUFSIZE]; ssize_t length; -#ifndef HAVE_PR_SET_PDEATHSIG - fd_set fds; - struct timeval tv = { 0, 500000 } ; - - FD_ZERO(&fds); - FD_SET(in_fd, &fds); - - if (select(in_fd+1, &fds, NULL, NULL, &tv) < 0) - goto fail; - - if (getppid() == 1) - break; -#endif + if (!have_death_sig) { + fd_set fds; + struct timeval tv = { 0, 500000 } ; + + FD_ZERO(&fds); + FD_SET(in_fd, &fds); + + if (select(in_fd+1, &fds, NULL, NULL, &tv) < 0) + goto fail; + + if (getppid() == 1) + break; + } if ((length = recv(in_fd, buf, sizeof(buf), 0)) <= 0) { @@ -578,6 +604,7 @@ static int handle_response(asyncns_t *asyncns, rheader_t *resp, size_t length) { } int asyncns_wait(asyncns_t *asyncns, int block) { + int handled = 0; assert(asyncns); for (;;) { @@ -590,7 +617,7 @@ int asyncns_wait(asyncns_t *asyncns, int block) { if (errno != EAGAIN) return -1; - if (!block) + if (!block || handled) return 0; FD_ZERO(&fds); @@ -603,7 +630,10 @@ int asyncns_wait(asyncns_t *asyncns, int block) { } - return handle_response(asyncns, (rheader_t*) buf, (size_t) l); + if (handle_response(asyncns, (rheader_t*) buf, (size_t) l) < 0) + return -1; + + handled = 1; } } diff --git a/libasyncns/asyncns.h b/libasyncns/asyncns.h index 28c70d1..6efcccc 100644 --- a/libasyncns/asyncns.h +++ b/libasyncns/asyncns.h @@ -1,37 +1,127 @@ #ifndef fooasyncnshfoo #define fooasyncnshfoo +/* $Id$ */ + +/*** + This file is part of libasyncns. + + libasyncns is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + libasyncns is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libasyncns; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> -struct asyncns; +/** \mainpage + * + * \section moo Method of operation + * + * To use libasyncns allocate an asyncns_t object with + * asyncns_new(). This will spawn a number of worker processes which + * are subsequently used to process the queries the controlling + * program issues via asyncns_getaddrinfo() and + * asyncns_getnameinfo(). Use asyncns_free() to shut down the worker + * processes. + * + * Since libasyncns forks off new processes you have to make sure that + * your program is not irritated by spurious SIGCHLD signals. + */ + +/** \example asyncns-test.c + * An example program */ + +/** An opaque libasyncns session structure */ typedef struct asyncns asyncns_t; -struct asyncns_query; +/** An opaque libasyncns query structure */ typedef struct asyncns_query asyncns_query_t; +/** Allocate a new libasyncns session with n_proc worker processes */ asyncns_t* asyncns_new(int n_proc); + +/** Free a libasyncns session. This destroys all attached + * asyncns_query_t objects automatically */ void asyncns_free(asyncns_t *asyncns); + +/** Return the UNIX file descriptor to select() for readability + * on. Use this function to integrate libasyncns with your custom main + * loop. */ int asyncns_fd(asyncns_t *asyncns); + +/** Process pending responses. If block is non-zero wait until at + * least one response has been processed. If block is zero, process + * all pending responses and return. */ int asyncns_wait(asyncns_t *asyncns, int block); +/** Issue a name to address query on the specified session. The + * arguments are compatible with the ones of libc's + * getaddrinfo(3). The function returns a new query object. When the + * query is completed you may retrieve the results using + * asyncns_getaddrinfo_done().*/ asyncns_query_t* asyncns_getaddrinfo(asyncns_t *asyncns, const char *node, const char *service, const struct addrinfo *hints); + +/** Retrieve the results of a preceding asyncns_getaddrinfo() + * call. Returns a addrinfo structure and a return value compatible + * with libc's getaddrinfo(3). The query object q is destroyed by this + * call and may not be used any further. Make sure to free the + * returned addrinfo structure with asyncns_freeaddrinfo() and not + * libc's freeaddrinfo(3)! If the query is not completed yet EAI_AGAIN + * is returned.*/ int asyncns_getaddrinfo_done(asyncns_t *asyncns, asyncns_query_t* q, struct addrinfo **ret_res); +/** Issue an address to name query on the specified session. The +arguments are compatible with the ones of libc's getnameinfo(3). The +function returns a new query object. When the query is completed you +may retrieve the results using asyncns_getnameinfo_done(). Set gethost +(resp. getserv) to non-zero if you want to query the hostname +(resp. the service name). */ asyncns_query_t* asyncns_getnameinfo(asyncns_t *asyncns, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv); + +/** Retrieve the results of a preceding asyncns_getnameinfo)( + * call. Returns the hostname and the service name in ret_host and + * ret_serv. The query object q is destroyed by this call and may not + * be used any further. If the query is not completed yet EAI_AGAIN is + * returned. */ int asyncns_getnameinfo_done(asyncns_t *asyncns, asyncns_query_t* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen); +/** Return the next completed query object. If no query has been completed yet, return NULL */ asyncns_query_t* asyncns_getnext(asyncns_t *asyncns); + +/** Return the number of query objects (completed or not) attached to this session */ int asyncns_getnqueries(asyncns_t *asyncns); +/** Cancel a currently running query. q is is destroyed by this call + * and may not be used any futher. */ void asyncns_cancel(asyncns_t *asyncns, asyncns_query_t* q); +/** Free the addrinfo structure as returned by +asyncns_getaddrinfo_done(). Make sure to use this functions instead of +the libc's freeaddrinfo()! */ void asyncns_freeaddrinfo(struct addrinfo *ai); +/** Returns non-zero when the query operation specified by q has been completed */ int asyncns_isdone(asyncns_t *asyncns, asyncns_query_t*q); +/** Assign some opaque userdata with a query object */ void asyncns_setuserdata(asyncns_t *asyncns, asyncns_query_t *q, void *userdata); + +/** Return userdata assigned to a query object. Use + * asyncns_setuserdata() to set this data. If no data has been set + * prior to this call it returns NULL. */ void* asyncns_getuserdata(asyncns_t *asyncns, asyncns_query_t *q); #endif |