Blame libasyncns/asyncns.c

Packit 6baad5
/***
Packit 6baad5
  This file is part of libasyncns.
Packit 6baad5
Packit 6baad5
  Copyright 2005-2008 Lennart Poettering
Packit 6baad5
Packit 6baad5
  libasyncns is free software; you can redistribute it and/or modify
Packit 6baad5
  it under the terms of the GNU Lesser General Public License as
Packit 6baad5
  published by the Free Software Foundation, either version 2.1 of the
Packit 6baad5
  License, or (at your option) any later version.
Packit 6baad5
Packit 6baad5
  libasyncns is distributed in the hope that it will be useful, but
Packit 6baad5
  WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6baad5
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit 6baad5
  Lesser General Public License for more details.
Packit 6baad5
Packit 6baad5
  You should have received a copy of the GNU Lesser General Public
Packit 6baad5
  License along with libasyncns. If not, see
Packit 6baad5
  <http://www.gnu.org/licenses/>.
Packit 6baad5
***/
Packit 6baad5
Packit 6baad5
#ifdef HAVE_CONFIG_H
Packit 6baad5
#include <config.h>
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
/* #undef HAVE_PTHREAD */
Packit 6baad5
Packit 6baad5
#include <assert.h>
Packit 6baad5
#include <fcntl.h>
Packit 6baad5
#include <signal.h>
Packit 6baad5
#include <unistd.h>
Packit 6baad5
#include <sys/select.h>
Packit 6baad5
#include <stdio.h>
Packit 6baad5
#include <string.h>
Packit 6baad5
#include <stdlib.h>
Packit 6baad5
#include <errno.h>
Packit 6baad5
#include <sys/wait.h>
Packit 6baad5
#include <sys/types.h>
Packit 6baad5
#include <pwd.h>
Packit 6baad5
#include <netinet/in.h>
Packit 6baad5
#include <arpa/nameser.h>
Packit 6baad5
#include <resolv.h>
Packit 6baad5
#include <dirent.h>
Packit 6baad5
#include <sys/time.h>
Packit 6baad5
#include <sys/resource.h>
Packit 6baad5
#include <stdint.h>
Packit 6baad5
Packit 6baad5
#ifdef HAVE_SYS_PRCTL_H
Packit 6baad5
#include <sys/prctl.h>
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
#if HAVE_PTHREAD
Packit 6baad5
#include <pthread.h>
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
#include "asyncns.h"
Packit 6baad5
Packit 6baad5
#ifndef MSG_NOSIGNAL
Packit 6baad5
#define MSG_NOSIGNAL 0
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
#define MAX_WORKERS 16
Packit 6baad5
#define MAX_QUERIES 256
Packit 6baad5
#define BUFSIZE (10240)
Packit 6baad5
Packit 6baad5
typedef enum {
Packit 6baad5
    REQUEST_ADDRINFO,
Packit 6baad5
    RESPONSE_ADDRINFO,
Packit 6baad5
    REQUEST_NAMEINFO,
Packit 6baad5
    RESPONSE_NAMEINFO,
Packit 6baad5
    REQUEST_RES_QUERY,
Packit 6baad5
    REQUEST_RES_SEARCH,
Packit 6baad5
    RESPONSE_RES,
Packit 6baad5
    REQUEST_TERMINATE,
Packit 6baad5
    RESPONSE_DIED
Packit 6baad5
} query_type_t;
Packit 6baad5
Packit 6baad5
enum {
Packit 6baad5
    REQUEST_RECV_FD = 0,
Packit 6baad5
    REQUEST_SEND_FD = 1,
Packit 6baad5
    RESPONSE_RECV_FD = 2,
Packit 6baad5
    RESPONSE_SEND_FD = 3,
Packit 6baad5
    MESSAGE_FD_MAX = 4
Packit 6baad5
};
Packit 6baad5
Packit 6baad5
struct asyncns {
Packit 6baad5
    int fds[4];
Packit 6baad5
Packit 6baad5
#ifndef HAVE_PTHREAD
Packit 6baad5
    pid_t workers[MAX_WORKERS];
Packit 6baad5
#else
Packit 6baad5
    pthread_t workers[MAX_WORKERS];
Packit 6baad5
#endif
Packit 6baad5
    unsigned valid_workers;
Packit 6baad5
Packit 6baad5
    unsigned current_id, current_index;
Packit 6baad5
    asyncns_query_t* queries[MAX_QUERIES];
Packit 6baad5
Packit 6baad5
    asyncns_query_t *done_head, *done_tail;
Packit 6baad5
Packit 6baad5
    int n_queries;
Packit 6baad5
    int dead;
Packit 6baad5
};
Packit 6baad5
Packit 6baad5
struct asyncns_query {
Packit 6baad5
    asyncns_t *asyncns;
Packit 6baad5
    int done;
Packit 6baad5
    unsigned id;
Packit 6baad5
    query_type_t type;
Packit 6baad5
    asyncns_query_t *done_next, *done_prev;
Packit 6baad5
    int ret;
Packit 6baad5
    int _errno;
Packit 6baad5
    int _h_errno;
Packit 6baad5
    struct addrinfo *addrinfo;
Packit 6baad5
    char *serv, *host;
Packit 6baad5
    void *userdata;
Packit 6baad5
};
Packit 6baad5
Packit 6baad5
typedef struct rheader {
Packit 6baad5
    query_type_t type;
Packit 6baad5
    unsigned id;
Packit 6baad5
    size_t length;
Packit 6baad5
} rheader_t;
Packit 6baad5
Packit 6baad5
typedef struct addrinfo_request {
Packit 6baad5
    struct rheader header;
Packit 6baad5
    int hints_is_null;
Packit 6baad5
    int ai_flags;
Packit 6baad5
    int ai_family;
Packit 6baad5
    int ai_socktype;
Packit 6baad5
    int ai_protocol;
Packit 6baad5
    size_t node_len, service_len;
Packit 6baad5
} addrinfo_request_t;
Packit 6baad5
Packit 6baad5
typedef struct addrinfo_response {
Packit 6baad5
    struct rheader header;
Packit 6baad5
    int ret;
Packit 6baad5
    int _errno;
Packit 6baad5
    int _h_errno;
Packit 6baad5
    /* followed by addrinfo_serialization[] */
Packit 6baad5
} addrinfo_response_t;
Packit 6baad5
Packit 6baad5
typedef struct addrinfo_serialization {
Packit 6baad5
    int ai_flags;
Packit 6baad5
    int ai_family;
Packit 6baad5
    int ai_socktype;
Packit 6baad5
    int ai_protocol;
Packit 6baad5
    size_t ai_addrlen;
Packit 6baad5
    size_t canonname_len;
Packit 6baad5
    /* Followed by ai_addr amd ai_canonname with variable lengths */
Packit 6baad5
} addrinfo_serialization_t;
Packit 6baad5
Packit 6baad5
typedef struct nameinfo_request {
Packit 6baad5
    struct rheader header;
Packit 6baad5
    int flags;
Packit 6baad5
    socklen_t sockaddr_len;
Packit 6baad5
    int gethost, getserv;
Packit 6baad5
} nameinfo_request_t;
Packit 6baad5
Packit 6baad5
typedef struct nameinfo_response {
Packit 6baad5
    struct rheader header;
Packit 6baad5
    size_t hostlen, servlen;
Packit 6baad5
    int ret;
Packit 6baad5
    int _errno;
Packit 6baad5
    int _h_errno;
Packit 6baad5
} nameinfo_response_t;
Packit 6baad5
Packit 6baad5
typedef struct res_request {
Packit 6baad5
    struct rheader header;
Packit 6baad5
    int class;
Packit 6baad5
    int type;
Packit 6baad5
    size_t dname_len;
Packit 6baad5
} res_request_t;
Packit 6baad5
Packit 6baad5
typedef struct res_response {
Packit 6baad5
    struct rheader header;
Packit 6baad5
    int ret;
Packit 6baad5
    int _errno;
Packit 6baad5
    int _h_errno;
Packit 6baad5
} res_response_t;
Packit 6baad5
Packit 6baad5
typedef union packet {
Packit 6baad5
    rheader_t rheader;
Packit 6baad5
    addrinfo_request_t addrinfo_request;
Packit 6baad5
    addrinfo_response_t addrinfo_response;
Packit 6baad5
    nameinfo_request_t nameinfo_request;
Packit 6baad5
    nameinfo_response_t nameinfo_response;
Packit 6baad5
    res_request_t res_request;
Packit 6baad5
    res_response_t res_response;
Packit 6baad5
} packet_t;
Packit 6baad5
Packit 6baad5
#ifndef HAVE_STRNDUP
Packit 6baad5
Packit 6baad5
static char *strndup(const char *s, size_t l) {
Packit 6baad5
    size_t a;
Packit 6baad5
    char *n;
Packit 6baad5
Packit 6baad5
    a = strlen(s);
Packit 6baad5
    if (a > l)
Packit 6baad5
        a = l;
Packit 6baad5
Packit 6baad5
    if (!(n = malloc(a+1)))
Packit 6baad5
        return NULL;
Packit 6baad5
Packit 6baad5
    memcpy(n, s, a);
Packit 6baad5
    n[a] = 0;
Packit 6baad5
Packit 6baad5
    return n;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
#ifndef HAVE_PTHREAD
Packit 6baad5
Packit 6baad5
static int close_allv(const int except_fds[]) {
Packit 6baad5
    struct rlimit rl;
Packit 6baad5
    int fd, maxfd;
Packit 6baad5
Packit 6baad5
#ifdef __linux__
Packit 6baad5
Packit 6baad5
    DIR *d;
Packit 6baad5
Packit 6baad5
    assert(except_fds);
Packit 6baad5
Packit 6baad5
    if ((d = opendir("/proc/self/fd"))) {
Packit 6baad5
Packit 6baad5
        struct dirent *de;
Packit 6baad5
Packit 6baad5
        while ((de = readdir(d))) {
Packit 6baad5
            int found;
Packit 6baad5
            long l;
Packit 6baad5
            char *e = NULL;
Packit 6baad5
            int i;
Packit 6baad5
Packit 6baad5
            if (de->d_name[0] == '.')
Packit 6baad5
                continue;
Packit 6baad5
Packit 6baad5
            errno = 0;
Packit 6baad5
            l = strtol(de->d_name, &e, 10);
Packit 6baad5
            if (errno != 0 || !e || *e) {
Packit 6baad5
                closedir(d);
Packit 6baad5
                errno = EINVAL;
Packit 6baad5
                return -1;
Packit 6baad5
            }
Packit 6baad5
Packit 6baad5
            fd = (int) l;
Packit 6baad5
Packit 6baad5
            if ((long) fd != l) {
Packit 6baad5
                closedir(d);
Packit 6baad5
                errno = EINVAL;
Packit 6baad5
                return -1;
Packit 6baad5
            }
Packit 6baad5
Packit 6baad5
            if (fd < 3)
Packit 6baad5
                continue;
Packit 6baad5
Packit 6baad5
            if (fd == dirfd(d))
Packit 6baad5
                continue;
Packit 6baad5
Packit 6baad5
            found = 0;
Packit 6baad5
            for (i = 0; except_fds[i] >= 0; i++)
Packit 6baad5
                if (except_fds[i] == fd) {
Packit 6baad5
                    found = 1;
Packit 6baad5
                    break;
Packit 6baad5
                }
Packit 6baad5
Packit 6baad5
            if (found)
Packit 6baad5
                continue;
Packit 6baad5
Packit 6baad5
            if (close(fd) < 0) {
Packit 6baad5
                int saved_errno;
Packit 6baad5
Packit 6baad5
                saved_errno = errno;
Packit 6baad5
                closedir(d);
Packit 6baad5
                errno = saved_errno;
Packit 6baad5
Packit 6baad5
                return -1;
Packit 6baad5
            }
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        closedir(d);
Packit 6baad5
        return 0;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
    if (getrlimit(RLIMIT_NOFILE, &rl) > 0)
Packit 6baad5
        maxfd = (int) rl.rlim_max;
Packit 6baad5
    else
Packit 6baad5
        maxfd = sysconf(_SC_OPEN_MAX);
Packit 6baad5
Packit 6baad5
    for (fd = 3; fd < maxfd; fd++) {
Packit 6baad5
        int i, found;
Packit 6baad5
Packit 6baad5
        found = 0;
Packit 6baad5
        for (i = 0; except_fds[i] >= 0; i++)
Packit 6baad5
            if (except_fds[i] == fd) {
Packit 6baad5
                found = 1;
Packit 6baad5
                continue;
Packit 6baad5
            }
Packit 6baad5
Packit 6baad5
        if (found)
Packit 6baad5
            continue;
Packit 6baad5
Packit 6baad5
        if (close(fd) < 0 && errno != EBADF)
Packit 6baad5
            return -1;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    return 0;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static int reset_sigsv(const int except[]) {
Packit 6baad5
    int sig;
Packit 6baad5
    assert(except);
Packit 6baad5
Packit 6baad5
    for (sig = 1; sig < NSIG; sig++) {
Packit 6baad5
        int reset = 1;
Packit 6baad5
Packit 6baad5
        switch (sig) {
Packit 6baad5
            case SIGKILL:
Packit 6baad5
            case SIGSTOP:
Packit 6baad5
                reset = 0;
Packit 6baad5
                break;
Packit 6baad5
Packit 6baad5
            default: {
Packit 6baad5
                int i;
Packit 6baad5
Packit 6baad5
                for (i = 0; except[i] > 0; i++) {
Packit 6baad5
                    if (sig == except[i]) {
Packit 6baad5
                        reset = 0;
Packit 6baad5
                        break;
Packit 6baad5
                    }
Packit 6baad5
                }
Packit 6baad5
            }
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        if (reset) {
Packit 6baad5
            struct sigaction sa;
Packit 6baad5
Packit 6baad5
            memset(&sa, 0, sizeof(sa));
Packit 6baad5
            sa.sa_handler = SIG_DFL;
Packit 6baad5
Packit 6baad5
            /* On Linux the first two RT signals are reserved by
Packit 6baad5
             * glibc, and sigaction() will return EINVAL for them. */
Packit 6baad5
            if ((sigaction(sig, &sa, NULL) < 0))
Packit 6baad5
                if (errno != EINVAL)
Packit 6baad5
                    return -1;
Packit 6baad5
        }
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    return 0;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static int ignore_sigsv(const int ignore[]) {
Packit 6baad5
    int i;
Packit 6baad5
    assert(ignore);
Packit 6baad5
Packit 6baad5
    for (i = 0; ignore[i] > 0; i++) {
Packit 6baad5
        struct sigaction sa;
Packit 6baad5
Packit 6baad5
        memset(&sa, 0, sizeof(sa));
Packit 6baad5
        sa.sa_handler = SIG_IGN;
Packit 6baad5
Packit 6baad5
        if ((sigaction(ignore[i], &sa, NULL) < 0))
Packit 6baad5
            return -1;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    return 0;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
static int fd_nonblock(int fd) {
Packit 6baad5
    int i;
Packit 6baad5
    assert(fd >= 0);
Packit 6baad5
Packit 6baad5
    if ((i = fcntl(fd, F_GETFL, 0)) < 0)
Packit 6baad5
        return -1;
Packit 6baad5
Packit 6baad5
    if (i & O_NONBLOCK)
Packit 6baad5
        return 0;
Packit 6baad5
Packit 6baad5
    return fcntl(fd, F_SETFL, i | O_NONBLOCK);
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static int fd_cloexec(int fd) {
Packit 6baad5
    int v;
Packit 6baad5
    assert(fd >= 0);
Packit 6baad5
Packit 6baad5
    if ((v = fcntl(fd, F_GETFD, 0)) < 0)
Packit 6baad5
        return -1;
Packit 6baad5
Packit 6baad5
    if (v & FD_CLOEXEC)
Packit 6baad5
        return 0;
Packit 6baad5
Packit 6baad5
    return fcntl(fd, F_SETFD, v | FD_CLOEXEC);
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static int send_died(int out_fd) {
Packit 6baad5
    rheader_t rh;
Packit 6baad5
    assert(out_fd > 0);
Packit 6baad5
Packit 6baad5
    memset(&rh, 0, sizeof(rh));
Packit 6baad5
    rh.type = RESPONSE_DIED;
Packit 6baad5
    rh.id = 0;
Packit 6baad5
    rh.length = sizeof(rh);
Packit 6baad5
Packit 6baad5
    return send(out_fd, &rh, rh.length, MSG_NOSIGNAL);
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
Packit 6baad5
    addrinfo_serialization_t s;
Packit 6baad5
    size_t cnl, l;
Packit 6baad5
    assert(p);
Packit 6baad5
    assert(ai);
Packit 6baad5
    assert(length);
Packit 6baad5
    assert(*length <= maxlength);
Packit 6baad5
Packit 6baad5
    cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0);
Packit 6baad5
    l = sizeof(addrinfo_serialization_t) + ai->ai_addrlen + cnl;
Packit 6baad5
Packit 6baad5
    if (*length + l > maxlength)
Packit 6baad5
        return NULL;
Packit 6baad5
Packit 6baad5
    s.ai_flags = ai->ai_flags;
Packit 6baad5
    s.ai_family = ai->ai_family;
Packit 6baad5
    s.ai_socktype = ai->ai_socktype;
Packit 6baad5
    s.ai_protocol = ai->ai_protocol;
Packit 6baad5
    s.ai_addrlen = ai->ai_addrlen;
Packit 6baad5
    s.canonname_len = cnl;
Packit 6baad5
Packit 6baad5
    memcpy((uint8_t*) p, &s, sizeof(addrinfo_serialization_t));
Packit 6baad5
    memcpy((uint8_t*) p + sizeof(addrinfo_serialization_t), ai->ai_addr, ai->ai_addrlen);
Packit 6baad5
Packit 6baad5
    if (ai->ai_canonname)
Packit 6baad5
        strcpy((char*) p + sizeof(addrinfo_serialization_t) + ai->ai_addrlen, ai->ai_canonname);
Packit 6baad5
Packit 6baad5
    *length += l;
Packit 6baad5
    return (uint8_t*) p + l;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) {
Packit 6baad5
    addrinfo_response_t data[BUFSIZE/sizeof(addrinfo_response_t) + 1];
Packit 6baad5
    addrinfo_response_t *resp = data;
Packit 6baad5
    assert(out_fd >= 0);
Packit 6baad5
Packit 6baad5
    memset(data, 0, sizeof(data));
Packit 6baad5
    resp->header.type = RESPONSE_ADDRINFO;
Packit 6baad5
    resp->header.id = id;
Packit 6baad5
    resp->header.length = sizeof(addrinfo_response_t);
Packit 6baad5
    resp->ret = ret;
Packit 6baad5
    resp->_errno = _errno;
Packit 6baad5
    resp->_h_errno = _h_errno;
Packit 6baad5
Packit 6baad5
    if (ret == 0 && ai) {
Packit 6baad5
        void *p = data + 1;
Packit 6baad5
        struct addrinfo *k;
Packit 6baad5
Packit 6baad5
        for (k = ai; k; k = k->ai_next) {
Packit 6baad5
Packit 6baad5
            if (!(p = serialize_addrinfo(p, k, &resp->header.length, (char*) data + BUFSIZE - (char*) p))) {
Packit 6baad5
                resp->ret = EAI_MEMORY;
Packit 6baad5
                break;
Packit 6baad5
            }
Packit 6baad5
        }
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (ai)
Packit 6baad5
        freeaddrinfo(ai);
Packit 6baad5
Packit 6baad5
    return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) {
Packit 6baad5
    nameinfo_response_t data[BUFSIZE/sizeof(nameinfo_response_t) + 1];
Packit 6baad5
    size_t hl, sl;
Packit 6baad5
    nameinfo_response_t *resp = data;
Packit 6baad5
Packit 6baad5
    assert(out_fd >= 0);
Packit 6baad5
Packit 6baad5
    sl = serv ? strlen(serv)+1 : 0;
Packit 6baad5
    hl = host ? strlen(host)+1 : 0;
Packit 6baad5
Packit 6baad5
    memset(data, 0, sizeof(data));
Packit 6baad5
    resp->header.type = RESPONSE_NAMEINFO;
Packit 6baad5
    resp->header.id = id;
Packit 6baad5
    resp->header.length = sizeof(nameinfo_response_t) + hl + sl;
Packit 6baad5
    resp->ret = ret;
Packit 6baad5
    resp->_errno = _errno;
Packit 6baad5
    resp->_h_errno = _h_errno;
Packit 6baad5
    resp->hostlen = hl;
Packit 6baad5
    resp->servlen = sl;
Packit 6baad5
Packit 6baad5
    assert(sizeof(data) >= resp->header.length);
Packit 6baad5
Packit 6baad5
    if (host)
Packit 6baad5
        memcpy((uint8_t *)data + sizeof(nameinfo_response_t), host, hl);
Packit 6baad5
Packit 6baad5
    if (serv)
Packit 6baad5
        memcpy((uint8_t *)data + sizeof(nameinfo_response_t) + hl, serv, sl);
Packit 6baad5
Packit 6baad5
    return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
Packit 6baad5
    res_response_t data[BUFSIZE/sizeof(res_response_t) + 1];
Packit 6baad5
    res_response_t *resp = data;
Packit 6baad5
Packit 6baad5
    assert(out_fd >= 0);
Packit 6baad5
Packit 6baad5
    memset(data, 0, sizeof(data));
Packit 6baad5
    resp->header.type = RESPONSE_RES;
Packit 6baad5
    resp->header.id = id;
Packit 6baad5
    resp->header.length = sizeof(res_response_t) + (ret < 0 ? 0 : ret);
Packit 6baad5
    resp->ret = ret;
Packit 6baad5
    resp->_errno = _errno;
Packit 6baad5
    resp->_h_errno = _h_errno;
Packit 6baad5
Packit 6baad5
    assert(sizeof(data) >= resp->header.length);
Packit 6baad5
Packit 6baad5
    if (ret > 0)
Packit 6baad5
        memcpy((uint8_t *)data + sizeof(res_response_t), answer, ret);
Packit 6baad5
Packit 6baad5
    return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static int handle_request(int out_fd, const packet_t *packet, size_t length) {
Packit 6baad5
    const rheader_t *req;
Packit 6baad5
    assert(out_fd >= 0);
Packit 6baad5
Packit 6baad5
    req = &packet->rheader;
Packit 6baad5
    assert(req);
Packit 6baad5
    assert(length >= sizeof(rheader_t));
Packit 6baad5
    assert(length == req->length);
Packit 6baad5
Packit 6baad5
    switch (req->type) {
Packit 6baad5
Packit 6baad5
        case REQUEST_ADDRINFO: {
Packit 6baad5
            struct addrinfo ai, *result = NULL;
Packit 6baad5
            const addrinfo_request_t *ai_req = &packet->addrinfo_request;
Packit 6baad5
            const char *node, *service;
Packit 6baad5
            int ret;
Packit 6baad5
Packit 6baad5
            assert(length >= sizeof(addrinfo_request_t));
Packit 6baad5
            assert(length == sizeof(addrinfo_request_t) + ai_req->node_len + ai_req->service_len);
Packit 6baad5
Packit 6baad5
            memset(&ai, 0, sizeof(ai));
Packit 6baad5
            ai.ai_flags = ai_req->ai_flags;
Packit 6baad5
            ai.ai_family = ai_req->ai_family;
Packit 6baad5
            ai.ai_socktype = ai_req->ai_socktype;
Packit 6baad5
            ai.ai_protocol = ai_req->ai_protocol;
Packit 6baad5
Packit 6baad5
            node = ai_req->node_len ? (const char*) ai_req + sizeof(addrinfo_request_t) : NULL;
Packit 6baad5
            service = ai_req->service_len ? (const char*) ai_req + sizeof(addrinfo_request_t) + ai_req->node_len : NULL;
Packit 6baad5
Packit 6baad5
            ret = getaddrinfo(node, service,
Packit 6baad5
                              ai_req->hints_is_null ? NULL : &ai,
Packit 6baad5
                              &result);
Packit 6baad5
Packit 6baad5
            /* send_addrinfo_reply() frees result */
Packit 6baad5
            return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        case REQUEST_NAMEINFO: {
Packit 6baad5
            int ret;
Packit 6baad5
            const nameinfo_request_t *ni_req = &packet->nameinfo_request;
Packit 6baad5
            char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
Packit 6baad5
            struct sockaddr_storage sa;
Packit 6baad5
Packit 6baad5
            assert(length >= sizeof(nameinfo_request_t));
Packit 6baad5
            assert(length == sizeof(nameinfo_request_t) + ni_req->sockaddr_len);
Packit 6baad5
Packit 6baad5
            memcpy(&sa, (const uint8_t *) ni_req + sizeof(nameinfo_request_t), ni_req->sockaddr_len);
Packit 6baad5
Packit 6baad5
            ret = getnameinfo((struct sockaddr *)&sa, ni_req->sockaddr_len,
Packit 6baad5
                              ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
Packit 6baad5
                              ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
Packit 6baad5
                              ni_req->flags);
Packit 6baad5
Packit 6baad5
            return send_nameinfo_reply(out_fd, req->id, ret,
Packit 6baad5
                                       ret == 0 && ni_req->gethost ? hostbuf : NULL,
Packit 6baad5
                                       ret == 0 && ni_req->getserv ? servbuf : NULL,
Packit 6baad5
                                       errno, h_errno);
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        case REQUEST_RES_QUERY:
Packit 6baad5
        case REQUEST_RES_SEARCH: {
Packit 6baad5
            int ret;
Packit 6baad5
            HEADER answer[BUFSIZE/sizeof(HEADER) + 1];
Packit 6baad5
            const res_request_t *res_req = &packet->res_request;
Packit 6baad5
            const char *dname;
Packit 6baad5
Packit 6baad5
            assert(length >= sizeof(res_request_t));
Packit 6baad5
            assert(length == sizeof(res_request_t) + res_req->dname_len);
Packit 6baad5
Packit 6baad5
            dname = (const char *) req + sizeof(res_request_t);
Packit 6baad5
Packit 6baad5
            if (req->type == REQUEST_RES_QUERY)
Packit 6baad5
                ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
Packit 6baad5
            else
Packit 6baad5
                ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
Packit 6baad5
Packit 6baad5
            return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno);
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        case REQUEST_TERMINATE:
Packit 6baad5
            /* Quit */
Packit 6baad5
            return -1;
Packit 6baad5
Packit 6baad5
        default:
Packit 6baad5
            ;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    return 0;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
#ifndef HAVE_PTHREAD
Packit 6baad5
Packit 6baad5
static int process_worker(int in_fd, int out_fd) {
Packit 6baad5
    int have_death_sig = 0;
Packit 6baad5
    int good_fds[3];
Packit 6baad5
    int ret = 1;
Packit 6baad5
Packit 6baad5
    const int ignore_sigs[] = {
Packit 6baad5
        SIGINT,
Packit 6baad5
        SIGHUP,
Packit 6baad5
        SIGPIPE,
Packit 6baad5
        SIGUSR1,
Packit 6baad5
        SIGUSR2,
Packit 6baad5
        -1
Packit 6baad5
    };
Packit 6baad5
Packit 6baad5
    assert(in_fd > 2);
Packit 6baad5
    assert(out_fd > 2);
Packit 6baad5
Packit 6baad5
    close(0);
Packit 6baad5
    close(1);
Packit 6baad5
    close(2);
Packit 6baad5
Packit 6baad5
    if (open("/dev/null", O_RDONLY) != 0)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    if (open("/dev/null", O_WRONLY) != 1)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    if (open("/dev/null", O_WRONLY) != 2)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    if (chdir("/") < 0)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    if (geteuid() == 0) {
Packit 6baad5
        struct passwd *pw;
Packit 6baad5
        int r;
Packit 6baad5
Packit 6baad5
        if ((pw = getpwnam("nobody"))) {
Packit 6baad5
#ifdef HAVE_SETRESUID
Packit 6baad5
            r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid);
Packit 6baad5
#elif HAVE_SETREUID
Packit 6baad5
            r = setreuid(pw->pw_uid, pw->pw_uid);
Packit 6baad5
#else
Packit 6baad5
            if ((r = setuid(pw->pw_uid)) >= 0)
Packit 6baad5
                r = seteuid(pw->pw_uid);
Packit 6baad5
#endif
Packit 6baad5
            if (r < 0)
Packit 6baad5
                goto fail;
Packit 6baad5
        }
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (reset_sigsv(ignore_sigs) < 0)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    if (ignore_sigsv(ignore_sigs) < 0)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    good_fds[0] = in_fd; good_fds[1] = out_fd; good_fds[2] = -1;
Packit 6baad5
    if (close_allv(good_fds) < 0)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
#ifdef PR_SET_PDEATHSIG
Packit 6baad5
    if (prctl(PR_SET_PDEATHSIG, SIGTERM) >= 0)
Packit 6baad5
        have_death_sig = 1;
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
    if (!have_death_sig)
Packit 6baad5
        fd_nonblock(in_fd);
Packit 6baad5
Packit 6baad5
    while (getppid() > 1) { /* if the parent PID is 1 our parent process died. */
Packit 6baad5
        packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
Packit 6baad5
        ssize_t length;
Packit 6baad5
Packit 6baad5
        if (!have_death_sig) {
Packit 6baad5
            fd_set fds;
Packit 6baad5
            struct timeval tv = { 0, 500000 };
Packit 6baad5
Packit 6baad5
            FD_ZERO(&fds);
Packit 6baad5
            FD_SET(in_fd, &fds);
Packit 6baad5
Packit 6baad5
            if (select(in_fd+1, &fds, NULL, NULL, &tv) < 0)
Packit 6baad5
                break;
Packit 6baad5
Packit 6baad5
            if (getppid() == 1)
Packit 6baad5
                break;
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        if ((length = recv(in_fd, buf, sizeof(buf), 0)) <= 0) {
Packit 6baad5
Packit 6baad5
            if (length < 0 &&
Packit 6baad5
                (errno == EAGAIN || errno == EINTR))
Packit 6baad5
                continue;
Packit 6baad5
Packit 6baad5
            break;
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        if (handle_request(out_fd, buf, (size_t) length) < 0)
Packit 6baad5
            break;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    ret = 0;
Packit 6baad5
Packit 6baad5
fail:
Packit 6baad5
    send_died(out_fd);
Packit 6baad5
Packit 6baad5
    return ret;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
#else
Packit 6baad5
Packit 6baad5
static void* thread_worker(void *p) {
Packit 6baad5
    asyncns_t *asyncns = p;
Packit 6baad5
    sigset_t fullset;
Packit 6baad5
Packit 6baad5
    /* No signals in this thread please */
Packit 6baad5
    sigfillset(&fullset);
Packit 6baad5
    pthread_sigmask(SIG_BLOCK, &fullset, NULL);
Packit 6baad5
Packit 6baad5
    while (!asyncns->dead) {
Packit 6baad5
        packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
Packit 6baad5
        ssize_t length;
Packit 6baad5
Packit 6baad5
        if ((length = recv(asyncns->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0)) <= 0) {
Packit 6baad5
Packit 6baad5
            if (length < 0 &&
Packit 6baad5
                (errno == EAGAIN || errno == EINTR))
Packit 6baad5
                continue;
Packit 6baad5
Packit 6baad5
            break;
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        if (asyncns->dead)
Packit 6baad5
            break;
Packit 6baad5
Packit 6baad5
        if (handle_request(asyncns->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0)
Packit 6baad5
            break;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    send_died(asyncns->fds[RESPONSE_SEND_FD]);
Packit 6baad5
Packit 6baad5
    return NULL;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
asyncns_t* asyncns_new(unsigned n_proc) {
Packit 6baad5
    asyncns_t *asyncns = NULL;
Packit 6baad5
    int i;
Packit 6baad5
    assert(n_proc >= 1);
Packit 6baad5
Packit 6baad5
    if (n_proc > MAX_WORKERS)
Packit 6baad5
        n_proc = MAX_WORKERS;
Packit 6baad5
Packit 6baad5
    if (!(asyncns = malloc(sizeof(asyncns_t)))) {
Packit 6baad5
        errno = ENOMEM;
Packit 6baad5
        goto fail;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    asyncns->dead = 0;
Packit 6baad5
    asyncns->valid_workers = 0;
Packit 6baad5
Packit 6baad5
    for (i = 0; i < MESSAGE_FD_MAX; i++)
Packit 6baad5
        asyncns->fds[i] = -1;
Packit 6baad5
Packit 6baad5
    memset(asyncns->queries, 0, sizeof(asyncns->queries));
Packit 6baad5
Packit 6baad5
    if (socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds) < 0 ||
Packit 6baad5
        socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds+2) < 0)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    for (i = 0; i < MESSAGE_FD_MAX; i++)
Packit 6baad5
        fd_cloexec(asyncns->fds[i]);
Packit 6baad5
Packit 6baad5
    for (asyncns->valid_workers = 0; asyncns->valid_workers < n_proc; asyncns->valid_workers++) {
Packit 6baad5
Packit 6baad5
#ifndef HAVE_PTHREAD
Packit 6baad5
        if ((asyncns->workers[asyncns->valid_workers] = fork()) < 0)
Packit 6baad5
            goto fail;
Packit 6baad5
        else if (asyncns->workers[asyncns->valid_workers] == 0) {
Packit 6baad5
            int ret;
Packit 6baad5
Packit 6baad5
            close(asyncns->fds[REQUEST_SEND_FD]);
Packit 6baad5
            close(asyncns->fds[RESPONSE_RECV_FD]);
Packit 6baad5
            ret = process_worker(asyncns->fds[REQUEST_RECV_FD], asyncns->fds[RESPONSE_SEND_FD]);
Packit 6baad5
            close(asyncns->fds[REQUEST_RECV_FD]);
Packit 6baad5
            close(asyncns->fds[RESPONSE_SEND_FD]);
Packit 6baad5
            _exit(ret);
Packit 6baad5
        }
Packit 6baad5
#else
Packit 6baad5
        int r;
Packit 6baad5
Packit 6baad5
        if ((r = pthread_create(&asyncns->workers[asyncns->valid_workers], NULL, thread_worker, asyncns)) != 0) {
Packit 6baad5
            errno = r;
Packit 6baad5
            goto fail;
Packit 6baad5
        }
Packit 6baad5
#endif
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
#ifndef HAVE_PTHREAD
Packit 6baad5
    close(asyncns->fds[REQUEST_RECV_FD]);
Packit 6baad5
    close(asyncns->fds[RESPONSE_SEND_FD]);
Packit 6baad5
    asyncns->fds[REQUEST_RECV_FD] = asyncns->fds[RESPONSE_SEND_FD] = -1;
Packit 6baad5
#endif
Packit 6baad5
Packit 6baad5
    asyncns->current_index = asyncns->current_id = 0;
Packit 6baad5
    asyncns->done_head = asyncns->done_tail = NULL;
Packit 6baad5
    asyncns->n_queries = 0;
Packit 6baad5
Packit 6baad5
    fd_nonblock(asyncns->fds[RESPONSE_RECV_FD]);
Packit 6baad5
Packit 6baad5
    return asyncns;
Packit 6baad5
Packit 6baad5
fail:
Packit 6baad5
    if (asyncns)
Packit 6baad5
        asyncns_free(asyncns);
Packit 6baad5
Packit 6baad5
    return NULL;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
void asyncns_free(asyncns_t *asyncns) {
Packit 6baad5
    int i;
Packit 6baad5
    int saved_errno = errno;
Packit 6baad5
    unsigned p;
Packit 6baad5
Packit 6baad5
    assert(asyncns);
Packit 6baad5
Packit 6baad5
    asyncns->dead = 1;
Packit 6baad5
Packit 6baad5
    if (asyncns->fds[REQUEST_SEND_FD] >= 0) {
Packit 6baad5
        rheader_t req;
Packit 6baad5
Packit 6baad5
        memset(&req, 0, sizeof(req));
Packit 6baad5
        req.type = REQUEST_TERMINATE;
Packit 6baad5
        req.length = sizeof(req);
Packit 6baad5
        req.id = 0;
Packit 6baad5
Packit 6baad5
        /* Send one termination packet for each worker */
Packit 6baad5
        for (p = 0; p < asyncns->valid_workers; p++)
Packit 6baad5
            send(asyncns->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    /* Now terminate them and wait until they are gone. */
Packit 6baad5
    for (p = 0; p < asyncns->valid_workers; p++) {
Packit 6baad5
#ifndef HAVE_PTHREAD
Packit 6baad5
        kill(asyncns->workers[p], SIGTERM);
Packit 6baad5
        for (;;) {
Packit 6baad5
            if (waitpid(asyncns->workers[p], NULL, 0) >= 0 || errno != EINTR)
Packit 6baad5
                break;
Packit 6baad5
        }
Packit 6baad5
#else
Packit 6baad5
        for (;;) {
Packit 6baad5
            if (pthread_join(asyncns->workers[p], NULL) != EINTR)
Packit 6baad5
                break;
Packit 6baad5
        }
Packit 6baad5
#endif
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    /* Close all communication channels */
Packit 6baad5
    for (i = 0; i < MESSAGE_FD_MAX; i++)
Packit 6baad5
        if (asyncns->fds[i] >= 0)
Packit 6baad5
            close(asyncns->fds[i]);
Packit 6baad5
Packit 6baad5
    for (p = 0; p < MAX_QUERIES; p++)
Packit 6baad5
        if (asyncns->queries[p])
Packit 6baad5
            asyncns_cancel(asyncns, asyncns->queries[p]);
Packit 6baad5
Packit 6baad5
    free(asyncns);
Packit 6baad5
Packit 6baad5
    errno = saved_errno;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
int asyncns_fd(asyncns_t *asyncns) {
Packit 6baad5
    assert(asyncns);
Packit 6baad5
Packit 6baad5
    return asyncns->fds[RESPONSE_RECV_FD];
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static asyncns_query_t *lookup_query(asyncns_t *asyncns, unsigned id) {
Packit 6baad5
    asyncns_query_t *q;
Packit 6baad5
    assert(asyncns);
Packit 6baad5
Packit 6baad5
    if ((q = asyncns->queries[id % MAX_QUERIES]))
Packit 6baad5
        if (q->id == id)
Packit 6baad5
            return q;
Packit 6baad5
Packit 6baad5
    return NULL;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static void complete_query(asyncns_t *asyncns, asyncns_query_t *q) {
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(q);
Packit 6baad5
    assert(!q->done);
Packit 6baad5
Packit 6baad5
    q->done = 1;
Packit 6baad5
Packit 6baad5
    if ((q->done_prev = asyncns->done_tail))
Packit 6baad5
        asyncns->done_tail->done_next = q;
Packit 6baad5
    else
Packit 6baad5
        asyncns->done_head = q;
Packit 6baad5
Packit 6baad5
    asyncns->done_tail = q;
Packit 6baad5
    q->done_next = NULL;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) {
Packit 6baad5
    addrinfo_serialization_t s;
Packit 6baad5
    size_t l;
Packit 6baad5
    struct addrinfo *ai;
Packit 6baad5
    assert(p);
Packit 6baad5
    assert(ret_ai);
Packit 6baad5
    assert(length);
Packit 6baad5
Packit 6baad5
    if (*length < sizeof(addrinfo_serialization_t))
Packit 6baad5
        return NULL;
Packit 6baad5
Packit 6baad5
    memcpy(&s, p, sizeof(s));
Packit 6baad5
Packit 6baad5
    l = sizeof(addrinfo_serialization_t) + s.ai_addrlen + s.canonname_len;
Packit 6baad5
    if (*length < l)
Packit 6baad5
        return NULL;
Packit 6baad5
Packit 6baad5
    if (!(ai = malloc(sizeof(struct addrinfo))))
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    ai->ai_addr = NULL;
Packit 6baad5
    ai->ai_canonname = NULL;
Packit 6baad5
    ai->ai_next = NULL;
Packit 6baad5
Packit 6baad5
    if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen)))
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len)))
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    ai->ai_flags = s.ai_flags;
Packit 6baad5
    ai->ai_family = s.ai_family;
Packit 6baad5
    ai->ai_socktype = s.ai_socktype;
Packit 6baad5
    ai->ai_protocol = s.ai_protocol;
Packit 6baad5
    ai->ai_addrlen = s.ai_addrlen;
Packit 6baad5
Packit 6baad5
    if (ai->ai_addr)
Packit 6baad5
        memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(addrinfo_serialization_t), s.ai_addrlen);
Packit 6baad5
Packit 6baad5
    if (ai->ai_canonname)
Packit 6baad5
        memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(addrinfo_serialization_t) + s.ai_addrlen, s.canonname_len);
Packit 6baad5
Packit 6baad5
    *length -= l;
Packit 6baad5
    *ret_ai = ai;
Packit 6baad5
Packit 6baad5
    return (const uint8_t*) p + l;
Packit 6baad5
Packit 6baad5
Packit 6baad5
fail:
Packit 6baad5
    if (ai)
Packit 6baad5
        asyncns_freeaddrinfo(ai);
Packit 6baad5
Packit 6baad5
    return NULL;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static int handle_response(asyncns_t *asyncns, const packet_t *packet, size_t length) {
Packit 6baad5
    const rheader_t *resp;
Packit 6baad5
    asyncns_query_t *q;
Packit 6baad5
Packit 6baad5
    assert(asyncns);
Packit 6baad5
Packit 6baad5
    resp = &packet->rheader;
Packit 6baad5
    assert(resp);
Packit 6baad5
    assert(length >= sizeof(rheader_t));
Packit 6baad5
    assert(length == resp->length);
Packit 6baad5
Packit 6baad5
    if (resp->type == RESPONSE_DIED) {
Packit 6baad5
        asyncns->dead = 1;
Packit 6baad5
        return 0;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (!(q = lookup_query(asyncns, resp->id)))
Packit 6baad5
        return 0;
Packit 6baad5
Packit 6baad5
    switch (resp->type) {
Packit 6baad5
        case RESPONSE_ADDRINFO: {
Packit 6baad5
            const addrinfo_response_t *ai_resp = &packet->addrinfo_response;
Packit 6baad5
            const void *p;
Packit 6baad5
            size_t l;
Packit 6baad5
            struct addrinfo *prev = NULL;
Packit 6baad5
Packit 6baad5
            assert(length >= sizeof(addrinfo_response_t));
Packit 6baad5
            assert(q->type == REQUEST_ADDRINFO);
Packit 6baad5
Packit 6baad5
            q->ret = ai_resp->ret;
Packit 6baad5
            q->_errno = ai_resp->_errno;
Packit 6baad5
            q->_h_errno = ai_resp->_h_errno;
Packit 6baad5
            l = length - sizeof(addrinfo_response_t);
Packit 6baad5
            p = (const uint8_t*) resp + sizeof(addrinfo_response_t);
Packit 6baad5
Packit 6baad5
            while (l > 0 && p) {
Packit 6baad5
                struct addrinfo *ai = NULL;
Packit 6baad5
                p = unserialize_addrinfo(p, &ai, &l);
Packit 6baad5
Packit 6baad5
                if (!p || !ai) {
Packit 6baad5
                    q->ret = EAI_MEMORY;
Packit 6baad5
                    break;
Packit 6baad5
                }
Packit 6baad5
Packit 6baad5
                if (prev)
Packit 6baad5
                    prev->ai_next = ai;
Packit 6baad5
                else
Packit 6baad5
                    q->addrinfo = ai;
Packit 6baad5
Packit 6baad5
                prev = ai;
Packit 6baad5
            }
Packit 6baad5
Packit 6baad5
            complete_query(asyncns, q);
Packit 6baad5
            break;
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        case RESPONSE_NAMEINFO: {
Packit 6baad5
            const nameinfo_response_t *ni_resp = &packet->nameinfo_response;
Packit 6baad5
Packit 6baad5
            assert(length >= sizeof(nameinfo_response_t));
Packit 6baad5
            assert(q->type == REQUEST_NAMEINFO);
Packit 6baad5
Packit 6baad5
            q->ret = ni_resp->ret;
Packit 6baad5
            q->_errno = ni_resp->_errno;
Packit 6baad5
            q->_h_errno = ni_resp->_h_errno;
Packit 6baad5
Packit 6baad5
            if (ni_resp->hostlen)
Packit 6baad5
                if (!(q->host = strndup((const char*) ni_resp + sizeof(nameinfo_response_t), ni_resp->hostlen-1)))
Packit 6baad5
                    q->ret = EAI_MEMORY;
Packit 6baad5
Packit 6baad5
            if (ni_resp->servlen)
Packit 6baad5
                if (!(q->serv = strndup((const char*) ni_resp + sizeof(nameinfo_response_t) + ni_resp->hostlen, ni_resp->servlen-1)))
Packit 6baad5
                    q->ret = EAI_MEMORY;
Packit 6baad5
Packit 6baad5
            complete_query(asyncns, q);
Packit 6baad5
            break;
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        case RESPONSE_RES: {
Packit 6baad5
            const res_response_t *res_resp = &packet->res_response;
Packit 6baad5
Packit 6baad5
            assert(length >= sizeof(res_response_t));
Packit 6baad5
            assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
Packit 6baad5
Packit 6baad5
            q->ret = res_resp->ret;
Packit 6baad5
            q->_errno = res_resp->_errno;
Packit 6baad5
            q->_h_errno = res_resp->_h_errno;
Packit 6baad5
Packit 6baad5
            if (res_resp->ret >= 0)  {
Packit 6baad5
                if (!(q->serv = malloc(res_resp->ret))) {
Packit 6baad5
                    q->ret = -1;
Packit 6baad5
                    q->_errno = ENOMEM;
Packit 6baad5
                } else
Packit 6baad5
                    memcpy(q->serv, (const char *)resp + sizeof(res_response_t), res_resp->ret);
Packit 6baad5
            }
Packit 6baad5
Packit 6baad5
            complete_query(asyncns, q);
Packit 6baad5
            break;
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        default:
Packit 6baad5
            ;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    return 0;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
int asyncns_wait(asyncns_t *asyncns, int block) {
Packit 6baad5
    int handled = 0;
Packit 6baad5
    assert(asyncns);
Packit 6baad5
Packit 6baad5
    for (;;) {
Packit 6baad5
        packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
Packit 6baad5
        ssize_t l;
Packit 6baad5
Packit 6baad5
        if (asyncns->dead) {
Packit 6baad5
            errno = ECHILD;
Packit 6baad5
            return -1;
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        if (((l = recv(asyncns->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0)) < 0)) {
Packit 6baad5
            fd_set fds;
Packit 6baad5
Packit 6baad5
            if (errno != EAGAIN)
Packit 6baad5
                return -1;
Packit 6baad5
Packit 6baad5
            if (!block || handled)
Packit 6baad5
                return 0;
Packit 6baad5
Packit 6baad5
            FD_ZERO(&fds);
Packit 6baad5
            FD_SET(asyncns->fds[RESPONSE_RECV_FD], &fds);
Packit 6baad5
Packit 6baad5
            if (select(asyncns->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0)
Packit 6baad5
                return -1;
Packit 6baad5
Packit 6baad5
            continue;
Packit 6baad5
        }
Packit 6baad5
Packit 6baad5
        if (handle_response(asyncns, buf, (size_t) l) < 0)
Packit 6baad5
            return -1;
Packit 6baad5
Packit 6baad5
        handled = 1;
Packit 6baad5
    }
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static asyncns_query_t *alloc_query(asyncns_t *asyncns) {
Packit 6baad5
    asyncns_query_t *q;
Packit 6baad5
    assert(asyncns);
Packit 6baad5
Packit 6baad5
    if (asyncns->n_queries >= MAX_QUERIES) {
Packit 6baad5
        errno = ENOMEM;
Packit 6baad5
        return NULL;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    while (asyncns->queries[asyncns->current_index]) {
Packit 6baad5
Packit 6baad5
        asyncns->current_index++;
Packit 6baad5
        asyncns->current_id++;
Packit 6baad5
Packit 6baad5
        while (asyncns->current_index >= MAX_QUERIES)
Packit 6baad5
            asyncns->current_index -= MAX_QUERIES;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (!(q = asyncns->queries[asyncns->current_index] = malloc(sizeof(asyncns_query_t)))) {
Packit 6baad5
        errno = ENOMEM;
Packit 6baad5
        return NULL;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    asyncns->n_queries++;
Packit 6baad5
Packit 6baad5
    q->asyncns = asyncns;
Packit 6baad5
    q->done = 0;
Packit 6baad5
    q->id = asyncns->current_id;
Packit 6baad5
    q->done_next = q->done_prev = NULL;
Packit 6baad5
    q->ret = 0;
Packit 6baad5
    q->_errno = 0;
Packit 6baad5
    q->_h_errno = 0;
Packit 6baad5
    q->addrinfo = NULL;
Packit 6baad5
    q->userdata = NULL;
Packit 6baad5
    q->host = q->serv = NULL;
Packit 6baad5
Packit 6baad5
    return q;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
asyncns_query_t* asyncns_getaddrinfo(asyncns_t *asyncns, const char *node, const char *service, const struct addrinfo *hints) {
Packit 6baad5
    addrinfo_request_t data[BUFSIZE/sizeof(addrinfo_request_t) + 1];
Packit 6baad5
    addrinfo_request_t *req = data;
Packit 6baad5
    asyncns_query_t *q;
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(node || service);
Packit 6baad5
Packit 6baad5
    if (asyncns->dead) {
Packit 6baad5
        errno = ECHILD;
Packit 6baad5
        return NULL;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (!(q = alloc_query(asyncns)))
Packit 6baad5
        return NULL;
Packit 6baad5
Packit 6baad5
    memset(req, 0, sizeof(addrinfo_request_t));
Packit 6baad5
Packit 6baad5
    req->node_len = node ? strlen(node)+1 : 0;
Packit 6baad5
    req->service_len = service ? strlen(service)+1 : 0;
Packit 6baad5
Packit 6baad5
    req->header.id = q->id;
Packit 6baad5
    req->header.type = q->type = REQUEST_ADDRINFO;
Packit 6baad5
    req->header.length = sizeof(addrinfo_request_t) + req->node_len + req->service_len;
Packit 6baad5
Packit 6baad5
    if (req->header.length > BUFSIZE) {
Packit 6baad5
        errno = ENOMEM;
Packit 6baad5
        goto fail;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (!(req->hints_is_null = !hints)) {
Packit 6baad5
        req->ai_flags = hints->ai_flags;
Packit 6baad5
        req->ai_family = hints->ai_family;
Packit 6baad5
        req->ai_socktype = hints->ai_socktype;
Packit 6baad5
        req->ai_protocol = hints->ai_protocol;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (node)
Packit 6baad5
        strcpy((char*) req + sizeof(addrinfo_request_t), node);
Packit 6baad5
Packit 6baad5
    if (service)
Packit 6baad5
        strcpy((char*) req + sizeof(addrinfo_request_t) + req->node_len, service);
Packit 6baad5
Packit 6baad5
    if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    return q;
Packit 6baad5
Packit 6baad5
fail:
Packit 6baad5
    if (q)
Packit 6baad5
        asyncns_cancel(asyncns, q);
Packit 6baad5
Packit 6baad5
    return NULL;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
int asyncns_getaddrinfo_done(asyncns_t *asyncns, asyncns_query_t* q, struct addrinfo **ret_res) {
Packit 6baad5
    int ret;
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(q);
Packit 6baad5
    assert(q->asyncns == asyncns);
Packit 6baad5
    assert(q->type == REQUEST_ADDRINFO);
Packit 6baad5
Packit 6baad5
    if (asyncns->dead) {
Packit 6baad5
        errno = ECHILD;
Packit 6baad5
        return EAI_SYSTEM;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (!q->done)
Packit 6baad5
        return EAI_AGAIN;
Packit 6baad5
Packit 6baad5
    *ret_res = q->addrinfo;
Packit 6baad5
    q->addrinfo = NULL;
Packit 6baad5
Packit 6baad5
    ret = q->ret;
Packit 6baad5
Packit 6baad5
    if (ret == EAI_SYSTEM)
Packit 6baad5
        errno = q->_errno;
Packit 6baad5
Packit 6baad5
    if (ret != 0)
Packit 6baad5
        h_errno = q->_h_errno;
Packit 6baad5
Packit 6baad5
    asyncns_cancel(asyncns, q);
Packit 6baad5
Packit 6baad5
    return ret;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
asyncns_query_t* asyncns_getnameinfo(asyncns_t *asyncns, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv) {
Packit 6baad5
    nameinfo_request_t data[BUFSIZE/sizeof(nameinfo_request_t) + 1];
Packit 6baad5
    nameinfo_request_t *req = data;
Packit 6baad5
    asyncns_query_t *q;
Packit 6baad5
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(sa);
Packit 6baad5
    assert(salen > 0);
Packit 6baad5
Packit 6baad5
    if (asyncns->dead) {
Packit 6baad5
        errno = ECHILD;
Packit 6baad5
        return NULL;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (!(q = alloc_query(asyncns)))
Packit 6baad5
        return NULL;
Packit 6baad5
Packit 6baad5
    memset(req, 0, sizeof(nameinfo_request_t));
Packit 6baad5
Packit 6baad5
    req->header.id = q->id;
Packit 6baad5
    req->header.type = q->type = REQUEST_NAMEINFO;
Packit 6baad5
    req->header.length = sizeof(nameinfo_request_t) + salen;
Packit 6baad5
Packit 6baad5
    if (req->header.length > BUFSIZE) {
Packit 6baad5
        errno = ENOMEM;
Packit 6baad5
        goto fail;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    req->flags = flags;
Packit 6baad5
    req->sockaddr_len = salen;
Packit 6baad5
    req->gethost = gethost;
Packit 6baad5
    req->getserv = getserv;
Packit 6baad5
Packit 6baad5
    memcpy((uint8_t*) req + sizeof(nameinfo_request_t), sa, salen);
Packit 6baad5
Packit 6baad5
    if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    return q;
Packit 6baad5
Packit 6baad5
fail:
Packit 6baad5
    if (q)
Packit 6baad5
        asyncns_cancel(asyncns, q);
Packit 6baad5
Packit 6baad5
    return NULL;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
int asyncns_getnameinfo_done(asyncns_t *asyncns, asyncns_query_t* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) {
Packit 6baad5
    int ret;
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(q);
Packit 6baad5
    assert(q->asyncns == asyncns);
Packit 6baad5
    assert(q->type == REQUEST_NAMEINFO);
Packit 6baad5
    assert(!ret_host || hostlen);
Packit 6baad5
    assert(!ret_serv || servlen);
Packit 6baad5
Packit 6baad5
    if (asyncns->dead) {
Packit 6baad5
        errno = ECHILD;
Packit 6baad5
        return EAI_SYSTEM;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (!q->done)
Packit 6baad5
        return EAI_AGAIN;
Packit 6baad5
Packit 6baad5
    if (ret_host && q->host) {
Packit 6baad5
        strncpy(ret_host, q->host, hostlen);
Packit 6baad5
        ret_host[hostlen-1] = 0;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (ret_serv && q->serv) {
Packit 6baad5
        strncpy(ret_serv, q->serv, servlen);
Packit 6baad5
        ret_serv[servlen-1] = 0;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    ret = q->ret;
Packit 6baad5
Packit 6baad5
    if (ret == EAI_SYSTEM)
Packit 6baad5
        errno = q->_errno;
Packit 6baad5
Packit 6baad5
    if (ret != 0)
Packit 6baad5
        h_errno = q->_h_errno;
Packit 6baad5
Packit 6baad5
    asyncns_cancel(asyncns, q);
Packit 6baad5
Packit 6baad5
    return ret;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
static asyncns_query_t * asyncns_res(asyncns_t *asyncns, query_type_t qtype, const char *dname, int class, int type) {
Packit 6baad5
    res_request_t data[BUFSIZE/sizeof(res_request_t) + 1];
Packit 6baad5
    res_request_t *req = data;
Packit 6baad5
    asyncns_query_t *q;
Packit 6baad5
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(dname);
Packit 6baad5
Packit 6baad5
    if (asyncns->dead) {
Packit 6baad5
        errno = ECHILD;
Packit 6baad5
        return NULL;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (!(q = alloc_query(asyncns)))
Packit 6baad5
        return NULL;
Packit 6baad5
Packit 6baad5
    memset(req, 0, sizeof(res_request_t));
Packit 6baad5
Packit 6baad5
    req->dname_len = strlen(dname) + 1;
Packit 6baad5
Packit 6baad5
    req->header.id = q->id;
Packit 6baad5
    req->header.type = q->type = qtype;
Packit 6baad5
    req->header.length = sizeof(res_request_t) + req->dname_len;
Packit 6baad5
Packit 6baad5
    if (req->header.length > BUFSIZE) {
Packit 6baad5
        errno = ENOMEM;
Packit 6baad5
        goto fail;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    req->class = class;
Packit 6baad5
    req->type = type;
Packit 6baad5
Packit 6baad5
    strcpy((char*) req + sizeof(res_request_t), dname);
Packit 6baad5
Packit 6baad5
    if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
Packit 6baad5
        goto fail;
Packit 6baad5
Packit 6baad5
    return q;
Packit 6baad5
Packit 6baad5
fail:
Packit 6baad5
    if (q)
Packit 6baad5
        asyncns_cancel(asyncns, q);
Packit 6baad5
Packit 6baad5
    return NULL;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
asyncns_query_t* asyncns_res_query(asyncns_t *asyncns, const char *dname, int class, int type) {
Packit 6baad5
    return asyncns_res(asyncns, REQUEST_RES_QUERY, dname, class, type);
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
asyncns_query_t* asyncns_res_search(asyncns_t *asyncns, const char *dname, int class, int type) {
Packit 6baad5
    return asyncns_res(asyncns, REQUEST_RES_SEARCH, dname, class, type);
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
int asyncns_res_done(asyncns_t *asyncns, asyncns_query_t* q, unsigned char **answer) {
Packit 6baad5
    int ret;
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(q);
Packit 6baad5
    assert(q->asyncns == asyncns);
Packit 6baad5
    assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
Packit 6baad5
    assert(answer);
Packit 6baad5
Packit 6baad5
    if (asyncns->dead) {
Packit 6baad5
        errno = ECHILD;
Packit 6baad5
        return -ECHILD;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    if (!q->done) {
Packit 6baad5
        errno = EAGAIN;
Packit 6baad5
        return -EAGAIN;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    *answer = (unsigned char *)q->serv;
Packit 6baad5
    q->serv = NULL;
Packit 6baad5
Packit 6baad5
    ret = q->ret;
Packit 6baad5
Packit 6baad5
    if (ret < 0) {
Packit 6baad5
        errno = q->_errno;
Packit 6baad5
        h_errno = q->_h_errno;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    asyncns_cancel(asyncns, q);
Packit 6baad5
Packit 6baad5
    return ret < 0 ? -errno : ret;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
asyncns_query_t* asyncns_getnext(asyncns_t *asyncns) {
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    return asyncns->done_head;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
int asyncns_getnqueries(asyncns_t *asyncns) {
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    return asyncns->n_queries;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
void asyncns_cancel(asyncns_t *asyncns, asyncns_query_t* q) {
Packit 6baad5
    int i;
Packit 6baad5
    int saved_errno = errno;
Packit 6baad5
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(q);
Packit 6baad5
    assert(q->asyncns == asyncns);
Packit 6baad5
    assert(asyncns->n_queries > 0);
Packit 6baad5
Packit 6baad5
    if (q->done) {
Packit 6baad5
Packit 6baad5
        if (q->done_prev)
Packit 6baad5
            q->done_prev->done_next = q->done_next;
Packit 6baad5
        else
Packit 6baad5
            asyncns->done_head = q->done_next;
Packit 6baad5
Packit 6baad5
        if (q->done_next)
Packit 6baad5
            q->done_next->done_prev = q->done_prev;
Packit 6baad5
        else
Packit 6baad5
            asyncns->done_tail = q->done_prev;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    i = q->id % MAX_QUERIES;
Packit 6baad5
    assert(asyncns->queries[i] == q);
Packit 6baad5
    asyncns->queries[i] = NULL;
Packit 6baad5
Packit 6baad5
    asyncns_freeaddrinfo(q->addrinfo);
Packit 6baad5
    free(q->host);
Packit 6baad5
    free(q->serv);
Packit 6baad5
Packit 6baad5
    asyncns->n_queries--;
Packit 6baad5
    free(q);
Packit 6baad5
Packit 6baad5
    errno = saved_errno;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
void asyncns_freeaddrinfo(struct addrinfo *ai) {
Packit 6baad5
    int saved_errno = errno;
Packit 6baad5
Packit 6baad5
    while (ai) {
Packit 6baad5
        struct addrinfo *next = ai->ai_next;
Packit 6baad5
Packit 6baad5
        free(ai->ai_addr);
Packit 6baad5
        free(ai->ai_canonname);
Packit 6baad5
        free(ai);
Packit 6baad5
Packit 6baad5
        ai = next;
Packit 6baad5
    }
Packit 6baad5
Packit 6baad5
    errno = saved_errno;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
void asyncns_freeanswer(unsigned char *answer) {
Packit 6baad5
    int saved_errno = errno;
Packit 6baad5
Packit 6baad5
    if (!answer)
Packit 6baad5
        return;
Packit 6baad5
Packit 6baad5
    /* Please note that this function is new in libasyncns 0.4. In
Packit 6baad5
     * older versions you were supposed to free the answer directly
Packit 6baad5
     * with free(). Hence, if this function is changed to do more than
Packit 6baad5
     * just a simple free() this must be considered ABI/API breakage! */
Packit 6baad5
Packit 6baad5
    free(answer);
Packit 6baad5
Packit 6baad5
    errno = saved_errno;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
int asyncns_isdone(asyncns_t *asyncns, asyncns_query_t*q) {
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(q);
Packit 6baad5
    assert(q->asyncns == asyncns);
Packit 6baad5
Packit 6baad5
    return q->done;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
void asyncns_setuserdata(asyncns_t *asyncns, asyncns_query_t *q, void *userdata) {
Packit 6baad5
    assert(q);
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(q->asyncns = asyncns);
Packit 6baad5
Packit 6baad5
    q->userdata = userdata;
Packit 6baad5
}
Packit 6baad5
Packit 6baad5
void* asyncns_getuserdata(asyncns_t *asyncns, asyncns_query_t *q) {
Packit 6baad5
    assert(q);
Packit 6baad5
    assert(asyncns);
Packit 6baad5
    assert(q->asyncns = asyncns);
Packit 6baad5
Packit 6baad5
    return q->userdata;
Packit 6baad5
}