summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--opentracker.c12
-rw-r--r--opentracker.conf.sample37
-rw-r--r--ot_accesslist.c281
-rw-r--r--ot_accesslist.h15
-rw-r--r--ot_clean.c4
-rw-r--r--ot_mutex.h6
-rw-r--r--ot_stats.c28
-rw-r--r--ot_stats.h6
-rw-r--r--trackerlogic.h5
10 files changed, 334 insertions, 61 deletions
diff --git a/Makefile b/Makefile
index 949e63e..e3301a5 100644
--- a/Makefile
+++ b/Makefile
@@ -24,6 +24,7 @@ STRIP?=strip
24 24
25#FEATURES+=-DWANT_ACCESSLIST_BLACK 25#FEATURES+=-DWANT_ACCESSLIST_BLACK
26#FEATURES+=-DWANT_ACCESSLIST_WHITE 26#FEATURES+=-DWANT_ACCESSLIST_WHITE
27#FEATURES+=-DWANT_DYNAMIC_ACCESSLIST
27 28
28#FEATURES+=-DWANT_SYNC_LIVE 29#FEATURES+=-DWANT_SYNC_LIVE
29#FEATURES+=-DWANT_IP_FROM_QUERY_STRING 30#FEATURES+=-DWANT_IP_FROM_QUERY_STRING
diff --git a/opentracker.c b/opentracker.c
index be169be..2ca9e06 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -135,8 +135,8 @@ static void help( char *name ) {
135} 135}
136#undef HELPLINE 136#undef HELPLINE
137 137
138static size_t header_complete( char * request, ssize_t byte_count ) { 138static ssize_t header_complete( char * request, ssize_t byte_count ) {
139 int i = 0, state = 0; 139 ssize_t i = 0, state = 0;
140 140
141 for( i=1; i < byte_count; i+=2 ) 141 for( i=1; i < byte_count; i+=2 )
142 if( request[i] <= 13 ) { 142 if( request[i] <= 13 ) {
@@ -187,7 +187,7 @@ static void handle_read( const int64 sock, struct ot_workstruct *ws ) {
187 ws->request_size = byte_count; 187 ws->request_size = byte_count;
188 http_handle_request( sock, ws ); 188 http_handle_request( sock, ws );
189 } else 189 } else
190 array_catb( &cookie->request, ws->inbuf, byte_count ); 190 array_catb( &cookie->request, ws->inbuf, (size_t)byte_count );
191 return; 191 return;
192 } 192 }
193 193
@@ -466,6 +466,12 @@ int parse_configfile( char * config_filename ) {
466 } else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) { 466 } else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) {
467 set_config_option( &g_accesslist_filename, p+17 ); 467 set_config_option( &g_accesslist_filename, p+17 );
468#endif 468#endif
469#ifdef WANT_DYNAMIC_ACCESSLIST
470 } else if(!byte_diff(p, 15, "access.fifo_add" ) && isspace(p[15])) {
471 set_config_option( &g_accesslist_pipe_add, p+16 );
472 } else if(!byte_diff(p, 18, "access.fifo_delete" ) && isspace(p[18])) {
473 set_config_option( &g_accesslist_pipe_delete, p+19 );
474#endif
469#ifdef WANT_RESTRICT_STATS 475#ifdef WANT_RESTRICT_STATS
470 } else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) { 476 } else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) {
471 if( !scan_ip6( p+13, tmpip )) goto parse_error; 477 if( !scan_ip6( p+13, tmpip )) goto parse_error;
diff --git a/opentracker.conf.sample b/opentracker.conf.sample
index db45122..55c2828 100644
--- a/opentracker.conf.sample
+++ b/opentracker.conf.sample
@@ -44,6 +44,43 @@
44# listing, so choose one of those options at compile time. File format 44# listing, so choose one of those options at compile time. File format
45# is straight forward: "<hex info hash>\n<hex info hash>\n..." 45# is straight forward: "<hex info hash>\n<hex info hash>\n..."
46# 46#
47# IIa) You can enable dynamic changesets to accesslists by enabling
48# WANT_DYNAMIC_ACCESSLIST.
49#
50# The suggested way to work with dynamic changeset lists is to keep a
51# main accesslist file that is loaded when opentracker (re)starts and
52# reloaded infrequently (hourly or daily).
53#
54# All changes to the accesslist (e.g. from a web frontend) should be
55# both appended to or removed from that file and sent to opentracker. By
56# keeping dynamic changeset lists, you can avoid reloading huge
57# accesslists whenever just a single entry is added or removed.
58#
59# Any info_hash (format see above) written to the fifo_add file will be
60# kept on a dynamic add-changeset, removed from the dynamic
61# delete-changeset and treated as if it was in the main accesslist file.
62# The semantic of the respective dynamic changeset depends on whether
63# WANT_ACCESSLIST_WHITE or WANT_ACCESSLIST_BLACK is enabled.
64#
65# access.fifo_add /var/run/opentracker/adder.fifo
66#
67# Any info_hash (format see above) written to the fifo_delete file will
68# be kept on a dynamic delete-changeset, removed from the dynamic
69# add-changeset and treated as if it was not in the main accesslist
70# file.
71#
72# access.fifo_delete /var/run/opentracker/deleter.fifo
73#
74# If you reload the accesslist by sending SIGHUP to the tracker process,
75# the dynamic lists are flushed, as opentracker assumes thoses lists are
76# merged into the main accesslist.
77#
78# NOTE: While you can have multiple writers sending lines to the fifos,
79# any writes larger than PIPE_BUF (see your limits.h, minimally 512
80# bytes but usually 4096) may be interleaved with data sent by other
81# writers. This can lead to unparsable lines of info_hashes.
82#
83# IIb)
47# If you do not want to grant anyone access to your stats, enable the 84# If you do not want to grant anyone access to your stats, enable the
48# WANT_RESTRICT_STATS option in Makefile and bless the ip addresses 85# WANT_RESTRICT_STATS option in Makefile and bless the ip addresses
49# allowed to fetch stats here. 86# allowed to fetch stats here.
diff --git a/ot_accesslist.c b/ot_accesslist.c
index a3a2049..7df503f 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -10,6 +10,11 @@
10#include <stdio.h> 10#include <stdio.h>
11#include <signal.h> 11#include <signal.h>
12#include <unistd.h> 12#include <unistd.h>
13#ifdef WANT_DYNAMIC_ACCESSLIST
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <errno.h>
17#endif
13 18
14/* Libowfat */ 19/* Libowfat */
15#include "byte.h" 20#include "byte.h"
@@ -24,23 +29,80 @@
24 29
25/* GLOBAL VARIABLES */ 30/* GLOBAL VARIABLES */
26#ifdef WANT_ACCESSLIST 31#ifdef WANT_ACCESSLIST
27 char *g_accesslist_filename; 32char *g_accesslist_filename = NULL;
33#ifdef WANT_DYNAMIC_ACCESSLIST
34char *g_accesslist_pipe_add = NULL;
35char *g_accesslist_pipe_delete = NULL;
36#endif
28static pthread_mutex_t g_accesslist_mutex; 37static pthread_mutex_t g_accesslist_mutex;
29 38
30typedef struct { 39/* Accesslists are lock free linked lists. We can not make them locking, because every announce
31 ot_hash *list; 40 would try to acquire the mutex, making it the most contested mutex in the whole of opentracker,
32 size_t size; 41 basically creating a central performance choke point.
33} ot_accesslist; 42
34ot_accesslist * g_accesslist = NULL; 43 The idea is that updating the list heads happens under the g_accesslist_mutex guard and is
35ot_accesslist * g_accesslist_old = NULL; 44 done atomically, while consumers might potentially still hold pointers deeper inside the list.
45
46 Consumers (for now only via accesslist_hashisvalid) will always fetch the list head pointer
47 that is guaranteed to live for at least five minutes. This should be many orders of magnitudes
48 more than how long it will be needed by the bsearch done on the list. */
49struct ot_accesslist;
50typedef struct ot_accesslist ot_accesslist;
51struct ot_accesslist {
52 ot_hash *list;
53 size_t size;
54 ot_time base;
55 ot_accesslist *next;
56};
57static ot_accesslist * _Atomic g_accesslist = NULL;
58#ifdef WANT_DYNAMIC_ACCESSLIST
59static ot_accesslist * _Atomic g_accesslist_add = NULL;
60static ot_accesslist * _Atomic g_accesslist_delete = NULL;
61#endif
36 62
63/* Helpers to work on access lists */
37static int vector_compare_hash(const void *hash1, const void *hash2 ) { 64static int vector_compare_hash(const void *hash1, const void *hash2 ) {
38 return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE ); 65 return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE );
39} 66}
40 67
68static ot_accesslist * accesslist_free(ot_accesslist *accesslist) {
69 while (accesslist) {
70 ot_accesslist * this_accesslist = accesslist;
71 accesslist = this_accesslist->next;
72 free(this_accesslist->list);
73 free(this_accesslist);
74 }
75 return NULL;
76}
77
78static ot_accesslist * accesslist_make(ot_accesslist *next, size_t size) {
79 ot_accesslist * accesslist_new = malloc(sizeof(ot_accesslist));
80 if (accesslist_new) {
81 accesslist_new->list = size ? malloc(sizeof(ot_hash) * size) : NULL;
82 accesslist_new->size = size;
83 accesslist_new->base = g_now_minutes;
84 accesslist_new->next = next;
85 if (size && !accesslist_new->list) {
86 free(accesslist_new);
87 accesslist_new = NULL;
88 }
89 }
90 return accesslist_new;
91}
92
93/* This must be called with g_accesslist_mutex held.
94 This will never delete head, because that might still be in use. */
95static void accesslist_clean(ot_accesslist *accesslist) {
96 while (accesslist && accesslist->next) {
97 if (accesslist->next->base + 5 < g_now_minutes)
98 accesslist->next = accesslist_free(accesslist->next);
99 accesslist = accesslist->next;
100 }
101}
102
41/* Read initial access list */ 103/* Read initial access list */
42static void accesslist_readfile( void ) { 104static void accesslist_readfile( void ) {
43 ot_accesslist * accesslist_new = malloc(sizeof(ot_accesslist)); 105 ot_accesslist * accesslist_new;
44 ot_hash *info_hash; 106 ot_hash *info_hash;
45 const char *map, *map_end, *read_offs; 107 const char *map, *map_end, *read_offs;
46 size_t maplen; 108 size_t maplen;
@@ -54,14 +116,13 @@ static void accesslist_readfile( void ) {
54 116
55 /* You need at least 41 bytes to pass an info_hash, make enough room 117 /* You need at least 41 bytes to pass an info_hash, make enough room
56 for the maximum amount of them */ 118 for the maximum amount of them */
57 accesslist_new->size = 0; 119 accesslist_new = accesslist_make(g_accesslist, maplen / 41);
58 info_hash = accesslist_new->list = malloc( ( maplen / 41 ) * 20 ); 120 if( !accesslist_new ) {
59 if( !accesslist_new->list ) {
60 fprintf( stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", ( maplen / 41 ) * 20 ); 121 fprintf( stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", ( maplen / 41 ) * 20 );
61 mmap_unmap( map, maplen); 122 mmap_unmap( map, maplen);
62 free(accesslist_new);
63 return; 123 return;
64 } 124 }
125 info_hash = accesslist_new->list;
65 126
66 /* No use to scan if there's not enough room for another full info_hash */ 127 /* No use to scan if there's not enough room for another full info_hash */
67 map_end = map + maplen - 40; 128 map_end = map + maplen - 40;
@@ -71,18 +132,18 @@ static void accesslist_readfile( void ) {
71 while( read_offs <= map_end ) { 132 while( read_offs <= map_end ) {
72 int i; 133 int i;
73 for( i=0; i<(int)sizeof(ot_hash); ++i ) { 134 for( i=0; i<(int)sizeof(ot_hash); ++i ) {
74 int eger1 = scan_fromhex( read_offs[ 2*i ] ); 135 int eger1 = scan_fromhex( (unsigned char)read_offs[ 2*i ] );
75 int eger2 = scan_fromhex( read_offs[ 1 + 2*i ] ); 136 int eger2 = scan_fromhex( (unsigned char)read_offs[ 1 + 2*i ] );
76 if( eger1 < 0 || eger2 < 0 ) 137 if( eger1 < 0 || eger2 < 0 )
77 break; 138 break;
78 (*info_hash)[i] = eger1 * 16 + eger2; 139 (*info_hash)[i] = (uint8_t)(eger1 * 16 + eger2);
79 } 140 }
80 141
81 if( i == sizeof(ot_hash) ) { 142 if( i == sizeof(ot_hash) ) {
82 read_offs += 40; 143 read_offs += 40;
83 144
84 /* Append accesslist to accesslist vector */ 145 /* Append accesslist to accesslist vector */
85 if( read_offs == map_end || scan_fromhex( *read_offs ) < 0 ) 146 if( read_offs == map_end || scan_fromhex( (unsigned char)*read_offs ) < 0 )
86 ++info_hash; 147 ++info_hash;
87 } 148 }
88 149
@@ -100,14 +161,19 @@ static void accesslist_readfile( void ) {
100 161
101 /* Now exchange the accesslist vector in the least race condition prone way */ 162 /* Now exchange the accesslist vector in the least race condition prone way */
102 pthread_mutex_lock(&g_accesslist_mutex); 163 pthread_mutex_lock(&g_accesslist_mutex);
164 accesslist_new->next = g_accesslist;
165 g_accesslist = accesslist_new; /* Only now set a new list */
166
167#ifdef WANT_DYNAMIC_ACCESSLIST
168 /* If we have dynamic accesslists, reloading a new one will always void the add/delete lists.
169 Insert empty ones at the list head */
170 if (g_accesslist_add && (accesslist_new = accesslist_make(g_accesslist_add, 0)) != NULL)
171 g_accesslist_add = accesslist_new;
172 if (g_accesslist_delete && (accesslist_new = accesslist_make(g_accesslist_delete, 0)) != NULL)
173 g_accesslist_delete = accesslist_new;
174#endif
103 175
104 if (g_accesslist_old) { 176 accesslist_clean(g_accesslist);
105 free(g_accesslist_old->list);
106 free(g_accesslist_old);
107 }
108
109 g_accesslist_old = g_accesslist; /* Keep a copy for later free */
110 g_accesslist = accesslist_new; /* Only now set a new list */
111 177
112 pthread_mutex_unlock(&g_accesslist_mutex); 178 pthread_mutex_unlock(&g_accesslist_mutex);
113} 179}
@@ -115,11 +181,25 @@ static void accesslist_readfile( void ) {
115int accesslist_hashisvalid( ot_hash hash ) { 181int accesslist_hashisvalid( ot_hash hash ) {
116 /* Get working copy of current access list */ 182 /* Get working copy of current access list */
117 ot_accesslist * accesslist = g_accesslist; 183 ot_accesslist * accesslist = g_accesslist;
118 184#ifdef WANT_DYNAMIC_ACCESSLIST
185 ot_accesslist * accesslist_add, * accesslist_delete;
186#endif
119 void * exactmatch = NULL; 187 void * exactmatch = NULL;
120 188
121 if (accesslist) 189 if (accesslist)
122 exactmatch = bsearch( hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); 190 exactmatch = bsearch( hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash );
191
192#ifdef WANT_DYNAMIC_ACCESSLIST
193 /* If we had no match on the main list, scan the list of dynamically added hashes */
194 accesslist_add = g_accesslist_add;
195 if ((exactmatch == NULL) && accesslist_add)
196 exactmatch = bsearch( hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash );
197
198 /* If we found a matching hash on the main list, scan the list of dynamically deleted hashes */
199 accesslist_delete = g_accesslist_delete;
200 if ((exactmatch != NULL) && accesslist_delete && bsearch( hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ))
201 exactmatch = NULL;
202#endif
123 203
124#ifdef WANT_ACCESSLIST_BLACK 204#ifdef WANT_ACCESSLIST_BLACK
125 return exactmatch == NULL; 205 return exactmatch == NULL;
@@ -138,6 +218,8 @@ static void * accesslist_worker( void * args ) {
138 (void)args; 218 (void)args;
139 219
140 while( 1 ) { 220 while( 1 ) {
221 if (!g_opentracker_running)
222 return NULL;
141 223
142 /* Initial attempt to read accesslist */ 224 /* Initial attempt to read accesslist */
143 accesslist_readfile( ); 225 accesslist_readfile( );
@@ -148,27 +230,156 @@ static void * accesslist_worker( void * args ) {
148 return NULL; 230 return NULL;
149} 231}
150 232
233#ifdef WANT_DYNAMIC_ACCESSLIST
234static pthread_t thread_adder_id, thread_deleter_id;
235static void * accesslist_adddel_worker(char * fifoname, ot_accesslist * _Atomic * adding_to, ot_accesslist * _Atomic * removing_from) {
236 struct stat st;
237
238 if (!stat(fifoname, &st)) {
239 if (!S_ISFIFO(st.st_mode)) {
240 fprintf(stderr, "Error when starting dynamic accesslists: Found Non-FIFO file at %s.\nPlease remove it and restart opentracker.\n", fifoname);
241 return NULL;
242 }
243 } else {
244 int error = mkfifo(fifoname, 0755);
245 if (error && error != EEXIST) {
246 fprintf(stderr, "Error when starting dynamic accesslists: Couldn't create FIFO at %s, error: %s\n", fifoname, strerror(errno));
247 return NULL;
248 }
249 }
250
251 while (g_opentracker_running) {
252 FILE * fifo = fopen(fifoname, "r");
253 char *line = NULL;
254 size_t linecap = 0;
255 ssize_t linelen;
256
257 if (!fifo) {
258 fprintf(stderr, "Error when reading dynamic accesslists: Couldn't open FIFO at %s, error: %s\n", fifoname, strerror(errno));
259 return NULL;
260 }
261
262 while ((linelen = getline(&line, &linecap, fifo)) > 0) {
263 ot_hash info_hash;
264 int i;
265
266 printf("Got line %*s", (int)linelen, line);
267 /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*"
268 If there's not enough characters for an info_hash in the line, skip it. */
269 if (linelen < 41)
270 continue;
271
272 for( i=0; i<(int)sizeof(ot_hash); ++i ) {
273 int eger1 = scan_fromhex( (unsigned char)line[ 2*i ] );
274 int eger2 = scan_fromhex( (unsigned char)line[ 1 + 2*i ] );
275 if( eger1 < 0 || eger2 < 0 )
276 break;
277 ((uint8_t*)info_hash)[i] = (uint8_t)(eger1 * 16 + eger2);
278 }
279printf("parsed info_hash %20s\n", info_hash);
280 if( i != sizeof(ot_hash) )
281 continue;
282
283 /* From now on we modify g_accesslist_add and g_accesslist_delete, so prevent the
284 other worker threads from doing the same */
285 pthread_mutex_lock(&g_accesslist_mutex);
286
287 /* If the info hash is in the removing_from list, create a new head without that entry */
288 if (*removing_from && (*removing_from)->list) {
289 ot_hash * exactmatch = bsearch( info_hash, (*removing_from)->list, (*removing_from)->size, OT_HASH_COMPARE_SIZE, vector_compare_hash );
290 if (exactmatch) {
291 ptrdiff_t off = exactmatch - (*removing_from)->list;
292 ot_accesslist * accesslist_new = accesslist_make(*removing_from, (*removing_from)->size - 1);
293 if (accesslist_new) {
294 memcpy(accesslist_new->list, (*removing_from)->list, sizeof(ot_hash) * off);
295 memcpy(accesslist_new->list + off, (*removing_from)->list + off + 1, (*removing_from)->size - off - 1);
296 *removing_from = accesslist_new;
297 }
298 }
299 }
300
301 /* Simple case: there's no adding_to list yet, create one with one member */
302 if (!*adding_to) {
303 ot_accesslist * accesslist_new = accesslist_make(NULL, 1);
304 if (accesslist_new) {
305 memcpy(accesslist_new->list, info_hash, sizeof(ot_hash));
306 *adding_to = accesslist_new;
307 }
308 } else {
309 int exactmatch = 0;
310 ot_hash * insert_point = binary_search( info_hash, (*adding_to)->list, (*adding_to)->size, OT_HASH_COMPARE_SIZE, sizeof(ot_hash), &exactmatch );
311
312 /* Only if the info hash is not in the adding_to list, create a new head with that entry */
313 if (!exactmatch) {
314 ot_accesslist * accesslist_new = accesslist_make(*adding_to, (*adding_to)->size + 1);
315 ptrdiff_t off = insert_point - (*adding_to)->list;
316 if (accesslist_new) {
317 memcpy(accesslist_new->list, (*adding_to)->list, sizeof(ot_hash) * off);
318 memcpy(accesslist_new->list + off, info_hash, sizeof(info_hash));
319 memcpy(accesslist_new->list + off + 1, (*adding_to)->list + off, (*adding_to)->size - off);
320 *adding_to = accesslist_new;
321 }
322 }
323 }
324
325 pthread_mutex_unlock(&g_accesslist_mutex);
326 }
327
328 fclose(fifo);
329 }
330 return NULL;
331}
332
333static void * accesslist_adder_worker( void * args ) {
334 (void)args;
335 return accesslist_adddel_worker(g_accesslist_pipe_add, &g_accesslist_add, &g_accesslist_delete);
336}
337static void * accesslist_deleter_worker( void * args ) {
338 (void)args;
339 return accesslist_adddel_worker(g_accesslist_pipe_delete, &g_accesslist_delete, &g_accesslist_add);
340}
341#endif
342
151static pthread_t thread_id; 343static pthread_t thread_id;
152void accesslist_init( ) { 344void accesslist_init( ) {
153 pthread_mutex_init(&g_accesslist_mutex, NULL); 345 pthread_mutex_init(&g_accesslist_mutex, NULL);
154 pthread_create( &thread_id, NULL, accesslist_worker, NULL ); 346 pthread_create( &thread_id, NULL, accesslist_worker, NULL );
347#ifdef WANT_DYNAMIC_ACCESSLIST
348 if (g_accesslist_pipe_add)
349 pthread_create( &thread_adder_id, NULL, accesslist_adder_worker, NULL );
350 if (g_accesslist_pipe_delete)
351 pthread_create( &thread_deleter_id, NULL, accesslist_deleter_worker, NULL );
352#endif
155} 353}
156 354
157void accesslist_deinit( void ) { 355void accesslist_deinit( void ) {
356 /* Wake up sleeping worker */
357 pthread_kill(thread_id, SIGHUP);
358
359 pthread_mutex_lock(&g_accesslist_mutex);
360
361 g_accesslist = accesslist_free(g_accesslist);
362
363#ifdef WANT_DYNAMIC_ACCESSLIST
364 g_accesslist_add = accesslist_free(g_accesslist_add);
365 g_accesslist_delete = accesslist_free(g_accesslist_delete);
366#endif
367
368 pthread_mutex_unlock(&g_accesslist_mutex);
158 pthread_cancel( thread_id ); 369 pthread_cancel( thread_id );
159 pthread_mutex_destroy(&g_accesslist_mutex); 370 pthread_mutex_destroy(&g_accesslist_mutex);
371}
160 372
161 if (g_accesslist_old) { 373void accesslist_cleanup( void ) {
162 free(g_accesslist_old->list); 374 pthread_mutex_lock(&g_accesslist_mutex);
163 free(g_accesslist_old);
164 g_accesslist_old = 0;
165 }
166 375
167 if (g_accesslist) { 376 accesslist_clean(g_accesslist);
168 free(g_accesslist->list); 377#if WANT_DYNAMIC_ACCESSLIST
169 free(g_accesslist); 378 accesslist_clean(g_accesslist_add);
170 g_accesslist = 0; 379 accesslist_clean(g_accesslist_delete);
171 } 380#endif
381
382 pthread_mutex_unlock(&g_accesslist_mutex);
172} 383}
173#endif 384#endif
174 385
diff --git a/ot_accesslist.h b/ot_accesslist.h
index b38b91a..281f61b 100644
--- a/ot_accesslist.h
+++ b/ot_accesslist.h
@@ -6,19 +6,28 @@
6#ifndef OT_ACCESSLIST_H__ 6#ifndef OT_ACCESSLIST_H__
7#define OT_ACCESSLIST_H__ 7#define OT_ACCESSLIST_H__
8 8
9#if defined ( WANT_ACCESSLIST_BLACK ) && defined (WANT_ACCESSLIST_WHITE ) 9#if defined ( WANT_ACCESSLIST_BLACK ) && defined ( WANT_ACCESSLIST_WHITE )
10# error WANT_ACCESSLIST_BLACK and WANT_ACCESSLIST_WHITE are exclusive. 10# error WANT_ACCESSLIST_BLACK and WANT_ACCESSLIST_WHITE are exclusive.
11#endif 11#endif
12 12
13#if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE ) 13#if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE )
14#define WANT_ACCESSLIST 14#define WANT_ACCESSLIST
15void accesslist_init( ); 15void accesslist_init( void );
16void accesslist_deinit( ); 16void accesslist_deinit( void );
17int accesslist_hashisvalid( ot_hash hash ); 17int accesslist_hashisvalid( ot_hash hash );
18void accesslist_cleanup( void );
18 19
19extern char *g_accesslist_filename; 20extern char *g_accesslist_filename;
21#ifdef WANT_DYNAMIC_ACCESSLIST
22extern char *g_accesslist_pipe_add;
23extern char *g_accesslist_pipe_delete;
24#endif
20 25
21#else 26#else
27#ifdef WANT_DYNAMIC_ACCESSLIST
28# error WANT_DYNAMIC_ACCESSLIST needs either WANT_ACCESSLIST_BLACK or WANT_ACCESSLIST_WHITE
29#endif
30
22#define accesslist_init( accesslist_filename ) 31#define accesslist_init( accesslist_filename )
23#define accesslist_deinit( ) 32#define accesslist_deinit( )
24#define accesslist_hashisvalid( hash ) 1 33#define accesslist_hashisvalid( hash ) 1
diff --git a/ot_clean.c b/ot_clean.c
index 4c03416..139bedb 100644
--- a/ot_clean.c
+++ b/ot_clean.c
@@ -17,6 +17,7 @@
17#include "ot_vector.h" 17#include "ot_vector.h"
18#include "ot_clean.h" 18#include "ot_clean.h"
19#include "ot_stats.h" 19#include "ot_stats.h"
20#include "ot_accesslist.h"
20 21
21/* Returns amount of removed peers */ 22/* Returns amount of removed peers */
22static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, time_t timedout, int *removed_seeders ) { 23static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, time_t timedout, int *removed_seeders ) {
@@ -123,6 +124,9 @@ static void * clean_worker( void * args ) {
123 usleep( OT_CLEAN_SLEEP ); 124 usleep( OT_CLEAN_SLEEP );
124 } 125 }
125 stats_cleanup(); 126 stats_cleanup();
127#ifdef WANT_ACCESSLIST
128 accesslist_cleanup();
129#endif
126 } 130 }
127 return NULL; 131 return NULL;
128} 132}
diff --git a/ot_mutex.h b/ot_mutex.h
index bd07009..93c1ecf 100644
--- a/ot_mutex.h
+++ b/ot_mutex.h
@@ -8,8 +8,8 @@
8 8
9#include <sys/uio.h> 9#include <sys/uio.h>
10 10
11void mutex_init( ); 11void mutex_init( void );
12void mutex_deinit( ); 12void mutex_deinit( void );
13 13
14ot_vector *mutex_bucket_lock( int bucket ); 14ot_vector *mutex_bucket_lock( int bucket );
15ot_vector *mutex_bucket_lock_by_hash( ot_hash hash ); 15ot_vector *mutex_bucket_lock_by_hash( ot_hash hash );
@@ -17,7 +17,7 @@ ot_vector *mutex_bucket_lock_by_hash( ot_hash hash );
17void mutex_bucket_unlock( int bucket, int delta_torrentcount ); 17void mutex_bucket_unlock( int bucket, int delta_torrentcount );
18void mutex_bucket_unlock_by_hash( ot_hash hash, int delta_torrentcount ); 18void mutex_bucket_unlock_by_hash( ot_hash hash, int delta_torrentcount );
19 19
20size_t mutex_get_torrent_count(); 20size_t mutex_get_torrent_count(void);
21 21
22typedef enum { 22typedef enum {
23 TASK_STATS_CONNS = 0x0001, 23 TASK_STATS_CONNS = 0x0001,
diff --git a/ot_stats.c b/ot_stats.c
index 7fc22de..7d2749f 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -293,7 +293,7 @@ static int torrent_statter( ot_torrent *torrent, uintptr_t data ) {
293/* Converter function from memory to human readable hex strings */ 293/* Converter function from memory to human readable hex strings */
294static char*to_hex(char*d,uint8_t*s){char*m="0123456789ABCDEF";char *t=d;char*e=d+40;while(d<e){*d++=m[*s>>4];*d++=m[*s++&15];}*d=0;return t;} 294static char*to_hex(char*d,uint8_t*s){char*m="0123456789ABCDEF";char *t=d;char*e=d+40;while(d<e){*d++=m[*s>>4];*d++=m[*s++&15];}*d=0;return t;}
295 295
296typedef struct { size_t val; ot_torrent * torrent; } ot_record; 296typedef struct { size_t val; ot_hash hash; } ot_record;
297 297
298/* Fetches stats from tracker */ 298/* Fetches stats from tracker */
299size_t stats_top_txt( char * reply, int amount ) { 299size_t stats_top_txt( char * reply, int amount ) {
@@ -311,18 +311,22 @@ size_t stats_top_txt( char * reply, int amount ) {
311 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 311 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
312 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 312 ot_vector *torrents_list = mutex_bucket_lock( bucket );
313 for( j=0; j<torrents_list->size; ++j ) { 313 for( j=0; j<torrents_list->size; ++j ) {
314 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; 314 ot_torrent *torrent = (ot_torrent*)(torrents_list->data) + j;
315 int idx = amount - 1; while( (idx >= 0) && ( peer_list->peer_count > top100c[idx].val ) ) --idx; 315 idx = amount - 1;
316 while( (idx >= 0) && ( torrent->peer_list->peer_count > top100c[idx].val ) )
317 --idx;
316 if ( idx++ != amount - 1 ) { 318 if ( idx++ != amount - 1 ) {
317 memmove( top100c + idx + 1, top100c + idx, ( amount - 1 - idx ) * sizeof( ot_record ) ); 319 memmove( top100c + idx + 1, top100c + idx, ( amount - 1 - idx ) * sizeof( ot_record ) );
318 top100c[idx].val = peer_list->peer_count; 320 memcpy( &top100c[idx].hash, &torrent->hash, sizeof(ot_hash));
319 top100c[idx].torrent = (ot_torrent*)(torrents_list->data) + j; 321 top100c[idx].val = torrent->peer_list->peer_count;
320 } 322 }
321 idx = amount - 1; while( (idx >= 0) && ( peer_list->seed_count > top100s[idx].val ) ) --idx; 323 idx = amount - 1;
324 while( (idx >= 0) && ( torrent->peer_list->seed_count > top100s[idx].val ) )
325 --idx;
322 if ( idx++ != amount - 1 ) { 326 if ( idx++ != amount - 1 ) {
323 memmove( top100s + idx + 1, top100s + idx, ( amount - 1 - idx ) * sizeof( ot_record ) ); 327 memmove( top100s + idx + 1, top100s + idx, ( amount - 1 - idx ) * sizeof( ot_record ) );
324 top100s[idx].val = peer_list->seed_count; 328 memcpy( &top100s[idx].hash, &torrent->hash, sizeof(ot_hash));
325 top100s[idx].torrent = (ot_torrent*)(torrents_list->data) + j; 329 top100s[idx].val = torrent->peer_list->seed_count;
326 } 330 }
327 } 331 }
328 mutex_bucket_unlock( bucket, 0 ); 332 mutex_bucket_unlock( bucket, 0 );
@@ -332,12 +336,12 @@ size_t stats_top_txt( char * reply, int amount ) {
332 336
333 r += sprintf( r, "Top %d torrents by peers:\n", amount ); 337 r += sprintf( r, "Top %d torrents by peers:\n", amount );
334 for( idx=0; idx<amount; ++idx ) 338 for( idx=0; idx<amount; ++idx )
335 if( top100c[idx].torrent ) 339 if( top100c[idx].val )
336 r += sprintf( r, "\t%zd\t%s\n", top100c[idx].val, to_hex( hex_out, top100c[idx].torrent->hash) ); 340 r += sprintf( r, "\t%zd\t%s\n", top100c[idx].val, to_hex( hex_out, top100c[idx].hash) );
337 r += sprintf( r, "Top %d torrents by seeds:\n", amount ); 341 r += sprintf( r, "Top %d torrents by seeds:\n", amount );
338 for( idx=0; idx<amount; ++idx ) 342 for( idx=0; idx<amount; ++idx )
339 if( top100s[idx].torrent ) 343 if( top100s[idx].val )
340 r += sprintf( r, "\t%zd\t%s\n", top100s[idx].val, to_hex( hex_out, top100s[idx].torrent->hash) ); 344 r += sprintf( r, "\t%zd\t%s\n", top100s[idx].val, to_hex( hex_out, top100s[idx].hash) );
341 345
342 return r - reply; 346 return r - reply;
343} 347}
diff --git a/ot_stats.h b/ot_stats.h
index 6a2515b..ed60f68 100644
--- a/ot_stats.h
+++ b/ot_stats.h
@@ -40,11 +40,11 @@ enum {
40 40
41void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event_data ); 41void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event_data );
42void stats_deliver( int64 sock, int tasktype ); 42void stats_deliver( int64 sock, int tasktype );
43void stats_cleanup(); 43void stats_cleanup( void );
44size_t return_stats_for_tracker( char *reply, int mode, int format ); 44size_t return_stats_for_tracker( char *reply, int mode, int format );
45size_t stats_return_tracker_version( char *reply ); 45size_t stats_return_tracker_version( char *reply );
46void stats_init( ); 46void stats_init( void );
47void stats_deinit( ); 47void stats_deinit( void );
48 48
49extern const char *g_version_rijndael_c; 49extern const char *g_version_rijndael_c;
50extern const char *g_version_livesync_c; 50extern const char *g_version_livesync_c;
diff --git a/trackerlogic.h b/trackerlogic.h
index 87b9138..ef59179 100644
--- a/trackerlogic.h
+++ b/trackerlogic.h
@@ -133,7 +133,6 @@ struct ot_workstruct {
133 char *peer_id; 133 char *peer_id;
134 134
135 /* HTTP specific, non static */ 135 /* HTTP specific, non static */
136 int keep_alive;
137 char *request; 136 char *request;
138 ssize_t request_size; 137 ssize_t request_size;
139 ssize_t header_size; 138 ssize_t header_size;
@@ -143,6 +142,8 @@ struct ot_workstruct {
143 /* Entropy state for rand48 function so that threads don't need to acquire mutexes for 142 /* Entropy state for rand48 function so that threads don't need to acquire mutexes for
144 global random() or arc4random() state, which causes heavy load on linuxes */ 143 global random() or arc4random() state, which causes heavy load on linuxes */
145 uint16_t rand48_state[3]; 144 uint16_t rand48_state[3];
145
146 int keep_alive;
146}; 147};
147 148
148/* 149/*
@@ -163,7 +164,7 @@ struct ot_workstruct {
163#error Live logging networks disabled at the moment. 164#error Live logging networks disabled at the moment.
164#endif 165#endif
165 166
166void trackerlogic_init( ); 167void trackerlogic_init( void );
167void trackerlogic_deinit( void ); 168void trackerlogic_deinit( void );
168void exerr( char * message ); 169void exerr( char * message );
169 170