From 6aced6393f36a46ac7112106b49ddef66c6e97a6 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 2 Jul 2009 21:54:14 +0000 Subject: [PATCH] (trunk third-party) update to dht 0.7 --- third-party/dht/CHANGES | 6 ++ third-party/dht/dht.c | 154 +++++++++++++++++++++++++++------------- 2 files changed, 109 insertions(+), 51 deletions(-) diff --git a/third-party/dht/CHANGES b/third-party/dht/CHANGES index 9cbff3404..ad7cb11d2 100644 --- a/third-party/dht/CHANGES +++ b/third-party/dht/CHANGES @@ -1,3 +1,9 @@ +24 June 2009: dht-0.7 + + * Removed the fixed limit on the number of concurrent searches, we now + use a linked list. + * Fixed build on FreeBSD (thanks to Humihara and Charles Kerr). + 22 May 2009: dht-0.6 * Fixed a buffer overflow (when reading) in parse_message. diff --git a/third-party/dht/dht.c b/third-party/dht/dht.c index eadb46f72..c13957838 100644 --- a/third-party/dht/dht.c +++ b/third-party/dht/dht.c @@ -122,6 +122,7 @@ struct search { int done; struct search_node nodes[SEARCH_NODES]; int numnodes; + struct search *next; }; struct peer { @@ -135,6 +136,16 @@ struct peer { #define DHT_MAX_PEERS 2048 #endif +/* The maximum number of searches we keep data about. */ +#ifndef DHT_MAX_SEARCHES +#define DHT_MAX_SEARCHES 1024 +#endif + +/* The time after which we consider a search to be expirable. */ +#ifndef DHT_SEARCH_EXPIRE_TIME +#define DHT_SEARCH_EXPIRE_TIME (62 * 60) +#endif + struct storage { unsigned char id[20]; int numpeers; @@ -207,12 +218,7 @@ static unsigned char oldsecret[8]; static struct bucket *buckets = NULL; static struct storage *storage; -/* The maximum number of concurrent searches. */ -#ifndef DHT_MAX_SEARCHES -#define DHT_MAX_SEARCHES 20 -#endif - -static struct search searches[DHT_MAX_SEARCHES]; +static struct search *searches = NULL; static int numsearches; static unsigned short search_id; @@ -724,10 +730,11 @@ expire_buckets(int s) static struct search * find_search(unsigned short tid) { - int i; - for(i = 0; i < numsearches; i++) { - if(searches[i].tid == tid) - return &searches[i]; + struct search *sr = searches; + while(sr) { + if(sr->tid == tid) + return sr; + sr = sr->next; } return NULL; } @@ -798,6 +805,27 @@ flush_search_node(struct search_node *n, struct search *sr) sr->numnodes--; } +static void +expire_searches(void) +{ + struct search *sr = searches, *previous = NULL; + + while(sr) { + struct search *next = sr->next; + if(sr->step_time < now.tv_sec - DHT_SEARCH_EXPIRE_TIME) { + if(previous) + previous->next = next; + else + searches->next = next; + free(sr); + numsearches--; + } else { + previous = sr; + } + sr = next; + } +} + /* This must always return 0 or 1, never -1, not even on failure (see below). */ static int search_send_get_peers(int s, struct search *sr, struct search_node *n) @@ -909,20 +937,36 @@ search_step(int s, struct search *sr, dht_callback *callback, void *closure) } static struct search * -find_free_search_slot(void) +new_search(void) { - int i; - struct search *sr = NULL; + struct search *sr, *oldest = NULL; - if(numsearches < DHT_MAX_SEARCHES) - return &searches[numsearches++]; - - for(i = 0; i < numsearches; i++) { - if(searches[i].done && - (sr == NULL || searches[i].step_time < sr->step_time)) - sr = &searches[i]; + /* Find the oldest done search */ + sr = searches; + while(sr) { + if(sr->done && + (oldest == NULL || oldest->step_time > sr->step_time)) + oldest = sr; + sr = sr->next; } - return sr; + + /* The oldest slot is expired. */ + if(oldest && oldest->step_time < now.tv_sec - DHT_SEARCH_EXPIRE_TIME) + return oldest; + + /* Allocate a new slot. */ + if(numsearches < DHT_MAX_SEARCHES) { + sr = calloc(1, sizeof(struct search)); + if(sr != NULL) { + sr->next = searches; + searches = sr; + numsearches++; + return sr; + } + } + + /* Oh, well, never mind. Reuse the oldest slot. */ + return oldest; } /* Insert the contents of a bucket into a search structure. */ @@ -945,23 +989,23 @@ dht_search(int s, const unsigned char *id, int port, { struct search *sr; struct bucket *b; - int i; - for(i = 0; i < numsearches; i++) { - if(id_cmp(searches[i].id, id) == 0) + sr = searches; + while(sr) { + if(id_cmp(sr->id, id) == 0) break; + sr = sr->next; } - if(i < numsearches) { + if(sr) { /* We're reusing data from an old search. Reusing the same tid means that we can merge replies for both searches. */ - int j; - sr = searches + i; + int i; sr->done = 0; again: - for(j = 0; j < sr->numnodes; j++) { + for(i = 0; i < sr->numnodes; i++) { struct search_node *n; - n = &sr->nodes[j]; + n = &sr->nodes[i]; /* Discard any doubtful nodes. */ if(n->pinged >= 3 || n->reply_time < now.tv_sec - 7200) { flush_search_node(n, sr); @@ -973,14 +1017,15 @@ dht_search(int s, const unsigned char *id, int port, n->acked = 0; } } else { - sr = find_free_search_slot(); + sr = new_search(); if(sr == NULL) { errno = ENOSPC; return -1; } - memset(sr, 0, sizeof(struct search)); sr->tid = search_id++; + sr->step_time = 0; memcpy(sr->id, id, 20); + sr->done = 0; sr->numnodes = 0; } @@ -1107,24 +1152,26 @@ expire_storage(void) static void broken_node(int s, const unsigned char *id, struct sockaddr_in *sin) { - int i, j; + int i; debugf("Blacklisting broken node.\n"); if(id) { - /* Make the node easy to discard. */ struct node *n; + struct search *sr; + /* Make the node easy to discard. */ n = find_node(id); if(n) { n->pinged = 3; pinged(s, n, NULL); } /* Discard it from any searches in progress. */ - for(i = 0; i < numsearches; i++) { - for(j = 0; j < searches[i].numnodes; j++) - if(id_cmp(searches[i].nodes[j].id, id) == 0) - flush_search_node(&searches[i].nodes[j], - &searches[i]); + sr = searches; + while(sr) { + for(i = 0; i < sr->numnodes; i++) + if(id_cmp(sr->nodes[i].id, id) == 0) + flush_search_node(&sr->nodes[i], sr); + sr = sr->next; } } /* And make sure we don't hear from it again. */ @@ -1214,9 +1261,10 @@ dht_nodes(int *good_return, int *dubious_return, int *cached_return, void dht_dump_tables(FILE *f) { - int i, j; + int i; struct bucket *b = buckets; struct storage *st = storage; + struct search *sr = searches; fprintf(f, "My id "); print_hex(f, myid, 20); @@ -1250,15 +1298,14 @@ dht_dump_tables(FILE *f) } b = b->next; } - for(i = 0; i < numsearches; i++) { - struct search *sr = &searches[i]; - fprintf(f, "\nSearch %d id ", i); + while(sr) { + fprintf(f, "\nSearch id "); print_hex(f, sr->id, 20); fprintf(f, " age %d%s\n", (int)(now.tv_sec - sr->step_time), sr->done ? " (done)" : ""); - for(j = 0; j < sr->numnodes; j++) { - struct search_node *n = &sr->nodes[j]; - fprintf(f, "Node %d id ", j); + for(i = 0; i < sr->numnodes; i++) { + struct search_node *n = &sr->nodes[i]; + fprintf(f, "Node %d id ", i); print_hex(f, n->id, 20); fprintf(f, " bits %d age ", common_bits(sr->id, n->id)); if(n->request_time) @@ -1270,6 +1317,7 @@ dht_dump_tables(FILE *f) find_node(n->id) ? " (known)" : "", n->replied ? " (replied)" : ""); } + sr = sr->next; } @@ -1305,6 +1353,7 @@ dht_init(int s, const unsigned char *id, const unsigned char *v) if(buckets == NULL) return -1; + searches = NULL; numsearches = 0; storage = NULL; @@ -1654,26 +1703,29 @@ dht_periodic(int s, int available, time_t *tosleep, if(now.tv_sec >= expire_stuff_time) { expire_buckets(s); expire_storage(); + expire_searches(); } if(search_time > 0 && now.tv_sec >= search_time) { - int i; - for(i = 0; i < numsearches; i++) { - struct search *sr = &searches[i]; + struct search *sr; + sr = searches; + while(sr) { if(!sr->done && sr->step_time + 5 <= now.tv_sec) { search_step(s, sr, callback, closure); } + sr = sr->next; } search_time = 0; - - for(i = 0; i < numsearches; i++) { - struct search *sr = &searches[i]; + + sr = searches; + while(sr) { if(!sr->done) { time_t tm = sr->step_time + 15 + random() % 10; if(search_time == 0 || search_time > tm) search_time = tm; } + sr = sr->next; } }