Arreglo el procesamiento de la lista de servidores fallidos.
parent
82fe2dd0c6
commit
670c3c5bd9
124
src/dns2.c
124
src/dns2.c
|
@ -33,6 +33,7 @@ typedef struct {
|
|||
socklen_t addr_size;
|
||||
|
||||
int socket;
|
||||
int fatal_network_error;
|
||||
} NameServer;
|
||||
|
||||
|
||||
|
@ -81,7 +82,6 @@ int dns2_async (DNS2 *obj) {
|
|||
dns_packet_recount_items (obj->packet);
|
||||
|
||||
if (obj->type == DNS_UPDATER && (obj->packet->header.qdcount == 0 || obj->packet->header.nscount == 0)) {
|
||||
|
||||
/* Error, nada que mandar en el update */
|
||||
return DNS_COMMAND_ERROR;
|
||||
}
|
||||
|
@ -212,6 +212,64 @@ int dns2_sync (DNS2 *obj) {
|
|||
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) {
|
||||
NameServer *ns;
|
||||
int flags;
|
||||
|
@ -297,19 +355,40 @@ int _dns2_internal_tcp_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 */
|
||||
GList *next;
|
||||
NameServer *ns;
|
||||
|
||||
obj->current_ns = g_list_next (obj->current_ns);
|
||||
if (obj->current_ns != NULL) {
|
||||
/* Buscar un siguiente que no haya tenido un error fatal */
|
||||
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 */
|
||||
obj->current_ns = next;
|
||||
obj->state = DNS_STATE_UDP;
|
||||
|
||||
return _dns2_internal_udp_create (obj);
|
||||
} else {
|
||||
/* Como ya no hay mas en la lista, esperar al timeout */
|
||||
/* Si el actual no tiene marca de error de red, pedir timeout */
|
||||
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;
|
||||
|
||||
obj->state = DNS_STATE_FREE;
|
||||
obj->direction = DNS_POLL_WANT_NONE;
|
||||
|
||||
return DNS_COMMAND_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int _dns2_internal_udp_send (DNS2 *obj) {
|
||||
|
@ -333,10 +412,11 @@ int _dns2_internal_udp_send (DNS2 *obj) {
|
|||
return DNS_COMMAND_POLL;
|
||||
}
|
||||
|
||||
ns->fatal_network_error = 1;
|
||||
return _dns2_internal_udp_next_or_error (obj);
|
||||
} else if (res < data_length) {
|
||||
/* Envié la petición incompleta, manejar este error */
|
||||
|
||||
ns->fatal_network_error = 1;
|
||||
return _dns2_internal_udp_next_or_error (obj);
|
||||
}
|
||||
|
||||
|
@ -429,6 +509,7 @@ int _dns2_internal_udp_recv (DNS2 *obj) {
|
|||
|
||||
if (obj->packet_response == NULL) {
|
||||
/* Como no es válida la respuesta, pasar al siguiente servidor */
|
||||
ns->fatal_network_error = 1;
|
||||
return _dns2_internal_udp_next_or_error (obj);
|
||||
} else {
|
||||
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);
|
||||
strncpy (ns->name, ip, sizeof (ns->name));
|
||||
ns->socket = -1;
|
||||
ns->fatal_network_error = 0;
|
||||
|
||||
obj->nameservers = g_list_append (obj->nameservers, ns);
|
||||
|
||||
|
@ -645,6 +727,7 @@ void dns2_clean_network (DNS2 *obj) {
|
|||
ns = (NameServer *) g->data;
|
||||
|
||||
if (ns->socket >= 0) {
|
||||
ns->fatal_network_error = 0;
|
||||
close (ns->socket);
|
||||
ns->socket = -1;
|
||||
}
|
||||
|
@ -652,7 +735,6 @@ void dns2_clean_network (DNS2 *obj) {
|
|||
}
|
||||
|
||||
void dns2_free (DNS2 *obj) {
|
||||
|
||||
/* Cerrar el socket, si es que hay alguno abierto */
|
||||
dns2_clean_network (obj);
|
||||
|
||||
|
@ -684,14 +766,20 @@ void dns2_free (DNS2 *obj) {
|
|||
int dns2_check_timeout (DNS2 *obj) {
|
||||
struct timespec now;
|
||||
double d;
|
||||
GList *last_usable;
|
||||
int pos_cur, pos_last;
|
||||
|
||||
if (obj->state != DNS_STATE_UDP) return DNS_COMMAND_POLL;
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &now);
|
||||
|
||||
d = _dns2_diff_timespec (&now, &obj->last_time_sent);
|
||||
if (obj->current_ns->next == NULL) {
|
||||
/* Si estamos al borde del último servidor, necesitamos el timeout largo */
|
||||
last_usable = _dns2_internal_get_last_usable_ns (obj);
|
||||
|
||||
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) {
|
||||
/* Como cayó el timeout largo, incrementar los retries y regresar al primer servidor */
|
||||
obj->retry_count++;
|
||||
|
@ -700,14 +788,27 @@ int dns2_check_timeout (DNS2 *obj) {
|
|||
dns2_clean_network (obj);
|
||||
obj->current_ns = NULL;
|
||||
|
||||
obj->state = DNS_STATE_FREE;
|
||||
obj->direction = DNS_POLL_WANT_NONE;
|
||||
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
||||
|
@ -721,6 +822,7 @@ int dns2_get_socket (DNS2 *obj) {
|
|||
|
||||
if (obj->state == DNS_STATE_FREE) return -1;
|
||||
|
||||
if (obj->current_ns == NULL) return -1;
|
||||
ns = (NameServer *) obj->current_ns->data;
|
||||
|
||||
return ns->socket;
|
||||
|
|
Loading…
Reference in New Issue