mirror of
https://github.com/libevent/libevent.git
synced 2025-01-09 00:56:20 +08:00
Add locks to evdns.
svn:r1204
This commit is contained in:
parent
ac3fc9913a
commit
327165b339
295
evdns.c
295
evdns.c
@ -102,12 +102,19 @@
|
||||
#include <event2/dns_struct.h>
|
||||
#include <event2/dns_compat.h>
|
||||
#include <event2/util.h>
|
||||
#include <event2/event.h>
|
||||
#include <event2/event_struct.h>
|
||||
#include <event2/thread.h>
|
||||
#include <event2/event.h>
|
||||
#include <event2/event_struct.h>
|
||||
#include <event2/thread.h>
|
||||
|
||||
#include "log-internal.h"
|
||||
#include "mm-internal.h"
|
||||
#include "strlcpy-internal.h"
|
||||
#include "ipv6-internal.h"
|
||||
#include "util-internal.h"
|
||||
#include "evthread-internal.h"
|
||||
#ifdef WIN32
|
||||
#include <ctype.h>
|
||||
#include <winsock2.h>
|
||||
@ -141,8 +148,6 @@
|
||||
/* libevent doesn't work without this */
|
||||
typedef unsigned int uint;
|
||||
#endif
|
||||
#include "event2/event.h"
|
||||
#include "event2/event_struct.h"
|
||||
|
||||
#define u64 ev_uint64_t
|
||||
#define u32 ev_uint32_t
|
||||
@ -244,6 +249,11 @@ struct evdns_server_port {
|
||||
/* circular list of replies that we want to write. */
|
||||
struct server_request *pending_replies;
|
||||
struct event_base *event_base;
|
||||
|
||||
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
|
||||
void *lock;
|
||||
int lock_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Represents part of a reply being built. (That is, a single RR.) */
|
||||
@ -329,6 +339,11 @@ struct evdns_base {
|
||||
socklen_t global_outgoing_addrlen;
|
||||
|
||||
struct search_state *global_search_state;
|
||||
|
||||
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
|
||||
void *lock;
|
||||
int lock_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct evdns_base *current_base = NULL;
|
||||
@ -365,9 +380,35 @@ static int server_request_free(struct server_request *req);
|
||||
static void server_request_free_answers(struct server_request *req);
|
||||
static void server_port_free(struct evdns_server_port *port);
|
||||
static void server_port_ready_callback(evutil_socket_t fd, short events, void *arg);
|
||||
static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename);
|
||||
static int evdns_base_set_option_impl(struct evdns_base *base,
|
||||
const char *option, const char *val, int flags);
|
||||
|
||||
static int strtoint(const char *const str);
|
||||
|
||||
#ifdef _EVENT_DISABLE_THREAD_SUPPORT
|
||||
#define EVDNS_LOCK(base) _EVUTIL_NIL_STMT
|
||||
#define EVDNS_UNLOCK(base) _EVUTIL_NIL_STMT
|
||||
#define ASSERT_LOCKED(base) _EVUTIL_NIL_STMT
|
||||
#else
|
||||
#define EVDNS_LOCK(base) \
|
||||
do { \
|
||||
if ((base)->lock) { \
|
||||
EVLOCK_LOCK((base)->lock, EVTHREAD_WRITE); \
|
||||
} \
|
||||
++(base)->lock_count; \
|
||||
} while (0)
|
||||
#define EVDNS_UNLOCK(base) \
|
||||
do { \
|
||||
assert((base)->lock_count > 0); \
|
||||
--(base)->lock_count; \
|
||||
if ((base)->lock) { \
|
||||
EVLOCK_UNLOCK((base)->lock, EVTHREAD_WRITE); \
|
||||
} \
|
||||
} while (0)
|
||||
#define ASSERT_LOCKED(base) assert((base)->lock_count > 0)
|
||||
#endif
|
||||
|
||||
#define CLOSE_SOCKET(s) EVUTIL_CLOSESOCKET(s)
|
||||
|
||||
static const char *
|
||||
@ -473,6 +514,8 @@ request_find_from_trans_id(struct evdns_base *base, u16 trans_id) {
|
||||
struct evdns_request *req = REQ_HEAD(base, trans_id);
|
||||
struct evdns_request *const started_at = req;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
|
||||
if (req) {
|
||||
do {
|
||||
if (req->trans_id == trans_id) return req;
|
||||
@ -491,7 +534,9 @@ nameserver_prod_callback(evutil_socket_t fd, short events, void *arg) {
|
||||
(void)fd;
|
||||
(void)events;
|
||||
|
||||
EVDNS_LOCK(ns->base);
|
||||
nameserver_send_probe(ns);
|
||||
EVDNS_UNLOCK(ns->base);
|
||||
}
|
||||
|
||||
/* a libevent callback which is called when a nameserver probe (to see if */
|
||||
@ -500,6 +545,8 @@ nameserver_prod_callback(evutil_socket_t fd, short events, void *arg) {
|
||||
static void
|
||||
nameserver_probe_failed(struct nameserver *const ns) {
|
||||
const struct timeval * timeout;
|
||||
|
||||
ASSERT_LOCKED(ns->base);
|
||||
(void) evtimer_del(&ns->timeout_event);
|
||||
if (ns->state == 1) {
|
||||
/* This can happen if the nameserver acts in a way which makes us mark */
|
||||
@ -529,6 +576,8 @@ nameserver_failed(struct nameserver *const ns, const char *msg) {
|
||||
struct evdns_request *req, *started_at;
|
||||
struct evdns_base *base = ns->base;
|
||||
int i;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
/* if this nameserver has already been marked as failed */
|
||||
/* then don't do anything */
|
||||
if (!ns->state) return;
|
||||
@ -578,6 +627,7 @@ nameserver_failed(struct nameserver *const ns, const char *msg) {
|
||||
|
||||
static void
|
||||
nameserver_up(struct nameserver *const ns) {
|
||||
EVDNS_LOCK(ns->base);
|
||||
if (ns->state) return;
|
||||
log(EVDNS_LOG_WARN, "Nameserver %s is back up",
|
||||
debug_ntop((struct sockaddr *)&ns->address));
|
||||
@ -605,6 +655,7 @@ static void
|
||||
request_finished(struct evdns_request *const req, struct evdns_request **head) {
|
||||
struct evdns_base *base = req->base;
|
||||
int was_inflight = (head != &base->req_waiting_head);
|
||||
EVDNS_LOCK(req->base);
|
||||
if (head)
|
||||
evdns_request_remove(req, head);
|
||||
|
||||
@ -640,6 +691,7 @@ request_finished(struct evdns_request *const req, struct evdns_request **head) {
|
||||
static int
|
||||
request_reissue(struct evdns_request *req) {
|
||||
const struct nameserver *const last_ns = req->ns;
|
||||
ASSERT_LOCKED(req->base);
|
||||
/* the last nameserver should have been marked as failing */
|
||||
/* by the caller of this function, therefore pick will try */
|
||||
/* not to return it */
|
||||
@ -662,6 +714,7 @@ request_reissue(struct evdns_request *req) {
|
||||
/* requests from the waiting queue if it can. */
|
||||
static void
|
||||
evdns_requests_pump_waiting_queue(struct evdns_base *base) {
|
||||
ASSERT_LOCKED(base);
|
||||
while (base->global_requests_inflight < base->global_max_requests_inflight &&
|
||||
base->global_requests_waiting) {
|
||||
struct evdns_request *req;
|
||||
@ -684,6 +737,7 @@ evdns_requests_pump_waiting_queue(struct evdns_base *base) {
|
||||
|
||||
static void
|
||||
reply_callback(struct evdns_request *const req, u32 ttl, u32 err, struct reply *reply) {
|
||||
/* TODO(nickm) This nees to be deferred. */
|
||||
switch (req->request_type) {
|
||||
case TYPE_A:
|
||||
if (reply)
|
||||
@ -726,6 +780,8 @@ reply_handle(struct evdns_request *const req, u16 flags, u32 ttl, struct reply *
|
||||
DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
|
||||
};
|
||||
|
||||
ASSERT_LOCKED(req->base);
|
||||
|
||||
if (flags & 0x020f || !reply || !reply->have_answer) {
|
||||
/* there was an error */
|
||||
if (flags & 0x0200) {
|
||||
@ -863,6 +919,8 @@ reply_parse(struct evdns_base *base, u8 *packet, int length) {
|
||||
struct evdns_request *req = NULL;
|
||||
unsigned int i;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
|
||||
GET16(trans_id);
|
||||
GET16(flags);
|
||||
GET16(questions);
|
||||
@ -1016,6 +1074,8 @@ request_parse(u8 *packet, int length, struct evdns_server_port *port, struct soc
|
||||
u16 trans_id, flags, questions, answers, authority, additional;
|
||||
struct server_request *server_req = NULL;
|
||||
|
||||
ASSERT_LOCKED(port);
|
||||
|
||||
/* Get the header fields */
|
||||
GET16(trans_id);
|
||||
GET16(flags);
|
||||
@ -1181,6 +1241,7 @@ evdns_set_random_bytes_fn(void (*fn)(char *, size_t))
|
||||
/* Try to choose a strong transaction id which isn't already in flight */
|
||||
static u16
|
||||
transaction_id_pick(struct evdns_base *base) {
|
||||
ASSERT_LOCKED(base);
|
||||
for (;;) {
|
||||
u16 trans_id = trans_id_function();
|
||||
|
||||
@ -1197,6 +1258,7 @@ transaction_id_pick(struct evdns_base *base) {
|
||||
static struct nameserver *
|
||||
nameserver_pick(struct evdns_base *base) {
|
||||
struct nameserver *started_at = base->server_head, *picked;
|
||||
ASSERT_LOCKED(base);
|
||||
if (!base->server_head) return NULL;
|
||||
|
||||
/* if we don't have any good nameservers then there's no */
|
||||
@ -1234,6 +1296,7 @@ nameserver_read(struct nameserver *ns) {
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t addrlen = sizeof(ss);
|
||||
u8 packet[1500];
|
||||
ASSERT_LOCKED(ns->base);
|
||||
|
||||
for (;;) {
|
||||
const int r = recvfrom(ns->socket, packet, sizeof(packet), 0,
|
||||
@ -1267,6 +1330,7 @@ server_port_read(struct evdns_server_port *s) {
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int r;
|
||||
ASSERT_LOCKED(s);
|
||||
|
||||
for (;;) {
|
||||
addrlen = sizeof(struct sockaddr_storage);
|
||||
@ -1288,6 +1352,7 @@ server_port_read(struct evdns_server_port *s) {
|
||||
static void
|
||||
server_port_flush(struct evdns_server_port *port)
|
||||
{
|
||||
ASSERT_LOCKED(port);
|
||||
while (port->pending_replies) {
|
||||
struct server_request *req = port->pending_replies;
|
||||
int r = sendto(port->socket, req->response, req->response_len, 0,
|
||||
@ -1321,6 +1386,7 @@ server_port_flush(struct evdns_server_port *port)
|
||||
/* we stop these events. */
|
||||
static void
|
||||
nameserver_write_waiting(struct nameserver *ns, char waiting) {
|
||||
ASSERT_LOCKED(ns->base);
|
||||
if (ns->write_waiting == waiting) return;
|
||||
|
||||
ns->write_waiting = waiting;
|
||||
@ -1342,6 +1408,7 @@ nameserver_ready_callback(evutil_socket_t fd, short events, void *arg) {
|
||||
struct nameserver *ns = (struct nameserver *) arg;
|
||||
(void)fd;
|
||||
|
||||
EVDNS_LOCK(ns->base);
|
||||
if (events & EV_WRITE) {
|
||||
ns->choked = 0;
|
||||
if (!evdns_transmit(ns->base)) {
|
||||
@ -1351,6 +1418,7 @@ nameserver_ready_callback(evutil_socket_t fd, short events, void *arg) {
|
||||
if (events & EV_READ) {
|
||||
nameserver_read(ns);
|
||||
}
|
||||
EVDNS_UNLOCK(ns->base);
|
||||
}
|
||||
|
||||
/* a callback function. Called by libevent when the kernel says that */
|
||||
@ -1360,6 +1428,7 @@ server_port_ready_callback(evutil_socket_t fd, short events, void *arg) {
|
||||
struct evdns_server_port *port = (struct evdns_server_port *) arg;
|
||||
(void) fd;
|
||||
|
||||
EVDNS_LOCK(port);
|
||||
if (events & EV_WRITE) {
|
||||
port->choked = 0;
|
||||
server_port_flush(port);
|
||||
@ -1367,6 +1436,7 @@ server_port_ready_callback(evutil_socket_t fd, short events, void *arg) {
|
||||
if (events & EV_READ) {
|
||||
server_port_read(port);
|
||||
}
|
||||
EVDNS_UNLOCK(port);
|
||||
}
|
||||
|
||||
/* This is an inefficient representation; only use it via the dnslabel_table_*
|
||||
@ -1572,6 +1642,7 @@ evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket,
|
||||
mm_free(port);
|
||||
return NULL;
|
||||
}
|
||||
EVTHREAD_ALLOC_LOCK(port->lock);
|
||||
return port;
|
||||
}
|
||||
|
||||
@ -1585,9 +1656,13 @@ evdns_add_server_port(evutil_socket_t socket, int is_tcp, evdns_request_callback
|
||||
void
|
||||
evdns_close_server_port(struct evdns_server_port *port)
|
||||
{
|
||||
if (--port->refcnt == 0)
|
||||
EVDNS_LOCK(port);
|
||||
if (--port->refcnt == 0) {
|
||||
EVDNS_UNLOCK(port);
|
||||
server_port_free(port);
|
||||
port->closing = 1;
|
||||
} else {
|
||||
port->closing = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* exported function */
|
||||
@ -1597,9 +1672,11 @@ evdns_server_request_add_reply(struct evdns_server_request *_req, int section, c
|
||||
struct server_request *req = TO_SERVER_REQUEST(_req);
|
||||
struct server_reply_item **itemp, *item;
|
||||
int *countp;
|
||||
int result = -1;
|
||||
|
||||
EVDNS_LOCK(req->port);
|
||||
if (req->response) /* have we already answered? */
|
||||
return (-1);
|
||||
goto done;
|
||||
|
||||
switch (section) {
|
||||
case EVDNS_ANSWER_SECTION:
|
||||
@ -1615,18 +1692,18 @@ evdns_server_request_add_reply(struct evdns_server_request *_req, int section, c
|
||||
countp = &req->n_additional;
|
||||
break;
|
||||
default:
|
||||
return (-1);
|
||||
goto done;
|
||||
}
|
||||
while (*itemp) {
|
||||
itemp = &((*itemp)->next);
|
||||
}
|
||||
item = mm_malloc(sizeof(struct server_reply_item));
|
||||
if (!item)
|
||||
return -1;
|
||||
goto done;
|
||||
item->next = NULL;
|
||||
if (!(item->name = mm_strdup(name))) {
|
||||
mm_free(item);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
item->type = type;
|
||||
item->dns_question_class = class;
|
||||
@ -1639,14 +1716,14 @@ evdns_server_request_add_reply(struct evdns_server_request *_req, int section, c
|
||||
if (!(item->data = mm_strdup(data))) {
|
||||
mm_free(item->name);
|
||||
mm_free(item);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
item->datalen = (u16)-1;
|
||||
} else {
|
||||
if (!(item->data = mm_malloc(datalen))) {
|
||||
mm_free(item->name);
|
||||
mm_free(item);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
item->datalen = datalen;
|
||||
memcpy(item->data, data, datalen);
|
||||
@ -1655,7 +1732,10 @@ evdns_server_request_add_reply(struct evdns_server_request *_req, int section, c
|
||||
|
||||
*itemp = item;
|
||||
++(*countp);
|
||||
return 0;
|
||||
result = 0;
|
||||
done:
|
||||
EVDNS_UNLOCK(req->port);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* exported function */
|
||||
@ -1819,10 +1899,12 @@ evdns_server_request_respond(struct evdns_server_request *_req, int err)
|
||||
{
|
||||
struct server_request *req = TO_SERVER_REQUEST(_req);
|
||||
struct evdns_server_port *port = req->port;
|
||||
int r;
|
||||
int r = -1;
|
||||
|
||||
EVDNS_LOCK(port);
|
||||
if (!req->response) {
|
||||
if ((r = evdns_server_request_format_response(req, err))<0)
|
||||
return r;
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = sendto(port->socket, req->response, req->response_len, 0,
|
||||
@ -1830,7 +1912,7 @@ evdns_server_request_respond(struct evdns_server_request *_req, int err)
|
||||
if (r<0) {
|
||||
int sock_err = evutil_socket_geterror(port->socket);
|
||||
if (EVUTIL_ERR_RW_RETRIABLE(sock_err))
|
||||
return -1;
|
||||
goto done;
|
||||
|
||||
if (port->pending_replies) {
|
||||
req->prev_pending = port->pending_replies->prev_pending;
|
||||
@ -1851,15 +1933,21 @@ evdns_server_request_respond(struct evdns_server_request *_req, int err)
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
r = 1;
|
||||
goto done;
|
||||
}
|
||||
if (server_request_free(req)) {
|
||||
r = 0;
|
||||
goto done;
|
||||
}
|
||||
if (server_request_free(req))
|
||||
return 0;
|
||||
|
||||
if (port->pending_replies)
|
||||
server_port_flush(port);
|
||||
|
||||
return 0;
|
||||
r = 0;
|
||||
done:
|
||||
EVDNS_UNLOCK(port);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Free all storage held by RRs in req. */
|
||||
@ -1894,7 +1982,7 @@ server_request_free_answers(struct server_request *req)
|
||||
static int
|
||||
server_request_free(struct server_request *req)
|
||||
{
|
||||
int i, rc=1;
|
||||
int i, rc=1, lock=0;
|
||||
if (req->base.questions) {
|
||||
for (i = 0; i < req->base.nquestions; ++i)
|
||||
mm_free(req->base.questions[i]);
|
||||
@ -1902,6 +1990,8 @@ server_request_free(struct server_request *req)
|
||||
}
|
||||
|
||||
if (req->port) {
|
||||
EVDNS_LOCK(req->port);
|
||||
lock=1;
|
||||
if (req->port->pending_replies == req) {
|
||||
if (req->next_pending)
|
||||
req->port->pending_replies = req->next_pending;
|
||||
@ -1923,10 +2013,13 @@ server_request_free(struct server_request *req)
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
EVDNS_UNLOCK(req->port); /* ????? nickm */
|
||||
server_port_free(req->port);
|
||||
mm_free(req);
|
||||
return (1);
|
||||
}
|
||||
if (lock)
|
||||
EVDNS_UNLOCK(req->port);
|
||||
mm_free(req);
|
||||
return (0);
|
||||
}
|
||||
@ -1943,6 +2036,7 @@ server_port_free(struct evdns_server_port *port)
|
||||
port->socket = -1;
|
||||
}
|
||||
(void) event_del(&port->event);
|
||||
EVTHREAD_FREE_LOCK(port->lock);
|
||||
mm_free(port);
|
||||
}
|
||||
|
||||
@ -1978,6 +2072,7 @@ evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
|
||||
(void) events;
|
||||
|
||||
log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
|
||||
EVDNS_LOCK(req->base);
|
||||
|
||||
req->ns->timedout++;
|
||||
if (req->ns->timedout > req->base->global_max_nameserver_timeout) {
|
||||
@ -1994,6 +2089,7 @@ evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
|
||||
(void) evtimer_del(&req->timeout_event);
|
||||
evdns_request_transmit(req);
|
||||
}
|
||||
EVDNS_UNLOCK(req->base);
|
||||
}
|
||||
|
||||
/* try to send a request to a given server. */
|
||||
@ -2004,7 +2100,9 @@ evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
|
||||
/* 2 other failure */
|
||||
static int
|
||||
evdns_request_transmit_to(struct evdns_request *req, struct nameserver *server) {
|
||||
const int r = send(server->socket, req->request, req->request_len, 0);
|
||||
int r;
|
||||
ASSERT_LOCKED(req->base);
|
||||
r = send(server->socket, req->request, req->request_len, 0);
|
||||
if (r < 0) {
|
||||
int err = evutil_socket_geterror(server->socket);
|
||||
if (EVUTIL_ERR_RW_RETRIABLE(err))
|
||||
@ -2028,6 +2126,7 @@ static int
|
||||
evdns_request_transmit(struct evdns_request *req) {
|
||||
int retcode = 0, r;
|
||||
|
||||
ASSERT_LOCKED(req->base);
|
||||
/* if we fail to send this packet then this flag marks it */
|
||||
/* for evdns_transmit */
|
||||
req->transmit_me = 1;
|
||||
@ -2076,6 +2175,8 @@ nameserver_probe_callback(int result, char type, int count, int ttl, void *addre
|
||||
(void) count;
|
||||
(void) ttl;
|
||||
(void) addresses;
|
||||
|
||||
EVDNS_LOCK(ns->base);
|
||||
ns->probe_request = NULL;
|
||||
if (result == DNS_ERR_CANCEL) {
|
||||
/* We canceled this request because the nameserver came up
|
||||
@ -2087,6 +2188,7 @@ nameserver_probe_callback(int result, char type, int count, int ttl, void *addre
|
||||
} else {
|
||||
nameserver_probe_failed(ns);
|
||||
}
|
||||
EVDNS_UNLOCK(ns->base);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2095,6 +2197,7 @@ nameserver_send_probe(struct nameserver *const ns) {
|
||||
/* here we need to send a probe to a given nameserver */
|
||||
/* in the hope that it is up now. */
|
||||
|
||||
ASSERT_LOCKED(ns->base);
|
||||
log(EVDNS_LOG_DEBUG, "Sending probe to %s",
|
||||
debug_ntop((struct sockaddr *)&ns->address));
|
||||
|
||||
@ -2115,6 +2218,7 @@ evdns_transmit(struct evdns_base *base) {
|
||||
char did_try_to_transmit = 0;
|
||||
int i;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
for (i = 0; i < base->n_req_heads; ++i) {
|
||||
if (base->req_heads[i]) {
|
||||
struct evdns_request *const started_at = base->req_heads[i], *req = started_at;
|
||||
@ -2137,14 +2241,19 @@ evdns_transmit(struct evdns_base *base) {
|
||||
int
|
||||
evdns_base_count_nameservers(struct evdns_base *base)
|
||||
{
|
||||
const struct nameserver *server = base->server_head;
|
||||
const struct nameserver *server;
|
||||
int n = 0;
|
||||
|
||||
EVDNS_LOCK(base);
|
||||
server = base->server_head;
|
||||
if (!server)
|
||||
return 0;
|
||||
goto done;
|
||||
do {
|
||||
++n;
|
||||
server = server->next;
|
||||
} while (server != base->server_head);
|
||||
done:
|
||||
EVDNS_UNLOCK(base);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -2158,11 +2267,16 @@ evdns_count_nameservers(void)
|
||||
int
|
||||
evdns_base_clear_nameservers_and_suspend(struct evdns_base *base)
|
||||
{
|
||||
struct nameserver *server = base->server_head, *started_at = base->server_head;
|
||||
struct nameserver *server, *started_at;
|
||||
int i;
|
||||
|
||||
if (!server)
|
||||
EVDNS_LOCK(base);
|
||||
server = base->server_head;
|
||||
started_at = base->server_head;
|
||||
if (!server) {
|
||||
EVDNS_UNLOCK(base);
|
||||
return 0;
|
||||
}
|
||||
while (1) {
|
||||
struct nameserver *next = server->next;
|
||||
(void) event_del(&server->event);
|
||||
@ -2207,6 +2321,7 @@ evdns_base_clear_nameservers_and_suspend(struct evdns_base *base)
|
||||
|
||||
base->global_requests_inflight = 0;
|
||||
|
||||
EVDNS_UNLOCK(base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2221,7 +2336,9 @@ evdns_clear_nameservers_and_suspend(void)
|
||||
int
|
||||
evdns_base_resume(struct evdns_base *base)
|
||||
{
|
||||
EVDNS_LOCK(base);
|
||||
evdns_requests_pump_waiting_queue(base);
|
||||
EVDNS_UNLOCK(base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2239,6 +2356,7 @@ _evdns_nameserver_add_impl(struct evdns_base *base, const struct sockaddr *addre
|
||||
struct nameserver *ns;
|
||||
int err = 0;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
if (server) {
|
||||
do {
|
||||
if (sockaddr_eq((struct sockaddr*)&server->address, address, 1)) return 3;
|
||||
@ -2316,10 +2434,14 @@ evdns_base_nameserver_add(struct evdns_base *base,
|
||||
unsigned long int address)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
int res;
|
||||
sin.sin_addr.s_addr = address;
|
||||
sin.sin_port = htons(53);
|
||||
sin.sin_family = AF_INET;
|
||||
return _evdns_nameserver_add_impl(base, (struct sockaddr*)&sin, sizeof(sin));
|
||||
EVDNS_LOCK(base);
|
||||
res = _evdns_nameserver_add_impl(base, (struct sockaddr*)&sin, sizeof(sin));
|
||||
EVDNS_UNLOCK(base);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
@ -2335,6 +2457,7 @@ evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string)
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr *sa;
|
||||
int len = sizeof(ss);
|
||||
int res;
|
||||
if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss,
|
||||
&len)) {
|
||||
log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s",
|
||||
@ -2357,7 +2480,10 @@ evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string)
|
||||
else
|
||||
return -1;
|
||||
|
||||
return _evdns_nameserver_add_impl(base, sa, len);
|
||||
EVDNS_LOCK(base);
|
||||
res = _evdns_nameserver_add_impl(base, sa, len);
|
||||
EVDNS_UNLOCK(base);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
@ -2371,6 +2497,7 @@ evdns_nameserver_ip_add(const char *ip_as_string) {
|
||||
static void
|
||||
evdns_request_remove(struct evdns_request *req, struct evdns_request **head)
|
||||
{
|
||||
ASSERT_LOCKED(req->base);
|
||||
if (req->next == req) {
|
||||
/* only item in the list */
|
||||
*head = NULL;
|
||||
@ -2384,6 +2511,7 @@ evdns_request_remove(struct evdns_request *req, struct evdns_request **head)
|
||||
/* insert into the tail of the queue */
|
||||
static void
|
||||
evdns_request_insert(struct evdns_request *req, struct evdns_request **head) {
|
||||
ASSERT_LOCKED(req->base);
|
||||
if (!*head) {
|
||||
*head = req;
|
||||
req->next = req->prev = req;
|
||||
@ -2409,6 +2537,7 @@ string_num_dots(const char *s) {
|
||||
static struct evdns_request *
|
||||
request_new(struct evdns_base *base, int type, const char *name, int flags,
|
||||
evdns_callback_type callback, void *user_ptr) {
|
||||
|
||||
const char issuing_now =
|
||||
(base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0;
|
||||
|
||||
@ -2422,6 +2551,8 @@ request_new(struct evdns_base *base, int type, const char *name, int flags,
|
||||
char namebuf[256];
|
||||
(void) flags;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
|
||||
if (!req) return NULL;
|
||||
|
||||
if (name_len >= sizeof(namebuf)) {
|
||||
@ -2475,6 +2606,7 @@ err1:
|
||||
static void
|
||||
request_submit(struct evdns_request *const req) {
|
||||
struct evdns_base *base = req->base;
|
||||
ASSERT_LOCKED(base);
|
||||
if (req->ns) {
|
||||
/* if it has a nameserver assigned then this is going */
|
||||
/* straight into the inflight queue */
|
||||
@ -2494,6 +2626,7 @@ evdns_cancel_request(struct evdns_base *base, struct evdns_request *req)
|
||||
if (!base)
|
||||
base = req->base;
|
||||
|
||||
EVDNS_LOCK(base);
|
||||
reply_callback(req, 0, DNS_ERR_CANCEL, NULL);
|
||||
if (req->ns) {
|
||||
/* remove from inflight queue */
|
||||
@ -2502,23 +2635,26 @@ evdns_cancel_request(struct evdns_base *base, struct evdns_request *req)
|
||||
/* remove from global_waiting head */
|
||||
request_finished(req, &base->req_waiting_head);
|
||||
}
|
||||
EVDNS_UNLOCK(base);
|
||||
}
|
||||
|
||||
/* exported function */
|
||||
struct evdns_request *
|
||||
evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags,
|
||||
evdns_callback_type callback, void *ptr) {
|
||||
struct evdns_request *req;
|
||||
log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
|
||||
EVDNS_LOCK(base);
|
||||
if (flags & DNS_QUERY_NO_SEARCH) {
|
||||
struct evdns_request *const req =
|
||||
req =
|
||||
request_new(base, TYPE_A, name, flags, callback, ptr);
|
||||
if (req == NULL)
|
||||
return NULL;
|
||||
request_submit(req);
|
||||
return (req);
|
||||
if (req)
|
||||
request_submit(req);
|
||||
} else {
|
||||
return (search_request_new(base, TYPE_A, name, flags, callback, ptr));
|
||||
req = search_request_new(base, TYPE_A, name, flags, callback, ptr);
|
||||
}
|
||||
EVDNS_UNLOCK(base);
|
||||
return req;
|
||||
}
|
||||
|
||||
int evdns_resolve_ipv4(const char *name, int flags,
|
||||
@ -2535,17 +2671,18 @@ evdns_base_resolve_ipv6(struct evdns_base *base,
|
||||
const char *name, int flags,
|
||||
evdns_callback_type callback, void *ptr)
|
||||
{
|
||||
struct evdns_request *req;
|
||||
log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
|
||||
EVDNS_LOCK(base);
|
||||
if (flags & DNS_QUERY_NO_SEARCH) {
|
||||
struct evdns_request *const req =
|
||||
request_new(base, TYPE_AAAA, name, flags, callback, ptr);
|
||||
if (req == NULL)
|
||||
return (NULL);
|
||||
request_submit(req);
|
||||
return (req);
|
||||
req = request_new(base, TYPE_AAAA, name, flags, callback, ptr);
|
||||
if (req)
|
||||
request_submit(req);
|
||||
} else {
|
||||
return (search_request_new(base,TYPE_AAAA, name, flags, callback, ptr));
|
||||
req = search_request_new(base,TYPE_AAAA, name, flags, callback, ptr);
|
||||
}
|
||||
EVDNS_UNLOCK(base);
|
||||
return req;
|
||||
}
|
||||
|
||||
int evdns_resolve_ipv6(const char *name, int flags,
|
||||
@ -2567,9 +2704,11 @@ evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, in
|
||||
(int)(u8)((a>>16)&0xff),
|
||||
(int)(u8)((a>>24)&0xff));
|
||||
log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
|
||||
EVDNS_LOCK(base);
|
||||
req = request_new(base, TYPE_PTR, buf, flags, callback, ptr);
|
||||
if (!req) return NULL;
|
||||
request_submit(req);
|
||||
if (req)
|
||||
request_submit(req);
|
||||
EVDNS_UNLOCK(base);
|
||||
return (req);
|
||||
}
|
||||
|
||||
@ -2597,9 +2736,11 @@ evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *
|
||||
assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
|
||||
memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
|
||||
log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
|
||||
EVDNS_LOCK(base);
|
||||
req = request_new(base, TYPE_PTR, buf, flags, callback, ptr);
|
||||
if (!req) return NULL;
|
||||
request_submit(req);
|
||||
if (req)
|
||||
request_submit(req);
|
||||
EVDNS_UNLOCK(base);
|
||||
return (req);
|
||||
}
|
||||
|
||||
@ -2668,8 +2809,11 @@ search_postfix_clear(struct evdns_base *base) {
|
||||
|
||||
/* exported function */
|
||||
void
|
||||
evdns_base_search_clear(struct evdns_base *base) {
|
||||
evdns_base_search_clear(struct evdns_base *base)
|
||||
{
|
||||
EVDNS_LOCK(base);
|
||||
search_postfix_clear(base);
|
||||
EVDNS_UNLOCK(base);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2684,6 +2828,7 @@ search_postfix_add(struct evdns_base *base, const char *domain) {
|
||||
while (domain[0] == '.') domain++;
|
||||
domain_len = strlen(domain);
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
if (!base->global_search_state) base->global_search_state = search_state_new();
|
||||
if (!base->global_search_state) return;
|
||||
base->global_search_state->num_domains++;
|
||||
@ -2702,6 +2847,7 @@ search_postfix_add(struct evdns_base *base, const char *domain) {
|
||||
static void
|
||||
search_reverse(struct evdns_base *base) {
|
||||
struct search_domain *cur, *prev = NULL, *next;
|
||||
ASSERT_LOCKED(base);
|
||||
cur = base->global_search_state->head;
|
||||
while (cur) {
|
||||
next = cur->next;
|
||||
@ -2716,7 +2862,9 @@ search_reverse(struct evdns_base *base) {
|
||||
/* exported function */
|
||||
void
|
||||
evdns_base_search_add(struct evdns_base *base, const char *domain) {
|
||||
EVDNS_LOCK(base);
|
||||
search_postfix_add(base, domain);
|
||||
EVDNS_UNLOCK(base);
|
||||
}
|
||||
void
|
||||
evdns_search_add(const char *domain) {
|
||||
@ -2726,9 +2874,11 @@ evdns_search_add(const char *domain) {
|
||||
/* exported function */
|
||||
void
|
||||
evdns_base_search_ndots_set(struct evdns_base *base, const int ndots) {
|
||||
EVDNS_LOCK(base);
|
||||
if (!base->global_search_state) base->global_search_state = search_state_new();
|
||||
if (!base->global_search_state) return;
|
||||
base->global_search_state->ndots = ndots;
|
||||
if (base->global_search_state)
|
||||
base->global_search_state->ndots = ndots;
|
||||
EVDNS_UNLOCK(base);
|
||||
}
|
||||
void
|
||||
evdns_search_ndots_set(const int ndots) {
|
||||
@ -2739,6 +2889,7 @@ static void
|
||||
search_set_from_hostname(struct evdns_base *base) {
|
||||
char hostname[HOST_NAME_MAX + 1], *domainname;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
search_postfix_clear(base);
|
||||
if (gethostname(hostname, sizeof(hostname))) return;
|
||||
domainname = strchr(hostname, '.');
|
||||
@ -2776,6 +2927,7 @@ search_make_new(const struct search_state *const state, int n, const char *const
|
||||
|
||||
static struct evdns_request *
|
||||
search_request_new(struct evdns_base *base, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) {
|
||||
ASSERT_LOCKED(base);
|
||||
assert(type == TYPE_A || type == TYPE_AAAA);
|
||||
if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
|
||||
base->global_search_state &&
|
||||
@ -2816,6 +2968,7 @@ search_request_new(struct evdns_base *base, int type, const char *const name, in
|
||||
static int
|
||||
search_try_next(struct evdns_request *const req) {
|
||||
struct evdns_base *base = req->base;
|
||||
ASSERT_LOCKED(base);
|
||||
if (req->search_state) {
|
||||
/* it is part of a search */
|
||||
char *new_name;
|
||||
@ -2856,6 +3009,7 @@ search_try_next(struct evdns_request *const req) {
|
||||
|
||||
static void
|
||||
search_request_finished(struct evdns_request *const req) {
|
||||
ASSERT_LOCKED(req->base);
|
||||
if (req->search_state) {
|
||||
search_state_decref(req->search_state);
|
||||
req->search_state = NULL;
|
||||
@ -2872,6 +3026,7 @@ search_request_finished(struct evdns_request *const req) {
|
||||
static void
|
||||
evdns_resolv_set_defaults(struct evdns_base *base, int flags) {
|
||||
/* if the file isn't found then we assume a local resolver */
|
||||
ASSERT_LOCKED(base);
|
||||
if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base);
|
||||
if (flags & DNS_OPTION_NAMESERVERS) evdns_base_nameserver_ip_add(base,"127.0.0.1");
|
||||
}
|
||||
@ -2928,6 +3083,8 @@ evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
|
||||
int old_n_heads = base->n_req_heads, n_heads;
|
||||
struct evdns_request **old_heads = base->req_heads, **new_heads, *req;
|
||||
int i;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
if (maxinflight < 1)
|
||||
maxinflight = 1;
|
||||
n_heads = (maxinflight+4) / 5;
|
||||
@ -2956,8 +3113,20 @@ evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
|
||||
/* exported function */
|
||||
int
|
||||
evdns_base_set_option(struct evdns_base *base,
|
||||
const char *option, const char *val, int flags)
|
||||
const char *option, const char *val, int flags)
|
||||
{
|
||||
int res;
|
||||
EVDNS_LOCK(base);
|
||||
res = evdns_base_set_option_impl(base, option, val, flags);
|
||||
EVDNS_UNLOCK(base);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
evdns_base_set_option_impl(struct evdns_base *base,
|
||||
const char *option, const char *val, int flags)
|
||||
{
|
||||
ASSERT_LOCKED(base);
|
||||
if (!strncmp(option, "ndots:", 6)) {
|
||||
const int ndots = strtoint(val);
|
||||
if (ndots == -1) return -1;
|
||||
@ -3022,7 +3191,9 @@ resolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) {
|
||||
static const char *const delims = " \t";
|
||||
#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
|
||||
|
||||
|
||||
char *const first_token = strtok_r(start, delims, &strtok_state);
|
||||
ASSERT_LOCKED(base);
|
||||
if (!first_token) return;
|
||||
|
||||
if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
|
||||
@ -3063,6 +3234,15 @@ resolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) {
|
||||
/* 5 short read from file */
|
||||
int
|
||||
evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename) {
|
||||
int res;
|
||||
EVDNS_LOCK(base);
|
||||
res = evdns_base_resolv_conf_parse_impl(base, flags, filename);
|
||||
EVDNS_UNLOCK(base);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) {
|
||||
struct stat st;
|
||||
int fd, n, r;
|
||||
u8 *resolv;
|
||||
@ -3139,6 +3319,7 @@ evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
|
||||
const char *addr;
|
||||
char *buf;
|
||||
int r;
|
||||
ASSERT_LOCKED(base);
|
||||
while (*ips) {
|
||||
while (isspace(*ips) || *ips == ',' || *ips == '\t')
|
||||
++ips;
|
||||
@ -3173,6 +3354,7 @@ load_nameservers_with_getnetworkparams(struct evdns_base *base)
|
||||
IP_ADDR_STRING *ns;
|
||||
GetNetworkParams_fn_t fn;
|
||||
|
||||
ASSERT_LOCKD(base);
|
||||
if (!(handle = LoadLibrary("iphlpapi.dll"))) {
|
||||
log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
|
||||
status = -1;
|
||||
@ -3245,6 +3427,7 @@ config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const char *su
|
||||
DWORD bufsz = 0, type = 0;
|
||||
int status = 0;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
|
||||
!= ERROR_MORE_DATA)
|
||||
return -1;
|
||||
@ -3270,7 +3453,7 @@ load_nameservers_from_registry(struct evdns_base *base)
|
||||
int found = 0;
|
||||
int r;
|
||||
#define TRY(k, name) \
|
||||
if (!found && config_nameserver_from_reg_key(base,k,name) == 0) { \
|
||||
if (!found && config_nameserver_from_reg_key(base,k,name) == 0) { \
|
||||
log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
|
||||
found = 1; \
|
||||
} else if (!found) { \
|
||||
@ -3278,6 +3461,8 @@ load_nameservers_from_registry(struct evdns_base *base)
|
||||
#k,#name); \
|
||||
}
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
|
||||
if (((int)GetVersion()) > 0) { /* NT */
|
||||
HKEY nt_key = 0, interfaces_key = 0;
|
||||
|
||||
@ -3321,6 +3506,7 @@ load_nameservers_from_registry(struct evdns_base *base)
|
||||
static int
|
||||
evdns_config_windows_nameservers(struct evdns_base *base)
|
||||
{
|
||||
ASSERT_LOCKED(base);
|
||||
if (load_nameservers_with_getnetworkparams(base) == 0)
|
||||
return 0;
|
||||
return load_nameservers_from_registry(base);
|
||||
@ -3337,8 +3523,12 @@ evdns_base_new(struct event_base *event_base, int initialize_nameservers)
|
||||
memset(base, 0, sizeof(struct evdns_base));
|
||||
base->req_waiting_head = NULL;
|
||||
|
||||
EVTHREAD_ALLOC_LOCK(base->lock);
|
||||
EVDNS_LOCK(base);
|
||||
|
||||
/* Set max requests inflight and allocate req_heads. */
|
||||
base->req_heads = NULL;
|
||||
|
||||
evdns_base_set_max_requests_inflight(base, 64);
|
||||
|
||||
base->server_head = NULL;
|
||||
@ -3353,6 +3543,7 @@ evdns_base_new(struct event_base *event_base, int initialize_nameservers)
|
||||
base->global_max_nameserver_timeout = 3;
|
||||
base->global_search_state = NULL;
|
||||
base->global_randomize_case = 1;
|
||||
|
||||
if (initialize_nameservers) {
|
||||
int r;
|
||||
#ifdef WIN32
|
||||
@ -3365,6 +3556,7 @@ evdns_base_new(struct event_base *event_base, int initialize_nameservers)
|
||||
base = NULL;
|
||||
}
|
||||
}
|
||||
EVDNS_UNLOCK(base);
|
||||
return base;
|
||||
}
|
||||
|
||||
@ -3407,6 +3599,10 @@ evdns_base_free(struct evdns_base *base, int fail_requests)
|
||||
struct search_domain *dom, *dom_next;
|
||||
int i;
|
||||
|
||||
/* TODO(nickm) we might need to refcount here. */
|
||||
|
||||
EVDNS_LOCK(base);
|
||||
|
||||
for (i = 0; i < base->n_req_heads; ++i) {
|
||||
while (base->req_heads[i]) {
|
||||
if (fail_requests)
|
||||
@ -3443,6 +3639,9 @@ evdns_base_free(struct evdns_base *base, int fail_requests)
|
||||
mm_free(base->global_search_state);
|
||||
base->global_search_state = NULL;
|
||||
}
|
||||
EVDNS_UNLOCK(base);
|
||||
EVTHREAD_FREE_LOCK(base->lock);
|
||||
|
||||
mm_free(base);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user