mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-08 03:44:22 -04:00
evdns: New flag to make evdns not prevent the event loop from exiting
Here is the brief description of problem: When you are use evdns to resolve domains to IP adresses (see ./sample/dns-example) you loop never returns from event_base_dispatch(), and because of this the program will never terminated. Because existing programs may be depending on the old behavior, we only apply the fix when evdns_base_new() is created with a new flag - EVDNS_BASE_DISABLE_WHEN_INACTIVE. (Commit message edited by Nick while squashing the branch.)
This commit is contained in:
parent
2fad0f3d52
commit
6b7fa620e8
47
evdns.c
47
evdns.c
@ -236,6 +236,10 @@ struct nameserver {
|
||||
char choked; /* true if we have an EAGAIN from this server's socket */
|
||||
char write_waiting; /* true if we are waiting for EV_WRITE events */
|
||||
struct evdns_base *base;
|
||||
|
||||
/* Number of currently inflight requests: used
|
||||
* to track when we should add/del the event. */
|
||||
int requests_inflight;
|
||||
};
|
||||
|
||||
|
||||
@ -358,6 +362,8 @@ struct evdns_base {
|
||||
#ifndef EVENT__DISABLE_THREAD_SUPPORT
|
||||
void *lock;
|
||||
#endif
|
||||
|
||||
int disable_when_inactive;
|
||||
};
|
||||
|
||||
struct hosts_entry {
|
||||
@ -660,12 +666,19 @@ request_finished(struct request *const req, struct request **head, int free_hand
|
||||
if (was_inflight) {
|
||||
evtimer_del(&req->timeout_event);
|
||||
base->global_requests_inflight--;
|
||||
req->ns->requests_inflight--;
|
||||
} else {
|
||||
base->global_requests_waiting--;
|
||||
}
|
||||
/* it was initialized during request_new / evtimer_assign */
|
||||
event_debug_unassign(&req->timeout_event);
|
||||
|
||||
if (req->ns &&
|
||||
req->ns->requests_inflight == 0 &&
|
||||
req->base->disable_when_inactive) {
|
||||
event_del(&req->ns->event);
|
||||
}
|
||||
|
||||
if (!req->request_appended) {
|
||||
/* need to free the request data on it's own */
|
||||
mm_free(req->request);
|
||||
@ -744,6 +757,8 @@ evdns_requests_pump_waiting_queue(struct evdns_base *base) {
|
||||
base->global_requests_inflight++;
|
||||
|
||||
req->ns = nameserver_pick(base);
|
||||
req->ns->requests_inflight++;
|
||||
|
||||
request_trans_id_set(req, transaction_id_pick(base));
|
||||
|
||||
evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
|
||||
@ -2188,6 +2203,13 @@ evdns_request_transmit_to(struct request *req, struct nameserver *server) {
|
||||
int r;
|
||||
ASSERT_LOCKED(req->base);
|
||||
ASSERT_VALID_REQUEST(req);
|
||||
|
||||
if (server->requests_inflight == 1 &&
|
||||
req->base->disable_when_inactive &&
|
||||
event_add(&server->event, NULL) < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = sendto(server->socket, (void*)req->request, req->request_len, 0,
|
||||
(struct sockaddr *)&server->address, server->addrlen);
|
||||
if (r < 0) {
|
||||
@ -2496,8 +2518,9 @@ evdns_nameserver_add_impl_(struct evdns_base *base, const struct sockaddr *addre
|
||||
memcpy(&ns->address, address, addrlen);
|
||||
ns->addrlen = addrlen;
|
||||
ns->state = 1;
|
||||
event_assign(&ns->event, ns->base->event_base, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
|
||||
if (event_add(&ns->event, NULL) < 0) {
|
||||
event_assign(&ns->event, ns->base->event_base, ns->socket,
|
||||
EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
|
||||
if (!base->disable_when_inactive && event_add(&ns->event, NULL) < 0) {
|
||||
err = 2;
|
||||
goto out2;
|
||||
}
|
||||
@ -2768,7 +2791,10 @@ request_submit(struct request *const req) {
|
||||
/* if it has a nameserver assigned then this is going */
|
||||
/* straight into the inflight queue */
|
||||
evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
|
||||
|
||||
base->global_requests_inflight++;
|
||||
req->ns->requests_inflight++;
|
||||
|
||||
evdns_request_transmit(req);
|
||||
} else {
|
||||
evdns_request_insert(req, &base->req_waiting_head);
|
||||
@ -3829,7 +3855,7 @@ evdns_config_windows_nameservers(void)
|
||||
#endif
|
||||
|
||||
struct evdns_base *
|
||||
evdns_base_new(struct event_base *event_base, int initialize_nameservers)
|
||||
evdns_base_new(struct event_base *event_base, int flags)
|
||||
{
|
||||
struct evdns_base *base;
|
||||
|
||||
@ -3877,7 +3903,16 @@ evdns_base_new(struct event_base *event_base, int initialize_nameservers)
|
||||
|
||||
TAILQ_INIT(&base->hostsdb);
|
||||
|
||||
if (initialize_nameservers) {
|
||||
#define EVDNS_BASE_ALL_FLAGS (0x8001)
|
||||
if (flags & ~EVDNS_BASE_ALL_FLAGS) {
|
||||
flags = EVDNS_BASE_INITIALIZE_NAMESERVERS;
|
||||
log(EVDNS_LOG_WARN,
|
||||
"Unrecognized flag passed to evdns_base_new(). Assuming "
|
||||
"you meant EVDNS_BASE_INITIALIZE_NAMESERVERS.");
|
||||
}
|
||||
#undef EVDNS_BASE_ALL_FLAGS
|
||||
|
||||
if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) {
|
||||
int r;
|
||||
#ifdef _WIN32
|
||||
r = evdns_base_config_windows_nameservers(base);
|
||||
@ -3889,6 +3924,10 @@ evdns_base_new(struct event_base *event_base, int initialize_nameservers)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE) {
|
||||
base->disable_when_inactive = 1;
|
||||
}
|
||||
|
||||
EVDNS_UNLOCK(base);
|
||||
return base;
|
||||
}
|
||||
|
@ -201,6 +201,12 @@ typedef void (*evdns_callback_type) (int result, char type, int count, int ttl,
|
||||
struct evdns_base;
|
||||
struct event_base;
|
||||
|
||||
/** Flag for evdns_base_new: process resolv.conf. */
|
||||
#define EVDNS_BASE_INITIALIZE_NAMESERVERS 1
|
||||
/** Flag for evdns_base_new: Do not prevent the libevent event loop from
|
||||
* exiting when we have no active dns requests. */
|
||||
#define EVDNS_BASE_DISABLE_WHEN_INACTIVE 0x8000
|
||||
|
||||
/**
|
||||
Initialize the asynchronous DNS library.
|
||||
|
||||
@ -209,7 +215,8 @@ struct event_base;
|
||||
evdns_config_windows_nameservers() on Windows.
|
||||
|
||||
@param event_base the event base to associate the dns client with
|
||||
@param initialize_nameservers 1 if resolve.conf processing should occur
|
||||
@param flags any of EVDNS_BASE_INITIALIZE_NAMESERVERS|
|
||||
EVDNS_BASE_DISABLE_WHEN_INACTIVE
|
||||
@return evdns_base object if successful, or NULL if an error occurred.
|
||||
@see evdns_base_free()
|
||||
*/
|
||||
|
@ -179,7 +179,7 @@ main(int c, char **v) {
|
||||
#endif
|
||||
|
||||
event_base = event_base_new();
|
||||
evdns_base = evdns_base_new(event_base, 0);
|
||||
evdns_base = evdns_base_new(event_base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
|
||||
evdns_set_log_fn(logfn);
|
||||
|
||||
if (servertest) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user