Split dns_cancel_pending_resolve into dns_cancel_pending_resolve (kill a

resolve in response to a DNS worker dying) and connection_dns_remove (remove
a pending connection from the resolve structure.)


svn:r1168
This commit is contained in:
Nick Mathewson 2004-02-28 22:23:44 +00:00
parent 9a55700747
commit 0a673f4491
3 changed files with 79 additions and 39 deletions

View File

@ -182,14 +182,14 @@ _connection_mark_for_close(connection_t *conn, char reason)
case CONN_TYPE_EXIT: case CONN_TYPE_EXIT:
case CONN_TYPE_AP: case CONN_TYPE_AP:
if (conn->state == EXIT_CONN_STATE_RESOLVING) if (conn->state == EXIT_CONN_STATE_RESOLVING)
dns_cancel_pending_resolve(conn->address, conn); connection_dns_remove(conn);
if (!conn->has_sent_end && reason && if (!conn->has_sent_end && reason &&
connection_edge_end(conn, reason, conn->cpath_layer) < 0) connection_edge_end(conn, reason, conn->cpath_layer) < 0)
return -1; return -1;
break; break;
case CONN_TYPE_DNSWORKER: case CONN_TYPE_DNSWORKER:
if (conn->state == DNSWORKER_STATE_BUSY) { if (conn->state == DNSWORKER_STATE_BUSY) {
dns_cancel_pending_resolve(conn->address, NULL); dns_cancel_pending_resolve(conn->address);
} }
break; break;
default: default:

View File

@ -171,7 +171,7 @@ static int assign_to_dnsworker(connection_t *exitconn) {
if(!dnsconn) { if(!dnsconn) {
log_fn(LOG_WARN,"no idle dns workers. Failing."); log_fn(LOG_WARN,"no idle dns workers. Failing.");
dns_cancel_pending_resolve(exitconn->address, NULL); dns_cancel_pending_resolve(exitconn->address);
return -1; return -1;
} }
@ -192,12 +192,53 @@ static int assign_to_dnsworker(connection_t *exitconn) {
} }
void connection_dns_remove(connection_t *conn)
{
struct pending_connection_t *pend, *victim;
struct cached_resolve search;
struct cached_resolve *resolve;
strncpy(search.address, conn->address, MAX_ADDRESSLEN);
search.address[MAX_ADDRESSLEN-1] = 0;
resolve = SPLAY_FIND(cache_tree, &cache_root, &search);
if(!resolve) {
log_fn(LOG_WARN,"Address '%s' is not pending. Dropping.", conn->address);
return;
}
assert(resolve->pending_connections);
assert_connection_ok(conn,0);
pend = resolve->pending_connections;
if(pend->conn == conn) {
resolve->pending_connections = pend->next;
free(pend);
log_fn(LOG_DEBUG, "Connection (fd %d) no longer waiting for resolve of '%s'",
conn->s, conn->address);
return;
} else {
for( ; pend->next; pend = pend->next) {
if(pend->next->conn == conn) {
victim = pend->next;
pend->next = victim->next;
free(victim);
log_fn(LOG_DEBUG, "Connection (fd %d) no longer waiting for resolve of '%s'",
conn->s, conn->address);
return; /* more are pending */
}
}
assert(0); /* not reachable unless onlyconn not in pending list */
}
}
/* If onlyconn is NULL, cancel all pending connections. If onlyconn is /* If onlyconn is NULL, cancel all pending connections. If onlyconn is
* defined, then remove onlyconn from the pending list. Does not cancel the * defined, then remove onlyconn from the pending list. Does not cancel the
* resolve itself, or remove the 'struct cached_resolve' from the cache. * resolve itself, or remove the 'struct cached_resolve' from the cache.
*/ */
void dns_cancel_pending_resolve(char *address, connection_t *onlyconn) { void dns_cancel_pending_resolve(char *address) {
struct pending_connection_t *pend, *victim; struct pending_connection_t *pend;
struct cached_resolve search; struct cached_resolve search;
struct cached_resolve *resolve, *tmp; struct cached_resolve *resolve, *tmp;
@ -212,40 +253,38 @@ void dns_cancel_pending_resolve(char *address, connection_t *onlyconn) {
assert(resolve->pending_connections); assert(resolve->pending_connections);
if(onlyconn) {
assert_connection_ok(onlyconn,0);
pend = resolve->pending_connections;
if(pend->conn == onlyconn) {
resolve->pending_connections = pend->next;
free(pend);
if(resolve->pending_connections) {/* more pending, don't cancel it */
log_fn(LOG_DEBUG, "Connection (fd %d) no longer waiting for resolve of '%s'",
onlyconn->s, address);
}
} else {
for( ; pend->next; pend = pend->next) {
if(pend->next->conn == onlyconn) {
victim = pend->next;
pend->next = victim->next;
free(victim);
log_fn(LOG_DEBUG, "Connection (fd %d) no longer waiting for resolve of '%s'",
onlyconn->s, address);
return; /* more are pending */
}
}
assert(0); /* not reachable unless onlyconn not in pending list */
}
} else {
/* mark all pending connections to fail */ /* mark all pending connections to fail */
log_fn(LOG_DEBUG, "Failing all connections waiting on DNS resolve of '%s'", log_fn(LOG_DEBUG, "Failing all connections waiting on DNS resolve of '%s'",
address); address);
while(resolve->pending_connections) { while(resolve->pending_connections) {
pend = resolve->pending_connections; pend = resolve->pending_connections;
/* This calls dns_cancel_pending_resolve, which removes pend
* from the list, so we don't have to do it. Beware of
* modify-while-iterating bugs hereabouts! */
connection_mark_for_close(pend->conn, END_STREAM_REASON_MISC); connection_mark_for_close(pend->conn, END_STREAM_REASON_MISC);
resolve->pending_connections = pend->next; assert(resolve->pending_connections != pend);
free(pend);
} }
/* remove resolve from the linked list */
if(resolve == oldest_cached_resolve) {
oldest_cached_resolve = resolve->next;
if(oldest_cached_resolve == NULL)
newest_cached_resolve = NULL;
} else {
/* FFFF make it a doubly linked list if this becomes too slow */
for(tmp=oldest_cached_resolve; tmp && tmp->next != resolve; tmp=tmp->next) ;
assert(tmp); /* it's got to be in the list, or we screwed up somewhere else */
tmp->next = resolve->next; /* unlink it */
if(newest_cached_resolve == resolve)
newest_cached_resolve = tmp;
} }
/* remove resolve from the tree */
SPLAY_REMOVE(cache_tree, &cache_root, resolve);
free(resolve);
} }
static void dns_found_answer(char *address, uint32_t addr) { static void dns_found_answer(char *address, uint32_t addr) {
@ -315,7 +354,7 @@ int connection_dns_process_inbuf(connection_t *conn) {
if(conn->inbuf_reached_eof) { if(conn->inbuf_reached_eof) {
log_fn(LOG_WARN,"Read eof. Worker dying."); log_fn(LOG_WARN,"Read eof. Worker dying.");
if(conn->state == DNSWORKER_STATE_BUSY) { if(conn->state == DNSWORKER_STATE_BUSY) {
dns_cancel_pending_resolve(conn->address, NULL); dns_cancel_pending_resolve(conn->address);
num_dnsworkers_busy--; num_dnsworkers_busy--;
} }
num_dnsworkers--; num_dnsworkers--;

View File

@ -754,7 +754,8 @@ int connection_dir_finished_flushing(connection_t *conn);
void dns_init(void); void dns_init(void);
int connection_dns_finished_flushing(connection_t *conn); int connection_dns_finished_flushing(connection_t *conn);
int connection_dns_process_inbuf(connection_t *conn); int connection_dns_process_inbuf(connection_t *conn);
void dns_cancel_pending_resolve(char *question, connection_t *onlyconn); void connection_dns_remove(connection_t *conn);
void dns_cancel_pending_resolve(char *question);
int dns_resolve(connection_t *exitconn); int dns_resolve(connection_t *exitconn);
/********************************* main.c ***************************/ /********************************* main.c ***************************/