diff options
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | doc/README.html.in | 6 | ||||
-rw-r--r-- | libasyncns/asyncns-test.c | 4 | ||||
-rw-r--r-- | libasyncns/asyncns.c | 150 |
4 files changed, 92 insertions, 74 deletions
diff --git a/configure.ac b/configure.ac index 2172791..4508930 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # <http://www.gnu.org/licenses/>. AC_PREREQ(2.62) -AC_INIT([libasyncns],[0.5],[mznflapaf (at) 0pointer (dot) de]) +AC_INIT([libasyncns],[0.6],[mznflapaf (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([libasyncns/asyncns.c]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) @@ -28,7 +28,7 @@ AM_INIT_AUTOMAKE([foreign 1.9 -Wall]) AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/libasyncns/]) -AC_SUBST(LIBASYNCNS_VERSION_INFO, [2:1:2]) +AC_SUBST(LIBASYNCNS_VERSION_INFO, [3:0:3]) if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) @@ -57,7 +57,7 @@ done AC_HEADER_ASSERT AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h stdlib.h string.h sys/socket.h unistd.h sys/prctl.h netinet/in.h]) +AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h stdlib.h string.h sys/socket.h unistd.h sys/prctl.h netinet/in.h arpa/nameser_compat.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/doc/README.html.in b/doc/README.html.in index 810e9bf..76e838c 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -38,6 +38,12 @@ Lesser General Public License for more details.</p> <h2><a name="news">News</a></h2> +<div class="news-date">Fri 24 Oct +2008: </div> <p class="news-text"><a href="@PACKAGE_URL@libasyncns-0.6.tar.gz">Version +0.6</a> released; changes include: save and restore <tt>h_errno</tt> +in addition to <tt>errno</tt>; drop usage of pthread's cancelling +since it is problematic on some platforms.</p> + <div class="news-date">Sun 17 Aug 2008: </div> <p class="news-text"><a href="@PACKAGE_URL@libasyncns-0.5.tar.gz">Version 0.5</a> released; changes include: fix getaddrinfo() serialization.</p> diff --git a/libasyncns/asyncns-test.c b/libasyncns/asyncns-test.c index 053b5bd..112cf11 100644 --- a/libasyncns/asyncns-test.c +++ b/libasyncns/asyncns-test.c @@ -34,6 +34,10 @@ #include <signal.h> #include <errno.h> +#if HAVE_ARPA_NAMESER_COMPAT_H +#include <arpa/nameser_compat.h> +#endif + #include "asyncns.h" int main(int argc, char *argv[]) { diff --git a/libasyncns/asyncns.c b/libasyncns/asyncns.c index b4d7087..4088ce7 100644 --- a/libasyncns/asyncns.c +++ b/libasyncns/asyncns.c @@ -41,6 +41,10 @@ #include <resolv.h> #include <dirent.h> +#if HAVE_ARPA_NAMESER_COMPAT_H +#include <arpa/nameser_compat.h> +#endif + #ifdef HAVE_SYS_PRCTL_H #include <sys/prctl.h> #endif @@ -51,6 +55,10 @@ #include "asyncns.h" +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + #define MAX_WORKERS 16 #define MAX_QUERIES 256 #define BUFSIZE (10240) @@ -102,6 +110,7 @@ struct asyncns_query { asyncns_query_t *done_next, *done_prev; int ret; int _errno; + int _h_errno; struct addrinfo *addrinfo; char *serv, *host; void *userdata; @@ -127,6 +136,7 @@ typedef struct addrinfo_response { struct rheader header; int ret; int _errno; + int _h_errno; /* followed by addrinfo_serialization[] */ } addrinfo_response_t; @@ -152,6 +162,7 @@ typedef struct nameinfo_response { size_t hostlen, servlen; int ret; int _errno; + int _h_errno; } nameinfo_response_t; typedef struct res_query_request { @@ -165,6 +176,7 @@ typedef struct res_query_response { struct rheader header; int ret; int _errno; + int _h_errno; } res_response_t; #ifndef HAVE_STRNDUP @@ -193,7 +205,6 @@ static char *strndup(const char *s, size_t l) { static int close_allv(const int except_fds[]) { struct rlimit rl; int fd; - int saved_errno; #ifdef __linux__ @@ -247,6 +258,8 @@ static int close_allv(const int except_fds[]) { continue; if (close(fd) < 0) { + int saved_errno; + saved_errno = errno; closedir(d); errno = saved_errno; @@ -285,7 +298,7 @@ static int reset_sigsv(const int except[]) { int sig; assert(except); - for (sig = 1; sig < _NSIG; sig++) { + for (sig = 1; sig < NSIG; sig++) { int reset = 1; switch (sig) { @@ -377,7 +390,7 @@ static int send_died(int out_fd) { rh.id = 0; rh.length = sizeof(rh); - return send(out_fd, &rh, rh.length, 0); + return send(out_fd, &rh, rh.length, MSG_NOSIGNAL); } static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) { @@ -411,7 +424,7 @@ static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *leng return (uint8_t*) p + l; } -static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno) { +static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) { addrinfo_response_t data[BUFSIZE/sizeof(addrinfo_response_t) + 1]; addrinfo_response_t *resp = data; assert(out_fd >= 0); @@ -422,6 +435,7 @@ static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo resp->header.length = sizeof(addrinfo_response_t); resp->ret = ret; resp->_errno = _errno; + resp->_h_errno = _h_errno; if (ret == 0 && ai) { void *p = data + 1; @@ -439,10 +453,10 @@ static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo if (ai) freeaddrinfo(ai); - return send(out_fd, resp, resp->header.length, 0); + return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL); } -static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno) { +static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) { nameinfo_response_t data[BUFSIZE/sizeof(nameinfo_response_t) + 1]; size_t hl, sl; nameinfo_response_t *resp = data; @@ -458,6 +472,7 @@ static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *hos resp->header.length = sizeof(nameinfo_response_t) + hl + sl; resp->ret = ret; resp->_errno = _errno; + resp->_h_errno = _h_errno; resp->hostlen = hl; resp->servlen = sl; @@ -469,10 +484,10 @@ static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *hos if (serv) memcpy((uint8_t *)data + sizeof(nameinfo_response_t) + hl, serv, sl); - return send(out_fd, resp, resp->header.length, 0); + return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL); } -static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno) { +static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) { res_response_t data[BUFSIZE/sizeof(res_response_t) + 1]; res_response_t *resp = data; @@ -484,13 +499,14 @@ static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, resp->header.length = sizeof(res_response_t) + (ret < 0 ? 0 : ret); resp->ret = ret; resp->_errno = _errno; + resp->_h_errno = _h_errno; assert(sizeof(data) >= resp->header.length); if (ret > 0) memcpy((uint8_t *)data + sizeof(res_response_t), answer, ret); - return send(out_fd, resp, resp->header.length, 0); + return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL); } static int handle_request(int out_fd, const rheader_t *req, size_t length) { @@ -523,7 +539,7 @@ static int handle_request(int out_fd, const rheader_t *req, size_t length) { &result); /* send_addrinfo_reply() frees result */ - return send_addrinfo_reply(out_fd, req->id, ret, result, errno); + return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno); } case REQUEST_NAMEINFO: { @@ -545,7 +561,7 @@ static int handle_request(int out_fd, const rheader_t *req, size_t length) { return send_nameinfo_reply(out_fd, req->id, ret, ret == 0 && ni_req->gethost ? hostbuf : NULL, ret == 0 && ni_req->getserv ? servbuf : NULL, - errno); + errno, h_errno); } case REQUEST_RES_QUERY: @@ -565,7 +581,7 @@ static int handle_request(int out_fd, const rheader_t *req, size_t length) { else ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE); - return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno); + return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno); } case REQUEST_TERMINATE: @@ -670,7 +686,8 @@ static int process_worker(int in_fd, int out_fd) { if ((length = recv(in_fd, buf, sizeof(buf), 0)) <= 0) { - if (length < 0 && errno == EAGAIN) + if (length < 0 && + (errno == EAGAIN || errno == EINTR)) continue; break; @@ -683,7 +700,6 @@ static int process_worker(int in_fd, int out_fd) { ret = 0; fail: - send_died(out_fd); return ret; @@ -692,42 +708,34 @@ fail: #else static void* thread_worker(void *p) { + asyncns_t *asyncns = p; sigset_t fullset; - int *fds = p; - int in_fd, out_fd; - - in_fd = fds[REQUEST_RECV_FD]; - out_fd = fds[RESPONSE_SEND_FD]; - free(p); - - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); /* No signals in this thread please */ sigfillset(&fullset); pthread_sigmask(SIG_BLOCK, &fullset, NULL); - for (;;) { + while (!asyncns->dead) { rheader_t buf[BUFSIZE/sizeof(rheader_t) + 1]; ssize_t length; - if ((length = recv(in_fd, buf, sizeof(buf), 0)) <= 0) - break; + if ((length = recv(asyncns->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0)) <= 0) { - /* We cannot cancel the thread while it is in on of the name - * resolver functions, because the cleanup might not happen - * properly. To work around this we temporarily disable - * cancellation. The request handling code will eventually - * terminate, and hence we should be safe. */ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + if (length < 0 && + (errno == EAGAIN || errno == EINTR)) + continue; - if (handle_request(out_fd, buf, (size_t) length) < 0) break; + } - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + if (asyncns->dead) + break; + + if (handle_request(asyncns->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0) + break; } - send_died(out_fd); + send_died(asyncns->fds[RESPONSE_SEND_FD]); return NULL; } @@ -778,22 +786,9 @@ asyncns_t* asyncns_new(unsigned n_proc) { _exit(ret); } #else + int r; - int *fds, r; - - /* We need to copy this array because otherwise we might have - * a small chance of a race where the thread accesses fds when - * *asyncns is already dead */ - - if (!(fds = malloc(sizeof(asyncns->fds)))) { - errno = ENOMEM; - goto fail; - } - - memcpy(fds, asyncns->fds, sizeof(asyncns->fds)); - - if ((r = pthread_create(&asyncns->workers[asyncns->valid_workers], NULL, thread_worker, fds)) != 0) { - free(fds); + if ((r = pthread_create(&asyncns->workers[asyncns->valid_workers], NULL, thread_worker, asyncns)) != 0) { errno = r; goto fail; } @@ -828,6 +823,8 @@ void asyncns_free(asyncns_t *asyncns) { assert(asyncns); + asyncns->dead = 1; + if (asyncns->fds[REQUEST_SEND_FD] >= 0) { rheader_t req; @@ -836,33 +833,32 @@ void asyncns_free(asyncns_t *asyncns) { req.length = sizeof(req); req.id = 0; - /* Send one termiantion packet for each worker */ + /* Send one termination packet for each worker */ for (p = 0; p < asyncns->valid_workers; p++) - send(asyncns->fds[REQUEST_SEND_FD], &req, req.length, 0); + send(asyncns->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL); } - /* Close all communication channels */ - for (i = 0; i < MESSAGE_FD_MAX; i++) - if (asyncns->fds[i] >= 0) - close(asyncns->fds[i]); - - /* Now terminate them forcibly */ + /* Now terminate them and wait until they are gone. */ for (p = 0; p < asyncns->valid_workers; p++) { #ifndef HAVE_PTHREAD kill(asyncns->workers[p], SIGTERM); - waitpid(asyncns->workers[p], NULL, 0); + for (;;) { + if (waitpid(asyncns->workers[p], NULL, 0) >= 0 || errno != EINTR) + break; + } #else - pthread_cancel(asyncns->workers[p]); - pthread_detach(asyncns->workers[p]); - - /* We don't join the thread here because there is no clean way - to cancel a running lookup if one should be active. So it - might take a while until the lookup thread actually - terminates. But we don't really care, because it won't leak - resources. */ + for (;;) { + if (pthread_join(asyncns->workers[p], NULL) != EINTR) + break; + } #endif } + /* Close all communication channels */ + for (i = 0; i < MESSAGE_FD_MAX; i++) + if (asyncns->fds[i] >= 0) + close(asyncns->fds[i]); + for (p = 0; p < MAX_QUERIES; p++) if (asyncns->queries[p]) asyncns_cancel(asyncns, asyncns->queries[p]); @@ -987,6 +983,7 @@ static int handle_response(asyncns_t *asyncns, rheader_t *resp, size_t length) { q->ret = ai_resp->ret; q->_errno = ai_resp->_errno; + q->_h_errno = ai_resp->_h_errno; l = length - sizeof(addrinfo_response_t); p = (uint8_t*) resp + sizeof(addrinfo_response_t); @@ -1019,6 +1016,7 @@ static int handle_response(asyncns_t *asyncns, rheader_t *resp, size_t length) { q->ret = ni_resp->ret; q->_errno = ni_resp->_errno; + q->_h_errno = ni_resp->_h_errno; if (ni_resp->hostlen) if (!(q->host = strndup((const char*) ni_resp + sizeof(nameinfo_response_t), ni_resp->hostlen-1))) @@ -1040,6 +1038,7 @@ static int handle_response(asyncns_t *asyncns, rheader_t *resp, size_t length) { q->ret = res_resp->ret; q->_errno = res_resp->_errno; + q->_h_errno = res_resp->_h_errno; if (res_resp->ret >= 0) { if (!(q->serv = malloc(res_resp->ret))) { @@ -1129,6 +1128,7 @@ static asyncns_query_t *alloc_query(asyncns_t *asyncns) { q->done_next = q->done_prev = NULL; q->ret = 0; q->_errno = 0; + q->_h_errno = 0; q->addrinfo = NULL; q->userdata = NULL; q->host = q->serv = NULL; @@ -1178,7 +1178,7 @@ asyncns_query_t* asyncns_getaddrinfo(asyncns_t *asyncns, const char *node, const if (service) strcpy((char*) req + sizeof(addrinfo_request_t) + req->node_len, service); - if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, 0) < 0) + if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0) goto fail; return q; @@ -1213,6 +1213,9 @@ int asyncns_getaddrinfo_done(asyncns_t *asyncns, asyncns_query_t* q, struct addr if (ret == EAI_SYSTEM) errno = q->_errno; + if (ret != 0) + h_errno = q->_h_errno; + asyncns_cancel(asyncns, q); return ret; @@ -1253,7 +1256,7 @@ asyncns_query_t* asyncns_getnameinfo(asyncns_t *asyncns, const struct sockaddr * memcpy((uint8_t*) req + sizeof(nameinfo_request_t), sa, salen); - if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, 0) < 0) + if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0) goto fail; return q; @@ -1297,6 +1300,9 @@ int asyncns_getnameinfo_done(asyncns_t *asyncns, asyncns_query_t* q, char *ret_h if (ret == EAI_SYSTEM) errno = q->_errno; + if (ret != 0) + h_errno = q->_h_errno; + asyncns_cancel(asyncns, q); return ret; @@ -1336,7 +1342,7 @@ static asyncns_query_t * asyncns_res(asyncns_t *asyncns, query_type_t qtype, con strcpy((char*) req + sizeof(res_request_t), dname); - if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, 0) < 0) + if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0) goto fail; return q; @@ -1379,8 +1385,10 @@ int asyncns_res_done(asyncns_t *asyncns, asyncns_query_t* q, unsigned char **ans ret = q->ret; - if (ret < 0) + if (ret < 0) { errno = q->_errno; + h_errno = q->_h_errno; + } asyncns_cancel(asyncns, q); |