diff options
Diffstat (limited to 'libasyncns')
| -rw-r--r-- | libasyncns/asyncns-test.c | 4 | ||||
| -rw-r--r-- | libasyncns/asyncns.c | 150 | 
2 files changed, 83 insertions, 71 deletions
| 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); | 
