mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-15 07:15:03 -04:00
Let evdns keep working when our IP changes. Fix by Christopher Davis; backported by nickm.
svn:r1328
This commit is contained in:
parent
b99254ac22
commit
763391947c
@ -4,6 +4,7 @@ Changes in 1.4.12-stable:
|
||||
o Use __VA_ARGS__ syntax for varargs macros in event_rpcgen when compiler is not GCC.
|
||||
o Activate fd events in a pseudorandom order with O(N) backends, so that we don't systematically favor low fds (select) or earlier-added fds (poll, win32).
|
||||
o Fix another pair of fencepost bugs in epoll.c. [Patch from Adam Langley.]
|
||||
o Do not break evdns connections to nameservers when our IP changes.
|
||||
|
||||
Changes in 1.4.11-stable:
|
||||
o Fix a bug when removing a timeout from the heap. [Patch from Marko Kreen]
|
||||
|
41
evdns.c
41
evdns.c
@ -209,6 +209,7 @@ struct reply {
|
||||
struct nameserver {
|
||||
int socket; /* a connected UDP socket */
|
||||
u32 address;
|
||||
u16 port;
|
||||
int failed_times; /* number of times which we have given this server a chance */
|
||||
int timedout; /* number of times in a row a request has timed out */
|
||||
struct event event;
|
||||
@ -1150,19 +1151,38 @@ nameserver_pick(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
address_is_correct(struct nameserver *ns, struct sockaddr *sa, socklen_t slen)
|
||||
{
|
||||
struct sockaddr_in *sin = (struct sockaddr_in*) sa;
|
||||
if (sa->sa_family != AF_INET || slen != sizeof(struct sockaddr_in))
|
||||
return 0;
|
||||
if (sin->sin_addr.s_addr != ns->address)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is called when a namesever socket is ready for reading */
|
||||
static void
|
||||
nameserver_read(struct nameserver *ns) {
|
||||
u8 packet[1500];
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t addrlen = sizeof(ss);
|
||||
|
||||
for (;;) {
|
||||
const int r = recv(ns->socket, packet, sizeof(packet), 0);
|
||||
const int r = recvfrom(ns->socket, packet, sizeof(packet), 0,
|
||||
(struct sockaddr*)&ss, &addrlen);
|
||||
if (r < 0) {
|
||||
int err = last_error(ns->socket);
|
||||
if (error_is_eagain(err)) return;
|
||||
nameserver_failed(ns, strerror(err));
|
||||
return;
|
||||
}
|
||||
if (!address_is_correct(ns, (struct sockaddr*)&ss, addrlen)) {
|
||||
log(EVDNS_LOG_WARN, "Address mismatch on received "
|
||||
"DNS packet.");
|
||||
return;
|
||||
}
|
||||
ns->timedout = 0;
|
||||
reply_parse(packet, r);
|
||||
}
|
||||
@ -1890,7 +1910,15 @@ evdns_request_timeout_callback(int fd, short events, void *arg) {
|
||||
/* 2 other failure */
|
||||
static int
|
||||
evdns_request_transmit_to(struct request *req, struct nameserver *server) {
|
||||
const int r = send(server->socket, req->request, req->request_len, 0);
|
||||
struct sockaddr_in sin;
|
||||
int r;
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_addr.s_addr = req->ns->address;
|
||||
sin.sin_port = req->ns->port;
|
||||
sin.sin_family = AF_INET;
|
||||
|
||||
r = sendto(server->socket, req->request, req->request_len, 0,
|
||||
(struct sockaddr*)&sin, sizeof(sin));
|
||||
if (r < 0) {
|
||||
int err = last_error(server->socket);
|
||||
if (error_is_eagain(err)) return 1;
|
||||
@ -2085,7 +2113,6 @@ _evdns_nameserver_add_impl(unsigned long int address, int port) {
|
||||
|
||||
const struct nameserver *server = server_head, *const started_at = server_head;
|
||||
struct nameserver *ns;
|
||||
struct sockaddr_in sin;
|
||||
int err = 0;
|
||||
if (server) {
|
||||
do {
|
||||
@ -2104,15 +2131,9 @@ _evdns_nameserver_add_impl(unsigned long int address, int port) {
|
||||
ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (ns->socket < 0) { err = 1; goto out1; }
|
||||
evutil_make_socket_nonblocking(ns->socket);
|
||||
sin.sin_addr.s_addr = address;
|
||||
sin.sin_port = htons(port);
|
||||
sin.sin_family = AF_INET;
|
||||
if (connect(ns->socket, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
|
||||
err = 2;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
ns->address = address;
|
||||
ns->port = htons(port);
|
||||
ns->state = 1;
|
||||
event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
|
||||
if (event_add(&ns->event, NULL) < 0) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user