mirror of
https://github.com/transmission/transmission
synced 2025-03-03 02:05:19 +00:00
(trunk third-party) #2302: upgrade from dht 0.6 to 0.8.
This commit is contained in:
parent
0b57127650
commit
c33f27c06c
3 changed files with 129 additions and 62 deletions
11
third-party/dht/CHANGES
vendored
11
third-party/dht/CHANGES
vendored
|
@ -1,3 +1,14 @@
|
|||
28 July 2009: dht-0.8
|
||||
|
||||
* Fixed a crash when expiring the first search on the list.
|
||||
* Fixed freeing of the search list when uniniting with dofree = 1.
|
||||
|
||||
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.
|
||||
|
|
18
third-party/dht/README
vendored
18
third-party/dht/README
vendored
|
@ -93,7 +93,7 @@ interesting happens (see below).
|
|||
|
||||
This schedules a search for information about the info-hash specified in
|
||||
id. If port is not 0, it specifies the TCP port on which the current peer
|
||||
is litening; in that case, when the search is complete it will be announced
|
||||
is listening; in that case, when the search is complete it will be announced
|
||||
to the network. The port is in host order, beware if you got it from
|
||||
a struct sockaddr_in.
|
||||
|
||||
|
@ -101,7 +101,7 @@ In either case, data is passed to the callback function as soon as it is
|
|||
available, possibly in multiple pieces. The callback function will
|
||||
additionally be called when the search is complete.
|
||||
|
||||
Up to DHT_MAX_SEARCHES (20) searches can be in progress at a given time;
|
||||
Up to DHT_MAX_SEARCHES (1024) searches can be in progress at a given time;
|
||||
any more, and dht_search will return -1. If you specify a new search for
|
||||
the same info hash as a search still in progress, the previous search is
|
||||
combined with the new one -- you will only receive a completion indication
|
||||
|
@ -123,12 +123,12 @@ It also includes the number of nodes that recently send us an unsolicited
|
|||
request; this can be used to determine if the UDP port used for the DHT is
|
||||
firewalled.
|
||||
|
||||
If you want to display a single figure to the user, you should display good
|
||||
+ doubtful, which is the total number of nodes in your routing table. Some
|
||||
clients try to estimate the total number of nodes, but this doesn't make
|
||||
much sense -- since the result is exponential in the number of nodes in the
|
||||
routing table, small variations in the latter cause huge jumps in the
|
||||
former.
|
||||
If you want to display a single figure to the user, you should display
|
||||
good + doubtful, which is the total number of nodes in your routing table.
|
||||
Some clients try to estimate the total number of nodes, but this doesn't
|
||||
make much sense -- since the result is exponential in the number of nodes
|
||||
in the routing table, small variations in the latter cause huge jumps in
|
||||
the former.
|
||||
|
||||
* dht_get_nodes
|
||||
|
||||
|
@ -186,8 +186,6 @@ make most full cone NATs happy.
|
|||
Some of the code has had very little testing. If it breaks, you get to
|
||||
keep both pieces.
|
||||
|
||||
There is currently no good way to save and restore your routing table.
|
||||
|
||||
IPv6 support is deliberately not included: designing a double-stack
|
||||
distributed hash table raises some tricky issues, and doing it naively may
|
||||
break connectivity for everyone.
|
||||
|
|
162
third-party/dht/dht.c
vendored
162
third-party/dht/dht.c
vendored
|
@ -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;
|
||||
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;
|
||||
|
@ -1377,7 +1426,13 @@ dht_uninit(int s, int dofree)
|
|||
free(st->peers);
|
||||
free(st);
|
||||
}
|
||||
|
||||
|
||||
while(searches) {
|
||||
struct search *sr = searches;
|
||||
searches = searches->next;
|
||||
free(sr);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1654,26 +1709,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue