Arreglo el procesamiento de la lista de servidores fallidos.
parent
82fe2dd0c6
commit
670c3c5bd9
126
src/dns2.c
126
src/dns2.c
|
@ -33,6 +33,7 @@ typedef struct {
|
||||||
socklen_t addr_size;
|
socklen_t addr_size;
|
||||||
|
|
||||||
int socket;
|
int socket;
|
||||||
|
int fatal_network_error;
|
||||||
} NameServer;
|
} NameServer;
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +82,6 @@ int dns2_async (DNS2 *obj) {
|
||||||
dns_packet_recount_items (obj->packet);
|
dns_packet_recount_items (obj->packet);
|
||||||
|
|
||||||
if (obj->type == DNS_UPDATER && (obj->packet->header.qdcount == 0 || obj->packet->header.nscount == 0)) {
|
if (obj->type == DNS_UPDATER && (obj->packet->header.qdcount == 0 || obj->packet->header.nscount == 0)) {
|
||||||
|
|
||||||
/* Error, nada que mandar en el update */
|
/* Error, nada que mandar en el update */
|
||||||
return DNS_COMMAND_ERROR;
|
return DNS_COMMAND_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -212,6 +212,64 @@ int dns2_sync (DNS2 *obj) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GList * _dns2_internal_get_last_usable_ns (DNS2 *obj) {
|
||||||
|
GList *next;
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
next = g_list_last (obj->nameservers);
|
||||||
|
while (next != NULL) {
|
||||||
|
ns = (NameServer *) next->data;
|
||||||
|
if (ns->fatal_network_error == 1) {
|
||||||
|
next = g_list_previous (next);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GList * _dns2_internal_get_next_ns (DNS2 *obj, GList *start) {
|
||||||
|
/* Tenemos que sacar el siguiente de la lista en una forma circular,
|
||||||
|
* sin darle la vuelta, omitiendo los que ya están etiquetados con error */
|
||||||
|
GList *next;
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
if (start == NULL) {
|
||||||
|
/* Empezar desde el inicio de la lista sin ciclarnos */
|
||||||
|
next = obj->nameservers;
|
||||||
|
while (next != NULL) {
|
||||||
|
ns = (NameServer *) next->data;
|
||||||
|
if (ns->fatal_network_error == 1) {
|
||||||
|
next = g_list_next (next);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Si nos dan un inicio, dar la vuelta de la otra forma */
|
||||||
|
next = start;
|
||||||
|
do {
|
||||||
|
next = g_list_next (next);
|
||||||
|
if (next == NULL) next = obj->nameservers;
|
||||||
|
|
||||||
|
if (next == start) {
|
||||||
|
/* Como le dí la vuelta, se acabó */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ns = (NameServer *) next->data;
|
||||||
|
if (ns->fatal_network_error == 1) continue;
|
||||||
|
break;
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
int _dns2_internal_tcp_start_connect (DNS2 *obj) {
|
int _dns2_internal_tcp_start_connect (DNS2 *obj) {
|
||||||
NameServer *ns;
|
NameServer *ns;
|
||||||
int flags;
|
int flags;
|
||||||
|
@ -297,18 +355,39 @@ int _dns2_internal_tcp_next_or_error (DNS2 *obj) {
|
||||||
|
|
||||||
int _dns2_internal_udp_next_or_error (DNS2 *obj) {
|
int _dns2_internal_udp_next_or_error (DNS2 *obj) {
|
||||||
/* Los sockets UDP no se cierran, se dejan para usar después */
|
/* Los sockets UDP no se cierran, se dejan para usar después */
|
||||||
|
GList *next;
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
obj->current_ns = g_list_next (obj->current_ns);
|
/* Buscar un siguiente que no haya tenido un error fatal */
|
||||||
if (obj->current_ns != NULL) {
|
next = _dns2_internal_get_next_ns (obj, obj->current_ns);
|
||||||
|
if (obj->current_ns->next == NULL) {
|
||||||
|
/* Como estoy al borde de la lista,
|
||||||
|
* pedir mejor timeout para que se ejecute el timeout largo,
|
||||||
|
* sin cambiar de ns */
|
||||||
|
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
} else if (next != NULL) {
|
||||||
/* Aún hay siguiente servidor, intentarlo con éste */
|
/* Aún hay siguiente servidor, intentarlo con éste */
|
||||||
|
obj->current_ns = next;
|
||||||
obj->state = DNS_STATE_UDP;
|
obj->state = DNS_STATE_UDP;
|
||||||
|
|
||||||
return _dns2_internal_udp_create (obj);
|
return _dns2_internal_udp_create (obj);
|
||||||
} else {
|
} else {
|
||||||
/* Como ya no hay mas en la lista, esperar al timeout */
|
/* Si el actual no tiene marca de error de red, pedir timeout */
|
||||||
obj->direction = DNS_POLL_WANT_READ;
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
if (ns->fatal_network_error == 0) {
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
/* Como ya no hay mas en la lista, marcar error */
|
||||||
|
dns2_clean_network (obj);
|
||||||
|
obj->current_ns = NULL;
|
||||||
|
|
||||||
return DNS_COMMAND_POLL;
|
obj->state = DNS_STATE_FREE;
|
||||||
|
obj->direction = DNS_POLL_WANT_NONE;
|
||||||
|
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,10 +412,11 @@ int _dns2_internal_udp_send (DNS2 *obj) {
|
||||||
return DNS_COMMAND_POLL;
|
return DNS_COMMAND_POLL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns->fatal_network_error = 1;
|
||||||
return _dns2_internal_udp_next_or_error (obj);
|
return _dns2_internal_udp_next_or_error (obj);
|
||||||
} else if (res < data_length) {
|
} else if (res < data_length) {
|
||||||
/* Envié la petición incompleta, manejar este error */
|
/* Envié la petición incompleta, manejar este error */
|
||||||
|
ns->fatal_network_error = 1;
|
||||||
return _dns2_internal_udp_next_or_error (obj);
|
return _dns2_internal_udp_next_or_error (obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,6 +509,7 @@ int _dns2_internal_udp_recv (DNS2 *obj) {
|
||||||
|
|
||||||
if (obj->packet_response == NULL) {
|
if (obj->packet_response == NULL) {
|
||||||
/* Como no es válida la respuesta, pasar al siguiente servidor */
|
/* Como no es válida la respuesta, pasar al siguiente servidor */
|
||||||
|
ns->fatal_network_error = 1;
|
||||||
return _dns2_internal_udp_next_or_error (obj);
|
return _dns2_internal_udp_next_or_error (obj);
|
||||||
} else {
|
} else {
|
||||||
if (obj->packet_response->header.id != obj->packet->header.id) {
|
if (obj->packet_response->header.id != obj->packet->header.id) {
|
||||||
|
@ -611,6 +692,7 @@ void dns2_add_nserver (DNS2 *obj, const char *ip) {
|
||||||
ns->addr_size = sizeof (v4);
|
ns->addr_size = sizeof (v4);
|
||||||
strncpy (ns->name, ip, sizeof (ns->name));
|
strncpy (ns->name, ip, sizeof (ns->name));
|
||||||
ns->socket = -1;
|
ns->socket = -1;
|
||||||
|
ns->fatal_network_error = 0;
|
||||||
|
|
||||||
obj->nameservers = g_list_append (obj->nameservers, ns);
|
obj->nameservers = g_list_append (obj->nameservers, ns);
|
||||||
|
|
||||||
|
@ -645,6 +727,7 @@ void dns2_clean_network (DNS2 *obj) {
|
||||||
ns = (NameServer *) g->data;
|
ns = (NameServer *) g->data;
|
||||||
|
|
||||||
if (ns->socket >= 0) {
|
if (ns->socket >= 0) {
|
||||||
|
ns->fatal_network_error = 0;
|
||||||
close (ns->socket);
|
close (ns->socket);
|
||||||
ns->socket = -1;
|
ns->socket = -1;
|
||||||
}
|
}
|
||||||
|
@ -652,7 +735,6 @@ void dns2_clean_network (DNS2 *obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void dns2_free (DNS2 *obj) {
|
void dns2_free (DNS2 *obj) {
|
||||||
|
|
||||||
/* Cerrar el socket, si es que hay alguno abierto */
|
/* Cerrar el socket, si es que hay alguno abierto */
|
||||||
dns2_clean_network (obj);
|
dns2_clean_network (obj);
|
||||||
|
|
||||||
|
@ -684,14 +766,20 @@ void dns2_free (DNS2 *obj) {
|
||||||
int dns2_check_timeout (DNS2 *obj) {
|
int dns2_check_timeout (DNS2 *obj) {
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
double d;
|
double d;
|
||||||
|
GList *last_usable;
|
||||||
|
int pos_cur, pos_last;
|
||||||
|
|
||||||
if (obj->state != DNS_STATE_UDP) return DNS_COMMAND_POLL;
|
if (obj->state != DNS_STATE_UDP) return DNS_COMMAND_POLL;
|
||||||
|
|
||||||
clock_gettime (CLOCK_MONOTONIC, &now);
|
clock_gettime (CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
d = _dns2_diff_timespec (&now, &obj->last_time_sent);
|
d = _dns2_diff_timespec (&now, &obj->last_time_sent);
|
||||||
if (obj->current_ns->next == NULL) {
|
last_usable = _dns2_internal_get_last_usable_ns (obj);
|
||||||
/* Si estamos al borde del último servidor, necesitamos el timeout largo */
|
|
||||||
|
pos_cur = g_list_position (obj->nameservers, obj->current_ns);
|
||||||
|
pos_last = g_list_position (obj->nameservers, last_usable);
|
||||||
|
if (pos_cur >= pos_last) {
|
||||||
|
/* Si estamos al borde del último servidor usable, necesitamos el timeout largo */
|
||||||
if (d > (double) obj->timeout) {
|
if (d > (double) obj->timeout) {
|
||||||
/* Como cayó el timeout largo, incrementar los retries y regresar al primer servidor */
|
/* Como cayó el timeout largo, incrementar los retries y regresar al primer servidor */
|
||||||
obj->retry_count++;
|
obj->retry_count++;
|
||||||
|
@ -700,14 +788,27 @@ int dns2_check_timeout (DNS2 *obj) {
|
||||||
dns2_clean_network (obj);
|
dns2_clean_network (obj);
|
||||||
obj->current_ns = NULL;
|
obj->current_ns = NULL;
|
||||||
|
|
||||||
|
obj->state = DNS_STATE_FREE;
|
||||||
|
obj->direction = DNS_POLL_WANT_NONE;
|
||||||
|
|
||||||
return DNS_COMMAND_ERROR;
|
return DNS_COMMAND_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj->current_ns = obj->nameservers;
|
obj->current_ns = _dns2_internal_get_next_ns (obj, NULL);
|
||||||
|
if (obj->current_ns == NULL) {
|
||||||
|
/* No quedan servidores, bye bye */
|
||||||
|
dns2_clean_network (obj);
|
||||||
|
obj->current_ns = NULL;
|
||||||
|
|
||||||
|
obj->state = DNS_STATE_FREE;
|
||||||
|
obj->direction = DNS_POLL_WANT_NONE;
|
||||||
|
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
return _dns2_internal_udp_create (obj);
|
return _dns2_internal_udp_create (obj);
|
||||||
}
|
}
|
||||||
} else if (d > 1.0) {
|
} else if (d > 1.0) {
|
||||||
/* 1 segundo entre servidor y servidor */
|
/* Como ocurrió 1 segundo de timeout en este servidor, pedir pasar al siguiente */
|
||||||
return _dns2_internal_udp_next_or_error (obj);
|
return _dns2_internal_udp_next_or_error (obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,6 +822,7 @@ int dns2_get_socket (DNS2 *obj) {
|
||||||
|
|
||||||
if (obj->state == DNS_STATE_FREE) return -1;
|
if (obj->state == DNS_STATE_FREE) return -1;
|
||||||
|
|
||||||
|
if (obj->current_ns == NULL) return -1;
|
||||||
ns = (NameServer *) obj->current_ns->data;
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
|
||||||
return ns->socket;
|
return ns->socket;
|
||||||
|
|
Loading…
Reference in New Issue