diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | opentracker.c | 2 | ||||
-rw-r--r-- | ot_clean.c | 119 | ||||
-rw-r--r-- | ot_clean.h | 15 | ||||
-rw-r--r-- | ot_mutex.c | 31 | ||||
-rw-r--r-- | ot_mutex.h | 9 | ||||
-rw-r--r-- | ot_stats.c | 201 | ||||
-rw-r--r-- | ot_stats.h | 13 | ||||
-rw-r--r-- | ot_sync.c | 107 | ||||
-rw-r--r-- | ot_sync.h | 14 | ||||
-rw-r--r-- | ot_vector.c | 110 | ||||
-rw-r--r-- | ot_vector.h | 26 | ||||
-rw-r--r-- | trackerlogic.c | 600 | ||||
-rw-r--r-- | trackerlogic.h | 48 |
14 files changed, 723 insertions, 578 deletions
@@ -1,13 +1,13 @@ | |||
1 | CC?=gcc | 1 | CC?=gcc |
2 | FEATURES=#-DWANT_CLOSED_TRACKER -DWANT_UTORRENT1600_WORKAROUND #-DWANT_IP_FROM_QUERY_STRING -D_DEBUG_HTTPERROR -DWANT_TRACKER_SYNC | 2 | FEATURES=-DWANT_TRACKER_SYNC #-DWANT_CLOSED_TRACKER -DWANT_UTORRENT1600_WORKAROUND #-DWANT_IP_FROM_QUERY_STRING -D_DEBUG_HTTPERROR -DWANT_TRACKER_SYNC |
3 | OPTS_debug=-g -ggdb #-pg # -fprofile-arcs -ftest-coverage | 3 | OPTS_debug=-g -ggdb #-pg # -fprofile-arcs -ftest-coverage |
4 | OPTS_production=-s -Os | 4 | OPTS_production=-s -Os |
5 | CFLAGS+=-I../libowfat -Wall -pipe -Wextra #-pedantic #-ansi | 5 | CFLAGS+=-I../libowfat -Wall -pipe -Wextra #-pedantic #-ansi |
6 | LDFLAGS+=-L../libowfat/ -lowfat | 6 | LDFLAGS+=-L../libowfat/ -lowfat |
7 | 7 | ||
8 | BINARY = opentracker | 8 | BINARY = opentracker |
9 | HEADERS=trackerlogic.h scan_urlencoded_query.h mutex.h | 9 | HEADERS=trackerlogic.h scan_urlencoded_query.h ot_mutex.h ot_stats.h ot_sync.h ot_vector.h ot_clean.h |
10 | SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c mutex.c | 10 | SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_mutex.c ot_stats.c ot_sync.c ot_vector.c ot_clean.c |
11 | 11 | ||
12 | all: $(BINARY) $(BINARY).debug | 12 | all: $(BINARY) $(BINARY).debug |
13 | 13 | ||
diff --git a/opentracker.c b/opentracker.c index 00fe65f..0345177 100644 --- a/opentracker.c +++ b/opentracker.c | |||
@@ -29,6 +29,8 @@ | |||
29 | 29 | ||
30 | #include "trackerlogic.h" | 30 | #include "trackerlogic.h" |
31 | #include "scan_urlencoded_query.h" | 31 | #include "scan_urlencoded_query.h" |
32 | #include "ot_stats.h" | ||
33 | #include "ot_sync.h" | ||
32 | 34 | ||
33 | /* Globals */ | 35 | /* Globals */ |
34 | static unsigned long long ot_overall_tcp_connections = 0; | 36 | static unsigned long long ot_overall_tcp_connections = 0; |
diff --git a/ot_clean.c b/ot_clean.c new file mode 100644 index 0000000..46b3e0c --- /dev/null +++ b/ot_clean.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
3 | |||
4 | /* System */ | ||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | |||
8 | /* Libowfat */ | ||
9 | #include "byte.h" | ||
10 | |||
11 | /* Opentracker */ | ||
12 | #include "trackerlogic.h" | ||
13 | #include "ot_mutex.h" | ||
14 | |||
15 | /* To remember, when we last cleaned up */ | ||
16 | static ot_time all_torrents_clean[OT_BUCKET_COUNT]; | ||
17 | |||
18 | /* Clean a single torrent | ||
19 | return 1 if torrent timed out | ||
20 | */ | ||
21 | int clean_single_torrent( ot_torrent *torrent ) { | ||
22 | ot_peerlist *peer_list = torrent->peer_list; | ||
23 | size_t peers_count = 0, seeds_count; | ||
24 | time_t timedout = (int)( NOW - peer_list->base ); | ||
25 | int i; | ||
26 | #ifdef WANT_TRACKER_SYNC | ||
27 | char *new_peers; | ||
28 | #endif | ||
29 | |||
30 | /* Torrent has idled out */ | ||
31 | if( timedout > OT_TORRENT_TIMEOUT ) | ||
32 | return 1; | ||
33 | |||
34 | /* Nothing to be cleaned here? Test if torrent is worth keeping */ | ||
35 | if( timedout > OT_POOLS_COUNT ) { | ||
36 | if( !peer_list->peer_count ) | ||
37 | return peer_list->down_count ? 0 : 1; | ||
38 | timedout = OT_POOLS_COUNT; | ||
39 | } | ||
40 | |||
41 | /* Release vectors that have timed out */ | ||
42 | for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i ) | ||
43 | free( peer_list->peers[i].data); | ||
44 | |||
45 | /* Shift vectors back by the amount of pools that were shifted out */ | ||
46 | memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) ); | ||
47 | byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout ); | ||
48 | |||
49 | /* Shift back seed counts as well */ | ||
50 | memmove( peer_list->seed_counts + timedout, peer_list->seed_counts, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) ); | ||
51 | byte_zero( peer_list->seed_counts, sizeof( size_t ) * timedout ); | ||
52 | |||
53 | #ifdef WANT_TRACKER_SYNC | ||
54 | /* Save the block modified within last OT_POOLS_TIMEOUT */ | ||
55 | if( peer_list->peers[1].size && | ||
56 | ( new_peers = realloc( peer_list->changeset.data, sizeof( ot_peer ) * peer_list->peers[1].size ) ) ) | ||
57 | { | ||
58 | memmove( new_peers, peer_list->peers[1].data, peer_list->peers[1].size ); | ||
59 | peer_list->changeset.data = new_peers; | ||
60 | peer_list->changeset.size = sizeof( ot_peer ) * peer_list->peers[1].size; | ||
61 | } else { | ||
62 | free( peer_list->changeset.data ); | ||
63 | |||
64 | memset( &peer_list->changeset, 0, sizeof( ot_vector ) ); | ||
65 | } | ||
66 | #endif | ||
67 | |||
68 | peers_count = seeds_count = 0; | ||
69 | for( i = 0; i < OT_POOLS_COUNT; ++i ) { | ||
70 | peers_count += peer_list->peers[i].size; | ||
71 | seeds_count += peer_list->seed_counts[i]; | ||
72 | } | ||
73 | peer_list->seed_count = seeds_count; | ||
74 | peer_list->peer_count = peers_count; | ||
75 | |||
76 | if( peers_count ) | ||
77 | peer_list->base = NOW; | ||
78 | else { | ||
79 | /* When we got here, the last time that torrent | ||
80 | has been touched is OT_POOLS_COUNT units before */ | ||
81 | peer_list->base = NOW - OT_POOLS_COUNT; | ||
82 | } | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | /* Clean up all peers in current bucket, remove timedout pools and | ||
87 | torrents */ | ||
88 | void clean_all_torrents( void ) { | ||
89 | ot_vector *torrents_list; | ||
90 | size_t i; | ||
91 | static int bucket; | ||
92 | ot_time time_now = NOW; | ||
93 | |||
94 | /* Search for an uncleaned bucked */ | ||
95 | while( ( all_torrents_clean[bucket] == time_now ) && ( ++bucket < OT_BUCKET_COUNT ) ); | ||
96 | if( bucket >= OT_BUCKET_COUNT ) { | ||
97 | bucket = 0; return; | ||
98 | } | ||
99 | |||
100 | all_torrents_clean[bucket] = time_now; | ||
101 | |||
102 | torrents_list = mutex_bucket_lock( bucket ); | ||
103 | for( i=0; i<torrents_list->size; ++i ) { | ||
104 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + i; | ||
105 | if( clean_single_torrent( torrent ) ) { | ||
106 | vector_remove_torrent( torrents_list, torrent ); | ||
107 | --i; continue; | ||
108 | } | ||
109 | } | ||
110 | mutex_bucket_unlock( bucket ); | ||
111 | } | ||
112 | |||
113 | void clean_init( void ) { | ||
114 | byte_zero( all_torrents_clean, sizeof( all_torrents_clean ) ); | ||
115 | } | ||
116 | |||
117 | void clean_deinit( void ) { | ||
118 | byte_zero( all_torrents_clean, sizeof( all_torrents_clean ) ); | ||
119 | } \ No newline at end of file | ||
diff --git a/ot_clean.h b/ot_clean.h new file mode 100644 index 0000000..9c2fe11 --- /dev/null +++ b/ot_clean.h | |||
@@ -0,0 +1,15 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
3 | |||
4 | #ifndef __OT_CLEAN_H__ | ||
5 | #define __OT_CLEAN_H__ | ||
6 | |||
7 | #include "trackerlogic.h" | ||
8 | |||
9 | void clean_init( void ); | ||
10 | void clean_deinit( void ); | ||
11 | |||
12 | void clean_all_torrents( void ); | ||
13 | int clean_single_torrent( ot_torrent *torrent ); | ||
14 | |||
15 | #endif \ No newline at end of file | ||
@@ -1,11 +1,19 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> |
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | 2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ |
3 | 3 | ||
4 | /* System */ | ||
4 | #include <pthread.h> | 5 | #include <pthread.h> |
5 | #include <stdio.h> | 6 | #include <stdio.h> |
6 | 7 | ||
8 | /* Libowfat */ | ||
9 | #include "byte.h" | ||
10 | |||
11 | /* Opentracker */ | ||
7 | #include "trackerlogic.h" | 12 | #include "trackerlogic.h" |
8 | #include "mutex.h" | 13 | #include "ot_mutex.h" |
14 | |||
15 | /* Our global all torrents list */ | ||
16 | static ot_vector all_torrents[OT_BUCKET_COUNT]; | ||
9 | 17 | ||
10 | static int bucket_locklist[ OT_MAX_THREADS ]; | 18 | static int bucket_locklist[ OT_MAX_THREADS ]; |
11 | static int bucket_locklist_count = 0; | 19 | static int bucket_locklist_count = 0; |
@@ -51,12 +59,23 @@ static void bucket_remove( int bucket ) { | |||
51 | --bucket_locklist_count; | 59 | --bucket_locklist_count; |
52 | } | 60 | } |
53 | 61 | ||
54 | void mutex_bucket_lock( int bucket ) { | 62 | ot_vector *mutex_bucket_lock( int bucket ) { |
55 | pthread_mutex_lock( &bucket_mutex ); | 63 | pthread_mutex_lock( &bucket_mutex ); |
56 | while( bucket_check( bucket ) ) | 64 | while( bucket_check( bucket ) ) |
57 | pthread_cond_wait( &bucket_being_unlocked, &bucket_mutex ); | 65 | pthread_cond_wait( &bucket_being_unlocked, &bucket_mutex ); |
58 | bucket_push( bucket ); | 66 | bucket_push( bucket ); |
59 | pthread_mutex_unlock( &bucket_mutex ); | 67 | pthread_mutex_unlock( &bucket_mutex ); |
68 | return all_torrents + bucket; | ||
69 | } | ||
70 | |||
71 | ot_vector *mutex_bucket_lock_by_hash( ot_hash *hash ) { | ||
72 | unsigned char *local_hash = hash[0]; | ||
73 | int bucket = ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 ); | ||
74 | |||
75 | /* Can block */ | ||
76 | mutex_bucket_lock( bucket ); | ||
77 | |||
78 | return all_torrents + bucket; | ||
60 | } | 79 | } |
61 | 80 | ||
62 | void mutex_bucket_unlock( int bucket ) { | 81 | void mutex_bucket_unlock( int bucket ) { |
@@ -66,12 +85,20 @@ void mutex_bucket_unlock( int bucket ) { | |||
66 | pthread_mutex_unlock( &bucket_mutex ); | 85 | pthread_mutex_unlock( &bucket_mutex ); |
67 | } | 86 | } |
68 | 87 | ||
88 | void mutex_bucket_unlock_by_hash( ot_hash *hash ) { | ||
89 | unsigned char *local_hash = hash[0]; | ||
90 | int bucket = ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 ); | ||
91 | mutex_bucket_unlock( bucket ); | ||
92 | } | ||
93 | |||
69 | void mutex_init( ) { | 94 | void mutex_init( ) { |
70 | pthread_mutex_init(&bucket_mutex, NULL); | 95 | pthread_mutex_init(&bucket_mutex, NULL); |
71 | pthread_cond_init (&bucket_being_unlocked, NULL); | 96 | pthread_cond_init (&bucket_being_unlocked, NULL); |
97 | byte_zero( all_torrents, sizeof( all_torrents ) ); | ||
72 | } | 98 | } |
73 | 99 | ||
74 | void mutex_deinit( ) { | 100 | void mutex_deinit( ) { |
75 | pthread_mutex_destroy(&bucket_mutex); | 101 | pthread_mutex_destroy(&bucket_mutex); |
76 | pthread_cond_destroy(&bucket_being_unlocked); | 102 | pthread_cond_destroy(&bucket_being_unlocked); |
103 | byte_zero( all_torrents, sizeof( all_torrents ) ); | ||
77 | } | 104 | } |
@@ -1,13 +1,16 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> |
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | 2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ |
3 | 3 | ||
4 | #ifndef __MUTEX_H__ | 4 | #ifndef __OT_MUTEX_H__ |
5 | #define __MUTEX_H__ | 5 | #define __OT_MUTEX_H__ |
6 | 6 | ||
7 | void mutex_init( ); | 7 | void mutex_init( ); |
8 | void mutex_deinit( ); | 8 | void mutex_deinit( ); |
9 | 9 | ||
10 | void mutex_bucket_lock( int bucket ); | 10 | ot_vector *mutex_bucket_lock( int bucket ); |
11 | ot_vector *mutex_bucket_lock_by_hash( ot_hash *hash ); | ||
12 | |||
11 | void mutex_bucket_unlock( int bucket ); | 13 | void mutex_bucket_unlock( int bucket ); |
14 | void mutex_bucket_unlock_by_hash( ot_hash *hash ); | ||
12 | 15 | ||
13 | #endif | 16 | #endif |
diff --git a/ot_stats.c b/ot_stats.c new file mode 100644 index 0000000..215d557 --- /dev/null +++ b/ot_stats.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
3 | |||
4 | /* System */ | ||
5 | #include <stdlib.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <sys/mman.h> | ||
8 | #include <stdio.h> | ||
9 | #include <string.h> | ||
10 | |||
11 | /* Libowfat */ | ||
12 | #include "byte.h" | ||
13 | |||
14 | /* Opentracker */ | ||
15 | #include "trackerlogic.h" | ||
16 | #include "ot_mutex.h" | ||
17 | #include "ot_stats.h" | ||
18 | |||
19 | /* Converter function from memory to human readable hex strings */ | ||
20 | static char*to_hex(char*d,ot_byte*s){const char*m="0123456789ABCDEF";char*e=d+40;while(d<e){*d++=m[*s>>4];*d++=m[*s++&15];}*d=0;return d;} | ||
21 | |||
22 | typedef struct { size_t val; ot_torrent * torrent; } ot_record; | ||
23 | |||
24 | /* Fetches stats from tracker */ | ||
25 | size_t return_stats_for_tracker( char *reply, int mode ) { | ||
26 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; | ||
27 | ot_record top5s[5], top5c[5]; | ||
28 | char *r = reply; | ||
29 | int bucket; | ||
30 | |||
31 | byte_zero( top5s, sizeof( top5s ) ); | ||
32 | byte_zero( top5c, sizeof( top5c ) ); | ||
33 | |||
34 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | ||
35 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); | ||
36 | torrent_count += torrents_list->size; | ||
37 | for( j=0; j<torrents_list->size; ++j ) { | ||
38 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | ||
39 | if( mode == STATS_TOP5 ) { | ||
40 | int idx = 4; while( (idx >= 0) && ( peer_list->peer_count > top5c[idx].val ) ) --idx; | ||
41 | if ( idx++ != 4 ) { | ||
42 | memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) ); | ||
43 | top5c[idx].val = peer_list->peer_count; | ||
44 | top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j; | ||
45 | } | ||
46 | idx = 4; while( (idx >= 0) && ( peer_list->seed_count > top5s[idx].val ) ) --idx; | ||
47 | if ( idx++ != 4 ) { | ||
48 | memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) ); | ||
49 | top5s[idx].val = peer_list->seed_count; | ||
50 | top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j; | ||
51 | } | ||
52 | } | ||
53 | peer_count += peer_list->peer_count; seed_count += peer_list->seed_count; | ||
54 | } | ||
55 | mutex_bucket_unlock( bucket ); | ||
56 | } | ||
57 | if( mode == STATS_TOP5 ) { | ||
58 | char hex_out[42]; | ||
59 | int idx; | ||
60 | r += sprintf( r, "Top5 torrents by peers:\n" ); | ||
61 | for( idx=0; idx<5; ++idx ) | ||
62 | if( top5c[idx].torrent ) | ||
63 | r += sprintf( r, "\t%zd\t%s\n", top5c[idx].val, to_hex( hex_out, top5c[idx].torrent->hash) ); | ||
64 | r += sprintf( r, "Top5 torrents by seeds:\n" ); | ||
65 | for( idx=0; idx<5; ++idx ) | ||
66 | if( top5s[idx].torrent ) | ||
67 | r += sprintf( r, "\t%zd\t%s\n", top5s[idx].val, to_hex( hex_out, top5s[idx].torrent->hash) ); | ||
68 | } else | ||
69 | r += sprintf( r, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", peer_count, seed_count, torrent_count ); | ||
70 | |||
71 | return r - reply; | ||
72 | } | ||
73 | |||
74 | /* This function collects 4096 /24s in 4096 possible | ||
75 | malloc blocks | ||
76 | */ | ||
77 | size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh ) { | ||
78 | |||
79 | #define NUM_TOPBITS 12 | ||
80 | #define NUM_LOWBITS (24-NUM_TOPBITS) | ||
81 | #define NUM_BUFS (1<<NUM_TOPBITS) | ||
82 | #define NUM_S24S (1<<NUM_LOWBITS) | ||
83 | #define MSK_S24S (NUM_S24S-1) | ||
84 | |||
85 | ot_dword *counts[ NUM_BUFS ]; | ||
86 | ot_dword slash24s[amount*2]; /* first dword amount, second dword subnet */ | ||
87 | int bucket; | ||
88 | size_t i, j, k, l; | ||
89 | char *r = reply; | ||
90 | |||
91 | byte_zero( counts, sizeof( counts ) ); | ||
92 | byte_zero( slash24s, amount * 2 * sizeof(ot_dword) ); | ||
93 | |||
94 | r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh ); | ||
95 | |||
96 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | ||
97 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); | ||
98 | for( j=0; j<torrents_list->size; ++j ) { | ||
99 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | ||
100 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | ||
101 | ot_peer *peers = peer_list->peers[k].data; | ||
102 | size_t numpeers = peer_list->peers[k].size; | ||
103 | for( l=0; l<numpeers; ++l ) { | ||
104 | ot_dword s24 = ntohl(*(ot_dword*)(peers+l)) >> 8; | ||
105 | ot_dword *count = counts[ s24 >> NUM_LOWBITS ]; | ||
106 | if( !count ) { | ||
107 | count = malloc( sizeof(ot_dword) * NUM_S24S ); | ||
108 | if( !count ) | ||
109 | goto bailout_cleanup; | ||
110 | byte_zero( count, sizeof( ot_dword ) * NUM_S24S ); | ||
111 | counts[ s24 >> NUM_LOWBITS ] = count; | ||
112 | } | ||
113 | count[ s24 & MSK_S24S ]++; | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | mutex_bucket_unlock( bucket ); | ||
118 | } | ||
119 | |||
120 | k = l = 0; /* Debug: count allocated bufs */ | ||
121 | for( i=0; i < NUM_BUFS; ++i ) { | ||
122 | ot_dword *count = counts[i]; | ||
123 | if( !counts[i] ) | ||
124 | continue; | ||
125 | ++k; /* Debug: count allocated bufs */ | ||
126 | for( j=0; j < NUM_S24S; ++j ) { | ||
127 | if( count[j] > thresh ) { | ||
128 | /* This subnet seems to announce more torrents than the last in our list */ | ||
129 | int insert_pos = amount - 1; | ||
130 | while( ( insert_pos >= 0 ) && ( count[j] > slash24s[ 2 * insert_pos ] ) ) | ||
131 | --insert_pos; | ||
132 | ++insert_pos; | ||
133 | memmove( slash24s + 2 * ( insert_pos + 1 ), slash24s + 2 * ( insert_pos ), 2 * sizeof( ot_dword ) * ( amount - insert_pos - 1 ) ); | ||
134 | slash24s[ 2 * insert_pos ] = count[j]; | ||
135 | slash24s[ 2 * insert_pos + 1 ] = ( i << NUM_TOPBITS ) + j; | ||
136 | if( slash24s[ 2 * amount - 2 ] > thresh ) | ||
137 | thresh = slash24s[ 2 * amount - 2 ]; | ||
138 | } | ||
139 | if( count[j] ) ++l; | ||
140 | } | ||
141 | free( count ); | ||
142 | } | ||
143 | |||
144 | r += sprintf( r, "Allocated bufs: %zd, used s24s: %zd\n", k, l ); | ||
145 | |||
146 | for( i=0; i < amount; ++i ) | ||
147 | if( slash24s[ 2*i ] >= thresh ) { | ||
148 | ot_dword ip = slash24s[ 2*i +1 ]; | ||
149 | r += sprintf( r, "% 10ld %d.%d.%d.0/24\n", (long)slash24s[ 2*i ], (int)(ip >> 16), (int)(255 & ( ip >> 8 )), (int)(ip & 255) ); | ||
150 | } | ||
151 | |||
152 | return r - reply; | ||
153 | |||
154 | bailout_cleanup: | ||
155 | |||
156 | for( i=0; i < NUM_BUFS; ++i ) | ||
157 | free( counts[i] ); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | size_t return_memstat_for_tracker( char **reply ) { | ||
163 | size_t torrent_count = 0, j; | ||
164 | size_t allocated, replysize; | ||
165 | ot_vector *torrents_list; | ||
166 | int bucket, k; | ||
167 | char *r; | ||
168 | |||
169 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | ||
170 | torrents_list = mutex_bucket_lock(bucket); | ||
171 | torrent_count += torrents_list->size; | ||
172 | mutex_bucket_unlock(bucket); | ||
173 | } | ||
174 | |||
175 | allocated = OT_BUCKET_COUNT*32 + (43+OT_POOLS_COUNT*32)*torrent_count; | ||
176 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; | ||
177 | |||
178 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | ||
179 | torrents_list = mutex_bucket_lock(bucket); | ||
180 | r += sprintf( r, "%02X: %08X %08X\n", bucket, (unsigned int)torrents_list->size, (unsigned int)torrents_list->space ); | ||
181 | mutex_bucket_unlock(bucket); | ||
182 | } | ||
183 | |||
184 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | ||
185 | ot_vector *torrents_list = mutex_bucket_lock(bucket); | ||
186 | char hex_out[42]; | ||
187 | for( j=0; j<torrents_list->size; ++j ) { | ||
188 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | ||
189 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | ||
190 | r += sprintf( r, "\n%s:\n", to_hex( hex_out, (ot_byte*)hash) ); | ||
191 | for( k=0; k<OT_POOLS_COUNT; ++k ) | ||
192 | r += sprintf( r, "\t%05X %05X\n", ((unsigned int)peer_list->peers[k].size), (unsigned int)peer_list->peers[k].space ); | ||
193 | } | ||
194 | mutex_bucket_unlock(bucket); | ||
195 | } | ||
196 | |||
197 | replysize = ( r - *reply ); | ||
198 | fix_mmapallocation( *reply, allocated, replysize ); | ||
199 | |||
200 | return replysize; | ||
201 | } \ No newline at end of file | ||
diff --git a/ot_stats.h b/ot_stats.h new file mode 100644 index 0000000..e4d7c06 --- /dev/null +++ b/ot_stats.h | |||
@@ -0,0 +1,13 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
3 | |||
4 | #ifndef __OT_STATS_H__ | ||
5 | #define __OT_STATS_H__ | ||
6 | |||
7 | enum { STATS_CONNS, STATS_PEERS, STATS_TOP5, STATS_DMEM, STATS_TCP, STATS_UDP, STATS_SLASH24S, SYNC_IN, SYNC_OUT, STATS_FULLSCRAPE }; | ||
8 | |||
9 | size_t return_stats_for_tracker( char *reply, int mode ); | ||
10 | size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh ); | ||
11 | size_t return_memstat_for_tracker( char **reply ); | ||
12 | |||
13 | #endif | ||
diff --git a/ot_sync.c b/ot_sync.c new file mode 100644 index 0000000..6e95a98 --- /dev/null +++ b/ot_sync.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
3 | |||
4 | /* System */ | ||
5 | #include <sys/types.h> | ||
6 | #include <sys/mman.h> | ||
7 | #include <stdio.h> | ||
8 | #include <string.h> | ||
9 | |||
10 | /* Libowfat */ | ||
11 | #include "scan.h" | ||
12 | #include "byte.h" | ||
13 | |||
14 | /* Opentracker */ | ||
15 | #include "trackerlogic.h" | ||
16 | #include "ot_mutex.h" | ||
17 | #include "ot_sync.h" | ||
18 | |||
19 | #ifdef WANT_TRACKER_SYNC | ||
20 | /* Import Changeset from an external authority | ||
21 | format: d4:syncd[..]ee | ||
22 | [..]: ( 20:01234567890abcdefghij16:XXXXYYYY )+ | ||
23 | */ | ||
24 | int add_changeset_to_tracker( ot_byte *data, size_t len ) { | ||
25 | ot_hash *hash; | ||
26 | ot_byte *end = data + len; | ||
27 | unsigned long peer_count; | ||
28 | |||
29 | /* We do know, that the string is \n terminated, so it cant | ||
30 | overflow */ | ||
31 | if( byte_diff( data, 8, "d4:syncd" ) ) return -1; | ||
32 | data += 8; | ||
33 | |||
34 | while( 1 ) { | ||
35 | if( byte_diff( data, 3, "20:" ) ) { | ||
36 | if( byte_diff( data, 2, "ee" ) ) | ||
37 | return -1; | ||
38 | return 0; | ||
39 | } | ||
40 | data += 3; | ||
41 | hash = (ot_hash*)data; | ||
42 | data += sizeof( ot_hash ); | ||
43 | |||
44 | /* Scan string length indicator */ | ||
45 | data += ( len = scan_ulong( (char*)data, &peer_count ) ); | ||
46 | |||
47 | /* If no long was scanned, it is not divisible by 8, it is not | ||
48 | followed by a colon or claims to need to much memory, we fail */ | ||
49 | if( !len || !peer_count || ( peer_count & 7 ) || ( *data++ != ':' ) || ( data + peer_count > end ) ) | ||
50 | return -1; | ||
51 | |||
52 | while( peer_count > 0 ) { | ||
53 | add_peer_to_torrent( hash, (ot_peer*)data, 1 ); | ||
54 | data += 8; peer_count -= 8; | ||
55 | } | ||
56 | } | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | /* Proposed output format | ||
61 | d4:syncd20:<info_hash>8*N:(xxxxyyyy)*Nee | ||
62 | */ | ||
63 | size_t return_changeset_for_tracker( char **reply ) { | ||
64 | size_t allocated = 0, i, replysize; | ||
65 | ot_vector *torrents_list; | ||
66 | int bucket; | ||
67 | char *r; | ||
68 | |||
69 | /* Maybe there is time to clean_all_torrents(); */ | ||
70 | |||
71 | /* Determine space needed for whole changeset */ | ||
72 | for( bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket ) { | ||
73 | torrents_list = mutex_bucket_lock(bucket); | ||
74 | for( i=0; i<torrents_list->size; ++i ) { | ||
75 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + i; | ||
76 | allocated += sizeof( ot_hash ) + sizeof(ot_peer) * torrent->peer_list->changeset.size + 13; | ||
77 | } | ||
78 | mutex_bucket_unlock(bucket); | ||
79 | } | ||
80 | |||
81 | /* add "d4:syncd" and "ee" */ | ||
82 | allocated += 8 + 2; | ||
83 | |||
84 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) | ||
85 | return 0; | ||
86 | |||
87 | memmove( r, "d4:syncd", 8 ); r += 8; | ||
88 | for( bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket ) { | ||
89 | torrents_list = mutex_bucket_lock(bucket); | ||
90 | for( i=0; i<torrents_list->size; ++i ) { | ||
91 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + i; | ||
92 | const size_t byte_count = sizeof(ot_peer) * torrent->peer_list->changeset.size; | ||
93 | *r++ = '2'; *r++ = '0'; *r++ = ':'; | ||
94 | memmove( r, torrent->hash, sizeof( ot_hash ) ); r += sizeof( ot_hash ); | ||
95 | r += sprintf( r, "%zd:", byte_count ); | ||
96 | memmove( r, torrent->peer_list->changeset.data, byte_count ); r += byte_count; | ||
97 | } | ||
98 | mutex_bucket_unlock(bucket); | ||
99 | } | ||
100 | *r++ = 'e'; *r++ = 'e'; | ||
101 | |||
102 | replysize = ( r - *reply ); | ||
103 | fix_mmapallocation( *reply, allocated, replysize ); | ||
104 | |||
105 | return replysize; | ||
106 | } | ||
107 | #endif | ||
diff --git a/ot_sync.h b/ot_sync.h new file mode 100644 index 0000000..cf0fb3d --- /dev/null +++ b/ot_sync.h | |||
@@ -0,0 +1,14 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
3 | |||
4 | #ifndef __OT_SYNC_H__ | ||
5 | #define __OT_SYNC_H__ | ||
6 | |||
7 | #include "trackerlogic.h" | ||
8 | |||
9 | #ifdef WANT_TRACKER_SYNC | ||
10 | size_t return_changeset_for_tracker( char **reply ); | ||
11 | int add_changeset_to_tracker( ot_byte *data, size_t len ); | ||
12 | #endif | ||
13 | |||
14 | #endif \ No newline at end of file | ||
diff --git a/ot_vector.c b/ot_vector.c new file mode 100644 index 0000000..aa71279 --- /dev/null +++ b/ot_vector.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
3 | |||
4 | /* System */ | ||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | |||
8 | /* Opentracker */ | ||
9 | #include "trackerlogic.h" | ||
10 | #include "ot_vector.h" | ||
11 | |||
12 | /* This function gives us a binary search that returns a pointer, even if | ||
13 | no exact match is found. In that case it sets exactmatch 0 and gives | ||
14 | calling functions the chance to insert data | ||
15 | */ | ||
16 | void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, | ||
17 | size_t compare_size, int *exactmatch ) { | ||
18 | size_t mc = member_count; | ||
19 | ot_byte *lookat = ((ot_byte*)base) + member_size * (member_count >> 1); | ||
20 | *exactmatch = 1; | ||
21 | |||
22 | while( mc ) { | ||
23 | int cmp = memcmp( lookat, key, compare_size); | ||
24 | if (cmp == 0) return (void *)lookat; | ||
25 | if (cmp < 0) { | ||
26 | base = (void*)(lookat + member_size); | ||
27 | --mc; | ||
28 | } | ||
29 | mc >>= 1; | ||
30 | lookat = ((ot_byte*)base) + member_size * (mc >> 1); | ||
31 | } | ||
32 | *exactmatch = 0; | ||
33 | return (void*)lookat; | ||
34 | } | ||
35 | |||
36 | /* This is the generic insert operation for our vector type. | ||
37 | It tries to locate the object at "key" with size "member_size" by comparing its first "compare_size" bytes with | ||
38 | those of objects in vector. Our special "binary_search" function does that and either returns the match or a | ||
39 | pointer to where the object is to be inserted. vector_find_or_insert makes space for the object and copies it, | ||
40 | if it wasn't found in vector. Caller needs to check the passed "exactmatch" variable to see, whether an insert | ||
41 | took place. If resizing the vector failed, NULL is returned, else the pointer to the object in vector. | ||
42 | */ | ||
43 | void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { | ||
44 | ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); | ||
45 | |||
46 | if( *exactmatch ) return match; | ||
47 | |||
48 | if( vector->size + 1 >= vector->space ) { | ||
49 | size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; | ||
50 | ot_byte *new_data = realloc( vector->data, new_space * member_size ); | ||
51 | if( !new_data ) return NULL; | ||
52 | |||
53 | /* Adjust pointer if it moved by realloc */ | ||
54 | match = new_data + (match - (ot_byte*)vector->data); | ||
55 | |||
56 | vector->data = new_data; | ||
57 | vector->space = new_space; | ||
58 | } | ||
59 | memmove( match + member_size, match, ((ot_byte*)vector->data) + member_size * vector->size - match ); | ||
60 | vector->size++; | ||
61 | return match; | ||
62 | } | ||
63 | |||
64 | /* This is the non-generic delete from vector-operation specialized for peers in pools. | ||
65 | Set hysteresis == 0 if you expect the vector not to ever grow again. | ||
66 | It returns 0 if no peer was found (and thus not removed) | ||
67 | 1 if a non-seeding peer was removed | ||
68 | 2 if a seeding peer was removed | ||
69 | */ | ||
70 | int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis ) { | ||
71 | int exactmatch; | ||
72 | size_t shrink_thresh = hysteresis ? OT_VECTOR_SHRINK_THRESH : OT_VECTOR_SHRINK_RATIO; | ||
73 | ot_peer *end = ((ot_peer*)vector->data) + vector->size; | ||
74 | ot_peer *match; | ||
75 | |||
76 | if( !vector->size ) return 0; | ||
77 | match = binary_search( peer, vector->data, vector->size, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch ); | ||
78 | |||
79 | if( !exactmatch ) return 0; | ||
80 | exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1; | ||
81 | memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) ); | ||
82 | if( ( --vector->size * shrink_thresh < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) { | ||
83 | vector->space /= OT_VECTOR_SHRINK_RATIO; | ||
84 | vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) ); | ||
85 | } | ||
86 | if( !vector->size ) { | ||
87 | /* for peer pools its safe to let them go, | ||
88 | in 999 of 1000 this happens in older pools, that won't ever grow again */ | ||
89 | free( vector->data ); | ||
90 | vector->data = NULL; | ||
91 | vector->space = 0; | ||
92 | } | ||
93 | return exactmatch; | ||
94 | } | ||
95 | |||
96 | void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { | ||
97 | ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; | ||
98 | |||
99 | if( !vector->size ) return; | ||
100 | |||
101 | /* If this is being called after a unsuccessful malloc() for peer_list | ||
102 | in add_peer_to_torrent, match->peer_list actually might be NULL */ | ||
103 | if( match->peer_list) free_peerlist( match->peer_list ); | ||
104 | |||
105 | memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) ); | ||
106 | if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) { | ||
107 | vector->space /= OT_VECTOR_SHRINK_RATIO; | ||
108 | vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) ); | ||
109 | } | ||
110 | } | ||
diff --git a/ot_vector.h b/ot_vector.h new file mode 100644 index 0000000..8863855 --- /dev/null +++ b/ot_vector.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
3 | |||
4 | #ifndef __OT_VECTOR_H__ | ||
5 | #define __OT_VECTOR_H__ | ||
6 | |||
7 | #include "trackerlogic.h" | ||
8 | |||
9 | #define OT_VECTOR_MIN_MEMBERS 4 | ||
10 | #define OT_VECTOR_GROW_RATIO 8 | ||
11 | #define OT_VECTOR_SHRINK_THRESH 6 | ||
12 | #define OT_VECTOR_SHRINK_RATIO 4 | ||
13 | typedef struct { | ||
14 | void *data; | ||
15 | size_t size; | ||
16 | size_t space; | ||
17 | } ot_vector; | ||
18 | |||
19 | void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, | ||
20 | size_t compare_size, int *exactmatch ); | ||
21 | void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ); | ||
22 | |||
23 | int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis ); | ||
24 | void vector_remove_torrent( ot_vector *vector, ot_torrent *match ); | ||
25 | |||
26 | #endif \ No newline at end of file | ||
diff --git a/trackerlogic.c b/trackerlogic.c index 2725399..c09f1b9 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
@@ -1,149 +1,33 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> |
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | 2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ |
3 | 3 | ||
4 | #include "trackerlogic.h" | 4 | /* System */ |
5 | |||
6 | #include <stdlib.h> | 5 | #include <stdlib.h> |
7 | #include <string.h> | 6 | #include <string.h> |
8 | #include <stdio.h> | 7 | #include <stdio.h> |
9 | #include <fcntl.h> | ||
10 | #include <sys/types.h> | 8 | #include <sys/types.h> |
11 | #include <sys/mman.h> | 9 | #include <sys/mman.h> |
12 | #include <arpa/inet.h> | ||
13 | #include <unistd.h> | 10 | #include <unistd.h> |
14 | #include <time.h> | 11 | #include <time.h> |
15 | #include <math.h> | 12 | #include <math.h> |
16 | #include <glob.h> | ||
17 | 13 | ||
18 | #include <errno.h> | 14 | /* Libowfat */ |
19 | #include "scan.h" | 15 | #include "scan.h" |
20 | #include "byte.h" | 16 | #include "byte.h" |
21 | #include "mutex.h" | ||
22 | 17 | ||
23 | /* GLOBAL VARIABLES */ | 18 | /* Opentracker */ |
19 | #include "trackerlogic.h" | ||
20 | #include "ot_mutex.h" | ||
21 | #include "ot_stats.h" | ||
22 | #include "ot_clean.h" | ||
24 | 23 | ||
25 | /* We maintain a list of 1024 pointers to sorted list of ot_torrent structs | 24 | /* GLOBAL VARIABLES */ |
26 | Sort key is, of course, its hash */ | ||
27 | #define OT_BUCKET_COUNT 1024 | ||
28 | static ot_vector all_torrents[OT_BUCKET_COUNT]; | ||
29 | static ot_time all_torrents_clean[OT_BUCKET_COUNT]; | ||
30 | #if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER ) | 25 | #if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER ) |
31 | static ot_vector accesslist; | 26 | static ot_vector accesslist; |
32 | #define WANT_ACCESS_CONTROL | 27 | #define WANT_ACCESS_CONTROL |
33 | #endif | 28 | #endif |
34 | 29 | ||
35 | static int clean_single_torrent( ot_torrent *torrent ); | 30 | void free_peerlist( ot_peerlist *peer_list ) { |
36 | |||
37 | /* these functions protect our buckets from other threads that | ||
38 | try to commit announces or clean up */ | ||
39 | static ot_vector *lock_bucket_by_hash( ot_hash *hash ) { | ||
40 | unsigned char *local_hash = hash[0]; | ||
41 | int bucket = ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 ); | ||
42 | |||
43 | /* Can block */ | ||
44 | mutex_bucket_lock( bucket ); | ||
45 | |||
46 | return all_torrents + bucket; | ||
47 | } | ||
48 | |||
49 | static void *unlock_bucket_by_hash( ot_hash *hash ) { | ||
50 | unsigned char *local_hash = hash[0]; | ||
51 | int bucket = ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 ); | ||
52 | mutex_bucket_unlock( bucket ); | ||
53 | |||
54 | /* To make caller's code look better, allow | ||
55 | return unlock_bucket_by_hash() */ | ||
56 | return NULL; | ||
57 | } | ||
58 | |||
59 | /* Converter function from memory to human readable hex strings */ | ||
60 | static char*to_hex(char*d,ot_byte*s){const char*m="0123456789ABCDEF";char*e=d+40;while(d<e){*d++=m[*s>>4];*d++=m[*s++&15];}*d=0;return d;} | ||
61 | |||
62 | /* This function gives us a binary search that returns a pointer, even if | ||
63 | no exact match is found. In that case it sets exactmatch 0 and gives | ||
64 | calling functions the chance to insert data | ||
65 | */ | ||
66 | static void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, | ||
67 | size_t compare_size, int *exactmatch ) { | ||
68 | size_t mc = member_count; | ||
69 | ot_byte *lookat = ((ot_byte*)base) + member_size * (member_count >> 1); | ||
70 | *exactmatch = 1; | ||
71 | |||
72 | while( mc ) { | ||
73 | int cmp = memcmp( lookat, key, compare_size); | ||
74 | if (cmp == 0) return (void *)lookat; | ||
75 | if (cmp < 0) { | ||
76 | base = (void*)(lookat + member_size); | ||
77 | --mc; | ||
78 | } | ||
79 | mc >>= 1; | ||
80 | lookat = ((ot_byte*)base) + member_size * (mc >> 1); | ||
81 | } | ||
82 | *exactmatch = 0; | ||
83 | return (void*)lookat; | ||
84 | } | ||
85 | |||
86 | /* This is the generic insert operation for our vector type. | ||
87 | It tries to locate the object at "key" with size "member_size" by comparing its first "compare_size" bytes with | ||
88 | those of objects in vector. Our special "binary_search" function does that and either returns the match or a | ||
89 | pointer to where the object is to be inserted. vector_find_or_insert makes space for the object and copies it, | ||
90 | if it wasn't found in vector. Caller needs to check the passed "exactmatch" variable to see, whether an insert | ||
91 | took place. If resizing the vector failed, NULL is returned, else the pointer to the object in vector. | ||
92 | */ | ||
93 | static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { | ||
94 | ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); | ||
95 | |||
96 | if( *exactmatch ) return match; | ||
97 | |||
98 | if( vector->size + 1 >= vector->space ) { | ||
99 | size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; | ||
100 | ot_byte *new_data = realloc( vector->data, new_space * member_size ); | ||
101 | if( !new_data ) return NULL; | ||
102 | |||
103 | /* Adjust pointer if it moved by realloc */ | ||
104 | match = new_data + (match - (ot_byte*)vector->data); | ||
105 | |||
106 | vector->data = new_data; | ||
107 | vector->space = new_space; | ||
108 | } | ||
109 | memmove( match + member_size, match, ((ot_byte*)vector->data) + member_size * vector->size - match ); | ||
110 | vector->size++; | ||
111 | return match; | ||
112 | } | ||
113 | |||
114 | /* This is the non-generic delete from vector-operation specialized for peers in pools. | ||
115 | Set hysteresis == 0 if you expect the vector not to ever grow again. | ||
116 | It returns 0 if no peer was found (and thus not removed) | ||
117 | 1 if a non-seeding peer was removed | ||
118 | 2 if a seeding peer was removed | ||
119 | */ | ||
120 | static int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis ) { | ||
121 | int exactmatch; | ||
122 | size_t shrink_thresh = hysteresis ? OT_VECTOR_SHRINK_THRESH : OT_VECTOR_SHRINK_RATIO; | ||
123 | ot_peer *end = ((ot_peer*)vector->data) + vector->size; | ||
124 | ot_peer *match; | ||
125 | |||
126 | if( !vector->size ) return 0; | ||
127 | match = binary_search( peer, vector->data, vector->size, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch ); | ||
128 | |||
129 | if( !exactmatch ) return 0; | ||
130 | exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1; | ||
131 | memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) ); | ||
132 | if( ( --vector->size * shrink_thresh < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) { | ||
133 | vector->space /= OT_VECTOR_SHRINK_RATIO; | ||
134 | vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) ); | ||
135 | } | ||
136 | if( !vector->size ) { | ||
137 | /* for peer pools its safe to let them go, | ||
138 | in 999 of 1000 this happens in older pools, that won't ever grow again */ | ||
139 | free( vector->data ); | ||
140 | vector->data = NULL; | ||
141 | vector->space = 0; | ||
142 | } | ||
143 | return exactmatch; | ||
144 | } | ||
145 | |||
146 | static void free_peerlist( ot_peerlist *peer_list ) { | ||
147 | size_t i; | 31 | size_t i; |
148 | for( i=0; i<OT_POOLS_COUNT; ++i ) | 32 | for( i=0; i<OT_POOLS_COUNT; ++i ) |
149 | if( peer_list->peers[i].data ) | 33 | if( peer_list->peers[i].data ) |
@@ -154,27 +38,11 @@ static void free_peerlist( ot_peerlist *peer_list ) { | |||
154 | free( peer_list ); | 38 | free( peer_list ); |
155 | } | 39 | } |
156 | 40 | ||
157 | static void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { | ||
158 | ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; | ||
159 | |||
160 | if( !vector->size ) return; | ||
161 | |||
162 | /* If this is being called after a unsuccessful malloc() for peer_list | ||
163 | in add_peer_to_torrent, match->peer_list actually might be NULL */ | ||
164 | if( match->peer_list) free_peerlist( match->peer_list ); | ||
165 | |||
166 | memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) ); | ||
167 | if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) { | ||
168 | vector->space /= OT_VECTOR_SHRINK_RATIO; | ||
169 | vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) ); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC_PARAM( int from_changeset ) ) { | 41 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC_PARAM( int from_changeset ) ) { |
174 | int exactmatch; | 42 | int exactmatch; |
175 | ot_torrent *torrent; | 43 | ot_torrent *torrent; |
176 | ot_peer *peer_dest; | 44 | ot_peer *peer_dest; |
177 | ot_vector *torrents_list = lock_bucket_by_hash( hash ), *peer_pool; | 45 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ), *peer_pool; |
178 | int base_pool = 0; | 46 | int base_pool = 0; |
179 | 47 | ||
180 | #ifdef WANT_ACCESS_CONTROL | 48 | #ifdef WANT_ACCESS_CONTROL |
@@ -184,13 +52,17 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
184 | exactmatch = !exactmatch; | 52 | exactmatch = !exactmatch; |
185 | #endif | 53 | #endif |
186 | 54 | ||
187 | if( exactmatch ) | 55 | if( exactmatch ) { |
188 | return unlock_bucket_by_hash( hash ); | 56 | mutex_bucket_unlock_by_hash( hash ); |
57 | return NULL; | ||
58 | } | ||
189 | #endif | 59 | #endif |
190 | 60 | ||
191 | torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 61 | torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
192 | if( !torrent ) | 62 | if( !torrent ) { |
193 | return unlock_bucket_by_hash( hash ); | 63 | mutex_bucket_unlock_by_hash( hash ); |
64 | return NULL; | ||
65 | } | ||
194 | 66 | ||
195 | if( !exactmatch ) { | 67 | if( !exactmatch ) { |
196 | /* Create a new torrent entry, then */ | 68 | /* Create a new torrent entry, then */ |
@@ -198,7 +70,8 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
198 | 70 | ||
199 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { | 71 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { |
200 | vector_remove_torrent( torrents_list, torrent ); | 72 | vector_remove_torrent( torrents_list, torrent ); |
201 | return unlock_bucket_by_hash( hash ); | 73 | mutex_bucket_unlock_by_hash( hash ); |
74 | return NULL; | ||
202 | } | 75 | } |
203 | 76 | ||
204 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); | 77 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); |
@@ -216,7 +89,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
216 | peer_pool = &torrent->peer_list->peers[0]; | 89 | peer_pool = &torrent->peer_list->peers[0]; |
217 | binary_search( peer, peer_pool->data, peer_pool->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch ); | 90 | binary_search( peer, peer_pool->data, peer_pool->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch ); |
218 | if( exactmatch ) { | 91 | if( exactmatch ) { |
219 | unlock_bucket_by_hash( hash ); | 92 | mutex_bucket_unlock_by_hash( hash ); |
220 | return torrent; | 93 | return torrent; |
221 | } | 94 | } |
222 | base_pool = 1; | 95 | base_pool = 1; |
@@ -248,7 +121,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
248 | torrent->peer_list->seed_count--; | 121 | torrent->peer_list->seed_count--; |
249 | case 1: default: | 122 | case 1: default: |
250 | torrent->peer_list->peer_count--; | 123 | torrent->peer_list->peer_count--; |
251 | unlock_bucket_by_hash( hash ); | 124 | mutex_bucket_unlock_by_hash( hash ); |
252 | return torrent; | 125 | return torrent; |
253 | } | 126 | } |
254 | } | 127 | } |
@@ -269,7 +142,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
269 | memmove( peer_dest, peer, sizeof( ot_peer ) ); | 142 | memmove( peer_dest, peer, sizeof( ot_peer ) ); |
270 | } | 143 | } |
271 | 144 | ||
272 | unlock_bucket_by_hash( hash ); | 145 | mutex_bucket_unlock_by_hash( hash ); |
273 | return torrent; | 146 | return torrent; |
274 | } | 147 | } |
275 | 148 | ||
@@ -282,13 +155,13 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
282 | size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int is_tcp ) { | 155 | size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int is_tcp ) { |
283 | char *r = reply; | 156 | char *r = reply; |
284 | int exactmatch; | 157 | int exactmatch; |
285 | ot_vector *torrents_list = lock_bucket_by_hash( hash ); | 158 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); |
286 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 159 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
287 | ot_peerlist *peer_list = torrent->peer_list; | 160 | ot_peerlist *peer_list = torrent->peer_list; |
288 | size_t index; | 161 | size_t index; |
289 | 162 | ||
290 | if( !torrent ) { | 163 | if( !torrent ) { |
291 | unlock_bucket_by_hash( hash ); | 164 | mutex_bucket_unlock_by_hash( hash ); |
292 | return 0; | 165 | return 0; |
293 | } | 166 | } |
294 | 167 | ||
@@ -338,12 +211,12 @@ size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int | |||
338 | if( is_tcp ) | 211 | if( is_tcp ) |
339 | *r++ = 'e'; | 212 | *r++ = 'e'; |
340 | 213 | ||
341 | unlock_bucket_by_hash( hash ); | 214 | mutex_bucket_unlock_by_hash( hash ); |
342 | return r - reply; | 215 | return r - reply; |
343 | } | 216 | } |
344 | 217 | ||
345 | /* Release memory we allocated too much */ | 218 | /* Release memory we allocated too much */ |
346 | static void fix_mmapallocation( void *buf, size_t old_alloc, size_t new_alloc ) { | 219 | void fix_mmapallocation( void *buf, size_t old_alloc, size_t new_alloc ) { |
347 | int page_size = getpagesize(); | 220 | int page_size = getpagesize(); |
348 | size_t old_pages = 1 + old_alloc / page_size; | 221 | size_t old_pages = 1 + old_alloc / page_size; |
349 | size_t new_pages = 1 + new_alloc / page_size; | 222 | size_t new_pages = 1 + new_alloc / page_size; |
@@ -356,19 +229,23 @@ static void fix_mmapallocation( void *buf, size_t old_alloc, size_t new_alloc ) | |||
356 | size_t return_fullscrape_for_tracker( char **reply ) { | 229 | size_t return_fullscrape_for_tracker( char **reply ) { |
357 | size_t torrent_count = 0, j; | 230 | size_t torrent_count = 0, j; |
358 | size_t allocated, replysize; | 231 | size_t allocated, replysize; |
359 | int i; | 232 | ot_vector *torrents_list; |
233 | int bucket; | ||
360 | char *r; | 234 | char *r; |
361 | 235 | ||
362 | for( i=0; i<OT_BUCKET_COUNT; ++i ) | 236 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { |
363 | torrent_count += all_torrents[i].size; | 237 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); |
238 | torrent_count += torrents_list->size; | ||
239 | mutex_bucket_unlock( bucket ); | ||
240 | } | ||
364 | 241 | ||
365 | /* one extra for pro- and epilogue */ | 242 | /* one extra for pro- and epilogue */ |
366 | allocated = 100*(1+torrent_count); | 243 | allocated = 100*(1+torrent_count); |
367 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; | 244 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; |
368 | 245 | ||
369 | memmove( r, "d5:filesd", 9 ); r += 9; | 246 | memmove( r, "d5:filesd", 9 ); r += 9; |
370 | for( i=0; i<OT_BUCKET_COUNT; ++i ) { | 247 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { |
371 | ot_vector *torrents_list = all_torrents + i; | 248 | torrents_list = mutex_bucket_lock( bucket ); |
372 | for( j=0; j<torrents_list->size; ++j ) { | 249 | for( j=0; j<torrents_list->size; ++j ) { |
373 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 250 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
374 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | 251 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; |
@@ -378,6 +255,7 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
378 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count ); | 255 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count ); |
379 | } | 256 | } |
380 | } | 257 | } |
258 | mutex_bucket_unlock( bucket ); | ||
381 | } | 259 | } |
382 | 260 | ||
383 | *r++='e'; *r++='e'; | 261 | *r++='e'; *r++='e'; |
@@ -388,45 +266,10 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
388 | return replysize; | 266 | return replysize; |
389 | } | 267 | } |
390 | 268 | ||
391 | size_t return_memstat_for_tracker( char **reply ) { | ||
392 | size_t torrent_count = 0, j; | ||
393 | size_t allocated, replysize; | ||
394 | int i, k; | ||
395 | char *r; | ||
396 | |||
397 | for( i=0; i<OT_BUCKET_COUNT; ++i ) { | ||
398 | ot_vector *torrents_list = all_torrents + i; | ||
399 | torrent_count += torrents_list->size; | ||
400 | } | ||
401 | |||
402 | allocated = OT_BUCKET_COUNT*32 + (43+OT_POOLS_COUNT*32)*torrent_count; | ||
403 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; | ||
404 | |||
405 | for( i=0; i<OT_BUCKET_COUNT; ++i ) | ||
406 | r += sprintf( r, "%02X: %08X %08X\n", i, (unsigned int)all_torrents[i].size, (unsigned int)all_torrents[i].space ); | ||
407 | |||
408 | for( i=0; i<OT_BUCKET_COUNT; ++i ) { | ||
409 | ot_vector *torrents_list = all_torrents + i; | ||
410 | char hex_out[42]; | ||
411 | for( j=0; j<torrents_list->size; ++j ) { | ||
412 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | ||
413 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | ||
414 | r += sprintf( r, "\n%s:\n", to_hex( hex_out, (ot_byte*)hash) ); | ||
415 | for( k=0; k<OT_POOLS_COUNT; ++k ) | ||
416 | r += sprintf( r, "\t%05X %05X\n", ((unsigned int)peer_list->peers[k].size), (unsigned int)peer_list->peers[k].space ); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | replysize = ( r - *reply ); | ||
421 | fix_mmapallocation( *reply, allocated, replysize ); | ||
422 | |||
423 | return replysize; | ||
424 | } | ||
425 | |||
426 | /* Fetches scrape info for a specific torrent */ | 269 | /* Fetches scrape info for a specific torrent */ |
427 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | 270 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { |
428 | int exactmatch; | 271 | int exactmatch; |
429 | ot_vector *torrents_list = lock_bucket_by_hash( hash ); | 272 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); |
430 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 273 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
431 | 274 | ||
432 | if( !exactmatch ) { | 275 | if( !exactmatch ) { |
@@ -443,7 +286,7 @@ size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
443 | r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count ); | 286 | r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count ); |
444 | } | 287 | } |
445 | } | 288 | } |
446 | unlock_bucket_by_hash( hash ); | 289 | mutex_bucket_unlock_by_hash( hash ); |
447 | return 12; | 290 | return 12; |
448 | } | 291 | } |
449 | 292 | ||
@@ -456,7 +299,7 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl | |||
456 | 299 | ||
457 | for( i=0; i<amount; ++i ) { | 300 | for( i=0; i<amount; ++i ) { |
458 | ot_hash *hash = hash_list + i; | 301 | ot_hash *hash = hash_list + i; |
459 | ot_vector *torrents_list = lock_bucket_by_hash( hash ); | 302 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); |
460 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 303 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
461 | 304 | ||
462 | if( exactmatch ) { | 305 | if( exactmatch ) { |
@@ -468,347 +311,22 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl | |||
468 | torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ) + 23; | 311 | torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ) + 23; |
469 | } | 312 | } |
470 | } | 313 | } |
471 | unlock_bucket_by_hash( hash ); | 314 | mutex_bucket_unlock_by_hash( hash ); |
472 | } | ||
473 | |||
474 | *r++ = 'e'; *r++ = 'e'; | ||
475 | return r - reply; | ||
476 | } | ||
477 | |||
478 | #ifdef WANT_TRACKER_SYNC | ||
479 | /* Import Changeset from an external authority | ||
480 | format: d4:syncd[..]ee | ||
481 | [..]: ( 20:01234567890abcdefghij16:XXXXYYYY )+ | ||
482 | */ | ||
483 | int add_changeset_to_tracker( ot_byte *data, size_t len ) { | ||
484 | ot_hash *hash; | ||
485 | ot_byte *end = data + len; | ||
486 | unsigned long peer_count; | ||
487 | |||
488 | /* We do know, that the string is \n terminated, so it cant | ||
489 | overflow */ | ||
490 | if( byte_diff( data, 8, "d4:syncd" ) ) return -1; | ||
491 | data += 8; | ||
492 | |||
493 | while( 1 ) { | ||
494 | if( byte_diff( data, 3, "20:" ) ) { | ||
495 | if( byte_diff( data, 2, "ee" ) ) | ||
496 | return -1; | ||
497 | return 0; | ||
498 | } | ||
499 | data += 3; | ||
500 | hash = (ot_hash*)data; | ||
501 | data += sizeof( ot_hash ); | ||
502 | |||
503 | /* Scan string length indicator */ | ||
504 | data += ( len = scan_ulong( (char*)data, &peer_count ) ); | ||
505 | |||
506 | /* If no long was scanned, it is not divisible by 8, it is not | ||
507 | followed by a colon or claims to need to much memory, we fail */ | ||
508 | if( !len || !peer_count || ( peer_count & 7 ) || ( *data++ != ':' ) || ( data + peer_count > end ) ) | ||
509 | return -1; | ||
510 | |||
511 | while( peer_count > 0 ) { | ||
512 | add_peer_to_torrent( hash, (ot_peer*)data, 1 ); | ||
513 | data += 8; peer_count -= 8; | ||
514 | } | ||
515 | } | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | /* Proposed output format | ||
520 | d4:syncd20:<info_hash>8*N:(xxxxyyyy)*Nee | ||
521 | */ | ||
522 | size_t return_changeset_for_tracker( char **reply ) { | ||
523 | size_t allocated = 0, i, replysize; | ||
524 | int bucket; | ||
525 | char *r; | ||
526 | |||
527 | /* Maybe there is time to clean_all_torrents(); */ | ||
528 | |||
529 | /* Determine space needed for whole changeset */ | ||
530 | for( bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket ) { | ||
531 | ot_vector *torrents_list = all_torrents + bucket; | ||
532 | for( i=0; i<torrents_list->size; ++i ) { | ||
533 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + i; | ||
534 | allocated += sizeof( ot_hash ) + sizeof(ot_peer) * torrent->peer_list->changeset.size + 13; | ||
535 | } | ||
536 | } | 315 | } |
537 | 316 | ||
538 | /* add "d4:syncd" and "ee" */ | ||
539 | allocated += 8 + 2; | ||
540 | |||
541 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) | ||
542 | return 0; | ||
543 | |||
544 | memmove( r, "d4:syncd", 8 ); r += 8; | ||
545 | for( bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket ) { | ||
546 | ot_vector *torrents_list = all_torrents + bucket; | ||
547 | for( i=0; i<torrents_list->size; ++i ) { | ||
548 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + i; | ||
549 | const size_t byte_count = sizeof(ot_peer) * torrent->peer_list->changeset.size; | ||
550 | *r++ = '2'; *r++ = '0'; *r++ = ':'; | ||
551 | memmove( r, torrent->hash, sizeof( ot_hash ) ); r += sizeof( ot_hash ); | ||
552 | r += sprintf( r, "%zd:", byte_count ); | ||
553 | memmove( r, torrent->peer_list->changeset.data, byte_count ); r += byte_count; | ||
554 | } | ||
555 | } | ||
556 | *r++ = 'e'; *r++ = 'e'; | 317 | *r++ = 'e'; *r++ = 'e'; |
557 | |||
558 | replysize = ( r - *reply ); | ||
559 | fix_mmapallocation( *reply, allocated, replysize ); | ||
560 | |||
561 | return replysize; | ||
562 | } | ||
563 | #endif | ||
564 | |||
565 | /* Clean a single torrent | ||
566 | return 1 if torrent timed out | ||
567 | */ | ||
568 | static int clean_single_torrent( ot_torrent *torrent ) { | ||
569 | ot_peerlist *peer_list = torrent->peer_list; | ||
570 | size_t peers_count = 0, seeds_count; | ||
571 | time_t timedout = (int)( NOW - peer_list->base ); | ||
572 | int i; | ||
573 | #ifdef WANT_TRACKER_SYNC | ||
574 | char *new_peers; | ||
575 | #endif | ||
576 | |||
577 | /* Torrent has idled out */ | ||
578 | if( timedout > OT_TORRENT_TIMEOUT ) | ||
579 | return 1; | ||
580 | |||
581 | /* Nothing to be cleaned here? Test if torrent is worth keeping */ | ||
582 | if( timedout > OT_POOLS_COUNT ) { | ||
583 | if( !peer_list->peer_count ) | ||
584 | return peer_list->down_count ? 0 : 1; | ||
585 | timedout = OT_POOLS_COUNT; | ||
586 | } | ||
587 | |||
588 | /* Release vectors that have timed out */ | ||
589 | for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i ) | ||
590 | free( peer_list->peers[i].data); | ||
591 | |||
592 | /* Shift vectors back by the amount of pools that were shifted out */ | ||
593 | memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) ); | ||
594 | byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout ); | ||
595 | |||
596 | /* Shift back seed counts as well */ | ||
597 | memmove( peer_list->seed_counts + timedout, peer_list->seed_counts, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) ); | ||
598 | byte_zero( peer_list->seed_counts, sizeof( size_t ) * timedout ); | ||
599 | |||
600 | #ifdef WANT_TRACKER_SYNC | ||
601 | /* Save the block modified within last OT_POOLS_TIMEOUT */ | ||
602 | if( peer_list->peers[1].size && | ||
603 | ( new_peers = realloc( peer_list->changeset.data, sizeof( ot_peer ) * peer_list->peers[1].size ) ) ) | ||
604 | { | ||
605 | memmove( new_peers, peer_list->peers[1].data, peer_list->peers[1].size ); | ||
606 | peer_list->changeset.data = new_peers; | ||
607 | peer_list->changeset.size = sizeof( ot_peer ) * peer_list->peers[1].size; | ||
608 | } else { | ||
609 | free( peer_list->changeset.data ); | ||
610 | |||
611 | memset( &peer_list->changeset, 0, sizeof( ot_vector ) ); | ||
612 | } | ||
613 | #endif | ||
614 | |||
615 | peers_count = seeds_count = 0; | ||
616 | for( i = 0; i < OT_POOLS_COUNT; ++i ) { | ||
617 | peers_count += peer_list->peers[i].size; | ||
618 | seeds_count += peer_list->seed_counts[i]; | ||
619 | } | ||
620 | peer_list->seed_count = seeds_count; | ||
621 | peer_list->peer_count = peers_count; | ||
622 | |||
623 | if( peers_count ) | ||
624 | peer_list->base = NOW; | ||
625 | else { | ||
626 | /* When we got here, the last time that torrent | ||
627 | has been touched is OT_POOLS_COUNT units before */ | ||
628 | peer_list->base = NOW - OT_POOLS_COUNT; | ||
629 | } | ||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | /* Clean up all peers in current bucket, remove timedout pools and | ||
634 | torrents */ | ||
635 | void clean_all_torrents( void ) { | ||
636 | ot_vector *torrents_list; | ||
637 | size_t i; | ||
638 | static int bucket; | ||
639 | ot_time time_now = NOW; | ||
640 | |||
641 | /* Search for an uncleaned bucked */ | ||
642 | while( ( all_torrents_clean[bucket] == time_now ) && ( ++bucket < OT_BUCKET_COUNT ) ); | ||
643 | if( bucket >= OT_BUCKET_COUNT ) { | ||
644 | bucket = 0; return; | ||
645 | } | ||
646 | |||
647 | all_torrents_clean[bucket] = time_now; | ||
648 | |||
649 | mutex_bucket_lock( bucket ); | ||
650 | torrents_list = all_torrents + bucket; | ||
651 | for( i=0; i<torrents_list->size; ++i ) { | ||
652 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + i; | ||
653 | if( clean_single_torrent( torrent ) ) { | ||
654 | vector_remove_torrent( torrents_list, torrent ); | ||
655 | --i; continue; | ||
656 | } | ||
657 | } | ||
658 | mutex_bucket_unlock( bucket ); | ||
659 | } | ||
660 | |||
661 | typedef struct { size_t val; ot_torrent * torrent; } ot_record; | ||
662 | |||
663 | /* Fetches stats from tracker */ | ||
664 | size_t return_stats_for_tracker( char *reply, int mode ) { | ||
665 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; | ||
666 | ot_record top5s[5], top5c[5]; | ||
667 | char *r = reply; | ||
668 | int bucket; | ||
669 | |||
670 | byte_zero( top5s, sizeof( top5s ) ); | ||
671 | byte_zero( top5c, sizeof( top5c ) ); | ||
672 | |||
673 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | ||
674 | ot_vector *torrents_list = all_torrents + bucket; | ||
675 | mutex_bucket_lock( bucket ); | ||
676 | torrent_count += torrents_list->size; | ||
677 | for( j=0; j<torrents_list->size; ++j ) { | ||
678 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | ||
679 | if( mode == STATS_TOP5 ) { | ||
680 | int idx = 4; while( (idx >= 0) && ( peer_list->peer_count > top5c[idx].val ) ) --idx; | ||
681 | if ( idx++ != 4 ) { | ||
682 | memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) ); | ||
683 | top5c[idx].val = peer_list->peer_count; | ||
684 | top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j; | ||
685 | } | ||
686 | idx = 4; while( (idx >= 0) && ( peer_list->seed_count > top5s[idx].val ) ) --idx; | ||
687 | if ( idx++ != 4 ) { | ||
688 | memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) ); | ||
689 | top5s[idx].val = peer_list->seed_count; | ||
690 | top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j; | ||
691 | } | ||
692 | } | ||
693 | peer_count += peer_list->peer_count; seed_count += peer_list->seed_count; | ||
694 | } | ||
695 | mutex_bucket_unlock( bucket ); | ||
696 | } | ||
697 | if( mode == STATS_TOP5 ) { | ||
698 | char hex_out[42]; | ||
699 | int idx; | ||
700 | r += sprintf( r, "Top5 torrents by peers:\n" ); | ||
701 | for( idx=0; idx<5; ++idx ) | ||
702 | if( top5c[idx].torrent ) | ||
703 | r += sprintf( r, "\t%zd\t%s\n", top5c[idx].val, to_hex( hex_out, top5c[idx].torrent->hash) ); | ||
704 | r += sprintf( r, "Top5 torrents by seeds:\n" ); | ||
705 | for( idx=0; idx<5; ++idx ) | ||
706 | if( top5s[idx].torrent ) | ||
707 | r += sprintf( r, "\t%zd\t%s\n", top5s[idx].val, to_hex( hex_out, top5s[idx].torrent->hash) ); | ||
708 | } else | ||
709 | r += sprintf( r, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", peer_count, seed_count, torrent_count ); | ||
710 | |||
711 | return r - reply; | ||
712 | } | ||
713 | |||
714 | /* This function collects 4096 /24s in 4096 possible | ||
715 | malloc blocks | ||
716 | */ | ||
717 | size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh ) { | ||
718 | |||
719 | #define NUM_TOPBITS 12 | ||
720 | #define NUM_LOWBITS (24-NUM_TOPBITS) | ||
721 | #define NUM_BUFS (1<<NUM_TOPBITS) | ||
722 | #define NUM_S24S (1<<NUM_LOWBITS) | ||
723 | #define MSK_S24S (NUM_S24S-1) | ||
724 | |||
725 | ot_dword *counts[ NUM_BUFS ]; | ||
726 | ot_dword slash24s[amount*2]; /* first dword amount, second dword subnet */ | ||
727 | int bucket; | ||
728 | size_t i, j, k, l; | ||
729 | char *r = reply; | ||
730 | |||
731 | byte_zero( counts, sizeof( counts ) ); | ||
732 | byte_zero( slash24s, amount * 2 * sizeof(ot_dword) ); | ||
733 | |||
734 | r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh ); | ||
735 | |||
736 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | ||
737 | ot_vector *torrents_list = all_torrents + bucket; | ||
738 | mutex_bucket_lock( bucket ); | ||
739 | for( j=0; j<torrents_list->size; ++j ) { | ||
740 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | ||
741 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | ||
742 | ot_peer *peers = peer_list->peers[k].data; | ||
743 | size_t numpeers = peer_list->peers[k].size; | ||
744 | for( l=0; l<numpeers; ++l ) { | ||
745 | ot_dword s24 = ntohl(*(ot_dword*)(peers+l)) >> 8; | ||
746 | ot_dword *count = counts[ s24 >> NUM_LOWBITS ]; | ||
747 | if( !count ) { | ||
748 | count = malloc( sizeof(ot_dword) * NUM_S24S ); | ||
749 | if( !count ) | ||
750 | goto bailout_cleanup; | ||
751 | byte_zero( count, sizeof( ot_dword ) * NUM_S24S ); | ||
752 | counts[ s24 >> NUM_LOWBITS ] = count; | ||
753 | } | ||
754 | count[ s24 & MSK_S24S ]++; | ||
755 | } | ||
756 | } | ||
757 | } | ||
758 | mutex_bucket_unlock( bucket ); | ||
759 | } | ||
760 | |||
761 | k = l = 0; /* Debug: count allocated bufs */ | ||
762 | for( i=0; i < NUM_BUFS; ++i ) { | ||
763 | ot_dword *count = counts[i]; | ||
764 | if( !counts[i] ) | ||
765 | continue; | ||
766 | ++k; /* Debug: count allocated bufs */ | ||
767 | for( j=0; j < NUM_S24S; ++j ) { | ||
768 | if( count[j] > thresh ) { | ||
769 | /* This subnet seems to announce more torrents than the last in our list */ | ||
770 | int insert_pos = amount - 1; | ||
771 | while( ( insert_pos >= 0 ) && ( count[j] > slash24s[ 2 * insert_pos ] ) ) | ||
772 | --insert_pos; | ||
773 | ++insert_pos; | ||
774 | memmove( slash24s + 2 * ( insert_pos + 1 ), slash24s + 2 * ( insert_pos ), 2 * sizeof( ot_dword ) * ( amount - insert_pos - 1 ) ); | ||
775 | slash24s[ 2 * insert_pos ] = count[j]; | ||
776 | slash24s[ 2 * insert_pos + 1 ] = ( i << NUM_TOPBITS ) + j; | ||
777 | if( slash24s[ 2 * amount - 2 ] > thresh ) | ||
778 | thresh = slash24s[ 2 * amount - 2 ]; | ||
779 | } | ||
780 | if( count[j] ) ++l; | ||
781 | } | ||
782 | free( count ); | ||
783 | } | ||
784 | |||
785 | r += sprintf( r, "Allocated bufs: %zd, used s24s: %zd\n", k, l ); | ||
786 | |||
787 | for( i=0; i < amount; ++i ) | ||
788 | if( slash24s[ 2*i ] >= thresh ) { | ||
789 | ot_dword ip = slash24s[ 2*i +1 ]; | ||
790 | r += sprintf( r, "% 10ld %d.%d.%d.0/24\n", (long)slash24s[ 2*i ], (int)(ip >> 16), (int)(255 & ( ip >> 8 )), (int)(ip & 255) ); | ||
791 | } | ||
792 | |||
793 | return r - reply; | 318 | return r - reply; |
794 | |||
795 | bailout_cleanup: | ||
796 | |||
797 | for( i=0; i < NUM_BUFS; ++i ) | ||
798 | free( counts[i] ); | ||
799 | |||
800 | return 0; | ||
801 | } | 319 | } |
802 | 320 | ||
803 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) { | 321 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) { |
804 | int exactmatch; | 322 | int exactmatch; |
805 | size_t index; | 323 | size_t index; |
806 | ot_vector *torrents_list = lock_bucket_by_hash( hash ); | 324 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); |
807 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 325 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
808 | ot_peerlist *peer_list; | 326 | ot_peerlist *peer_list; |
809 | 327 | ||
810 | if( !exactmatch ) { | 328 | if( !exactmatch ) { |
811 | unlock_bucket_by_hash( hash ); | 329 | mutex_bucket_unlock_by_hash( hash ); |
812 | 330 | ||
813 | if( is_tcp ) | 331 | if( is_tcp ) |
814 | return sprintf( reply, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 332 | return sprintf( reply, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
@@ -835,7 +353,7 @@ exit_loop: | |||
835 | 353 | ||
836 | if( is_tcp ) { | 354 | if( is_tcp ) { |
837 | size_t reply_size = sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 355 | size_t reply_size = sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
838 | unlock_bucket_by_hash( hash ); | 356 | mutex_bucket_unlock_by_hash( hash ); |
839 | return reply_size; | 357 | return reply_size; |
840 | } | 358 | } |
841 | 359 | ||
@@ -844,7 +362,7 @@ exit_loop: | |||
844 | ((ot_dword*)reply)[3] = peer_list->peer_count - peer_list->seed_count; | 362 | ((ot_dword*)reply)[3] = peer_list->peer_count - peer_list->seed_count; |
845 | ((ot_dword*)reply)[4] = peer_list->seed_count; | 363 | ((ot_dword*)reply)[4] = peer_list->seed_count; |
846 | 364 | ||
847 | unlock_bucket_by_hash( hash ); | 365 | mutex_bucket_unlock_by_hash( hash ); |
848 | return (size_t)20; | 366 | return (size_t)20; |
849 | } | 367 | } |
850 | 368 | ||
@@ -874,30 +392,28 @@ int trackerlogic_init( const char * const serverdir ) { | |||
874 | } | 392 | } |
875 | 393 | ||
876 | srandom( time(NULL) ); | 394 | srandom( time(NULL) ); |
877 | 395 | ||
878 | /* Initialize control structures */ | 396 | clean_init( ); |
879 | byte_zero( all_torrents, sizeof( all_torrents ) ); | ||
880 | |||
881 | mutex_init( ); | 397 | mutex_init( ); |
882 | 398 | ||
883 | return 0; | 399 | return 0; |
884 | } | 400 | } |
885 | 401 | ||
886 | void trackerlogic_deinit( void ) { | 402 | void trackerlogic_deinit( void ) { |
887 | int i; | 403 | int bucket; |
888 | size_t j; | 404 | size_t j; |
889 | 405 | ||
890 | /* Free all torrents... */ | 406 | /* Free all torrents... */ |
891 | for(i=0; i<OT_BUCKET_COUNT; ++i ) { | 407 | for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { |
892 | if( all_torrents[i].size ) { | 408 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); |
893 | ot_torrent *torrents_list = (ot_torrent*)all_torrents[i].data; | 409 | if( torrents_list->size ) { |
894 | for( j=0; j<all_torrents[i].size; ++j ) | 410 | for( j=0; j<torrents_list->size; ++j ) { |
895 | free_peerlist( torrents_list[j].peer_list ); | 411 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j; |
896 | free( all_torrents[i].data ); | 412 | free_peerlist( torrent->peer_list ); |
413 | } | ||
414 | free( torrents_list->data ); | ||
897 | } | 415 | } |
898 | } | 416 | } |
899 | byte_zero( all_torrents, sizeof (all_torrents)); | ||
900 | byte_zero( all_torrents_clean, sizeof (all_torrents_clean)); | ||
901 | |||
902 | mutex_deinit( ); | 417 | mutex_deinit( ); |
903 | } | 418 | clean_deinit( ); |
419 | } \ No newline at end of file | ||
diff --git a/trackerlogic.h b/trackerlogic.h index 5b03012..fd80f92 100644 --- a/trackerlogic.h +++ b/trackerlogic.h | |||
@@ -1,8 +1,8 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> |
2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | 2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ |
3 | 3 | ||
4 | #ifndef __TRACKERLOGIC_H__ | 4 | #ifndef __OT_TRACKERLOGIC_H__ |
5 | #define __TRACKERLOGIC_H__ | 5 | #define __OT_TRACKERLOGIC_H__ |
6 | 6 | ||
7 | #include <sys/types.h> | 7 | #include <sys/types.h> |
8 | #include <sys/time.h> | 8 | #include <sys/time.h> |
@@ -20,16 +20,6 @@ typedef ot_byte ot_hash[20]; | |||
20 | typedef ot_dword ot_ip; | 20 | typedef ot_dword ot_ip; |
21 | typedef time_t ot_time; | 21 | typedef time_t ot_time; |
22 | 22 | ||
23 | #define OT_VECTOR_MIN_MEMBERS 4 | ||
24 | #define OT_VECTOR_GROW_RATIO 8 | ||
25 | #define OT_VECTOR_SHRINK_THRESH 6 | ||
26 | #define OT_VECTOR_SHRINK_RATIO 4 | ||
27 | typedef struct { | ||
28 | void *data; | ||
29 | size_t size; | ||
30 | size_t space; | ||
31 | } ot_vector; | ||
32 | |||
33 | /* Some tracker behaviour tunable */ | 23 | /* Some tracker behaviour tunable */ |
34 | #define OT_CLIENT_TIMEOUT 30 | 24 | #define OT_CLIENT_TIMEOUT 30 |
35 | #define OT_CLIENT_TIMEOUT_CHECKINTERVAL 10 | 25 | #define OT_CLIENT_TIMEOUT_CHECKINTERVAL 10 |
@@ -42,6 +32,10 @@ typedef struct { | |||
42 | 32 | ||
43 | #define OT_CLIENT_REQUEST_INTERVAL_RANDOM ( OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION/2 + (int)( random( ) % OT_CLIENT_REQUEST_VARIATION ) ) | 33 | #define OT_CLIENT_REQUEST_INTERVAL_RANDOM ( OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION/2 + (int)( random( ) % OT_CLIENT_REQUEST_VARIATION ) ) |
44 | 34 | ||
35 | /* We maintain a list of 1024 pointers to sorted list of ot_torrent structs | ||
36 | Sort key is, of course, its hash */ | ||
37 | #define OT_BUCKET_COUNT 1024 | ||
38 | |||
45 | /* Number of tracker admin ip addresses allowed */ | 39 | /* Number of tracker admin ip addresses allowed */ |
46 | #define OT_ADMINIP_MAX 64 | 40 | #define OT_ADMINIP_MAX 64 |
47 | #define OT_MAX_THREADS 16 | 41 | #define OT_MAX_THREADS 16 |
@@ -70,7 +64,16 @@ static const ot_byte PEER_FLAG_STOPPED = 0x20; | |||
70 | #define OT_PEER_COMPARE_SIZE ((size_t)6) | 64 | #define OT_PEER_COMPARE_SIZE ((size_t)6) |
71 | #define OT_HASH_COMPARE_SIZE (sizeof(ot_hash)) | 65 | #define OT_HASH_COMPARE_SIZE (sizeof(ot_hash)) |
72 | 66 | ||
67 | struct ot_peerlist; | ||
68 | typedef struct ot_peerlist ot_peerlist; | ||
73 | typedef struct { | 69 | typedef struct { |
70 | ot_hash hash; | ||
71 | ot_peerlist *peer_list; | ||
72 | } ot_torrent; | ||
73 | |||
74 | #include "ot_vector.h" | ||
75 | |||
76 | struct ot_peerlist { | ||
74 | ot_time base; | 77 | ot_time base; |
75 | size_t seed_count; | 78 | size_t seed_count; |
76 | size_t peer_count; | 79 | size_t peer_count; |
@@ -80,12 +83,7 @@ typedef struct { | |||
80 | #ifdef WANT_TRACKER_SYNC | 83 | #ifdef WANT_TRACKER_SYNC |
81 | ot_vector changeset; | 84 | ot_vector changeset; |
82 | #endif | 85 | #endif |
83 | } ot_peerlist; | 86 | }; |
84 | |||
85 | typedef struct { | ||
86 | ot_hash hash; | ||
87 | ot_peerlist *peer_list; | ||
88 | } ot_torrent; | ||
89 | 87 | ||
90 | /* | 88 | /* |
91 | Exported functions | 89 | Exported functions |
@@ -100,27 +98,21 @@ typedef struct { | |||
100 | int trackerlogic_init( const char * const serverdir ); | 98 | int trackerlogic_init( const char * const serverdir ); |
101 | void trackerlogic_deinit( void ); | 99 | void trackerlogic_deinit( void ); |
102 | 100 | ||
103 | enum { STATS_CONNS, STATS_PEERS, STATS_TOP5, STATS_DMEM, STATS_TCP, STATS_UDP, STATS_SLASH24S, SYNC_IN, SYNC_OUT, STATS_FULLSCRAPE }; | ||
104 | |||
105 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC_PARAM( int from_changeset ) ); | 101 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC_PARAM( int from_changeset ) ); |
106 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ); | 102 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ); |
107 | size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int is_tcp ); | 103 | size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int is_tcp ); |
108 | size_t return_fullscrape_for_tracker( char **reply ); | 104 | size_t return_fullscrape_for_tracker( char **reply ); |
109 | size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply ); | 105 | size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply ); |
110 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ); | 106 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ); |
111 | size_t return_stats_for_tracker( char *reply, int mode ); | ||
112 | size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh ); | ||
113 | size_t return_memstat_for_tracker( char **reply ); | ||
114 | void clean_all_torrents( void ); | 107 | void clean_all_torrents( void ); |
115 | 108 | ||
116 | #ifdef WANT_TRACKER_SYNC | ||
117 | size_t return_changeset_for_tracker( char **reply ); | ||
118 | int add_changeset_to_tracker( ot_byte *data, size_t len ); | ||
119 | #endif | ||
120 | |||
121 | #if defined ( WANT_BLACKLISTING ) || defined ( WANT_CLOSED_TRACKER ) | 109 | #if defined ( WANT_BLACKLISTING ) || defined ( WANT_CLOSED_TRACKER ) |
122 | int accesslist_addentry( ot_hash *hash ); | 110 | int accesslist_addentry( ot_hash *hash ); |
123 | void accesslist_reset( void ); | 111 | void accesslist_reset( void ); |
124 | #endif | 112 | #endif |
125 | 113 | ||
114 | /* Helper, before it moves to its own object */ | ||
115 | void fix_mmapallocation( void *buf, size_t old_alloc, size_t new_alloc ); | ||
116 | void free_peerlist( ot_peerlist *peer_list ); | ||
117 | |||
126 | #endif | 118 | #endif |