summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac6
-rw-r--r--doc/README.html.in6
-rw-r--r--libasyncns/asyncns-test.c4
-rw-r--r--libasyncns/asyncns.c150
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);