diff options
-rw-r--r-- | trackerlogic.c | 177 |
1 files changed, 85 insertions, 92 deletions
diff --git a/trackerlogic.c b/trackerlogic.c index 4587300..a19f9d4 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
@@ -1,6 +1,5 @@ | |||
1 | // THIS REALLY BELONGS INTO A HEADER FILE | 1 | #include "trackerlogic.h" |
2 | // | 2 | |
3 | // | ||
4 | #include <stdlib.h> | 3 | #include <stdlib.h> |
5 | #include <string.h> | 4 | #include <string.h> |
6 | #include <stdio.h> | 5 | #include <stdio.h> |
@@ -9,77 +8,51 @@ | |||
9 | #include <sys/mman.h> | 8 | #include <sys/mman.h> |
10 | #include <unistd.h> | 9 | #include <unistd.h> |
11 | #include <time.h> | 10 | #include <time.h> |
11 | #include <glob.h> | ||
12 | 12 | ||
13 | /* Should be called BYTE, WORD, DWORD - but some OSs already have that and there's no #iftypedef */ | 13 | // Helper functions for binary_find |
14 | /* They mark memory used as data instead of integer or human readable string - | ||
15 | they should be cast before used as integer/text */ | ||
16 | typedef unsigned char ot_byte; | ||
17 | typedef unsigned short ot_word; | ||
18 | typedef unsigned long ot_dword; | ||
19 | |||
20 | typedef unsigned long ot_time; | ||
21 | typedef ot_byte ot_hash[20]; | ||
22 | typedef ot_byte ot_ip[ 4/*0*/ ]; | ||
23 | // tunables | ||
24 | const unsigned long OT_TIMEOUT = 2700; | ||
25 | const unsigned long OT_HUGE_FILESIZE = 1024*1024*256; // Thats 256MB per file, enough for 204800 peers of 128 bytes | ||
26 | |||
27 | #define OT_COMPACT_ONLY | ||
28 | |||
29 | #define MEMMOVE memmove | ||
30 | #define BZERO bzero | ||
31 | #define FORMAT_FIXED_STRING sprintf | ||
32 | #define FORMAT_FORMAT_STRING sprintf | ||
33 | #define BINARY_FIND binary_search | ||
34 | #define NOW time(NULL) | ||
35 | |||
36 | typedef struct ot_peer { | ||
37 | #ifndef OT_COMPACT_ONLY | ||
38 | ot_hash id; | ||
39 | ot_hash key; | ||
40 | #endif | ||
41 | ot_ip ip; | ||
42 | ot_word port; | ||
43 | ot_time death; | ||
44 | ot_byte flags; | ||
45 | } *ot_peer; | ||
46 | ot_byte PEER_FLAG_SEEDING = 0x80; | ||
47 | ot_byte PEER_IP_LENGTH_MASK = 0x3f; | ||
48 | |||
49 | typedef struct { | ||
50 | ot_hash hash; | ||
51 | ot_peer peer_list; | ||
52 | unsigned long peer_count; | ||
53 | unsigned long seed_count; | ||
54 | } *ot_torrent; | ||
55 | |||
56 | void *map_file( char *file_name ); | ||
57 | void unmap_file( char *file_name, void *map, unsigned long real_size ); | ||
58 | |||
59 | // This behaves quite like bsearch but allows to find | ||
60 | // the insertion point for inserts after unsuccessful searches | ||
61 | // in this case exactmatch is 0 on exit | ||
62 | // | 14 | // |
15 | int compare_hash( const void *hash1, const void *hash2 ) { return memcmp( hash1, hash2, sizeof( ot_hash )); } | ||
16 | int compare_ip_port( const void *peer1, const void *peer2 ) { return memcmp( &((ot_peer)peer1)->ip, &((ot_peer)peer2)->ip, 6); } | ||
17 | |||
63 | void *binary_search( const void *key, const void *base, | 18 | void *binary_search( const void *key, const void *base, |
64 | const unsigned long member_count, const unsigned long member_size, | 19 | unsigned long member_count, const unsigned long member_size, |
65 | int (*compar) (const void *, const void *), | 20 | int (*compar) (const void *, const void *), |
66 | int *exactmatch ); | 21 | int *exactmatch ) { |
22 | ot_byte *lookat = ((ot_byte*)base) + member_size * (member_count >> 1); | ||
23 | *exactmatch = 1; | ||
67 | 24 | ||
68 | int compare_hash( const void *hash1, const void *hash2 ) { return memcmp( hash1, hash2, sizeof( ot_hash )); } | 25 | while( member_count ) { |
69 | int compare_ip_port( const void *peer1, const void *peer2 ) { return memcmp( peer1, peer2, 6); } | 26 | int cmp = compar((void*)lookat, key); |
27 | if (cmp == 0) return (void *)lookat; | ||
28 | if (cmp < 0) { | ||
29 | base = (void*)(lookat + member_size); | ||
30 | --member_count; | ||
31 | } | ||
32 | member_count >>= 1; | ||
33 | lookat = ((ot_byte*)base) + member_size * (member_count >> 1); | ||
34 | } | ||
35 | *exactmatch = 0; | ||
36 | return (void*)lookat; | ||
70 | 37 | ||
38 | } | ||
39 | |||
40 | // Converter function from memory to human readable hex strings | ||
41 | // * definitely not thread safe!!! | ||
71 | // | 42 | // |
72 | // | 43 | char ths[1+2*20];char *to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+40;char*t=ths;while(t<e){*t++=m[*s>>4];*t++=m[*s++&15];}*t=0;return ths;} |
73 | // END OF STUFF THAT BELONGS INTO A HEADER FILE | ||
74 | 44 | ||
45 | // GLOBAL VARIABLES | ||
46 | // | ||
75 | unsigned long torrents_count = 0; | 47 | unsigned long torrents_count = 0; |
76 | ot_torrent torrents_list = 0; | 48 | ot_torrent torrents_list = 0; |
77 | ot_byte *scratch_space = 0; | 49 | ot_byte *scratch_space = 0; |
78 | 50 | ||
79 | // Converter function from memory to human readable hex strings | 51 | #define SETINVALID( i ) (scratch_space[index] = 3); |
80 | // * definitely not thread safe!!! | 52 | #define SETSELECTED( i ) (scratch_space[index] = 1); |
81 | // | 53 | #define TESTSELECTED( i ) (scratch_space[index] == 1 ) |
82 | char ths[1+2*20];char *to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+40;char*t=ths;while(t<e){*t++=m[*s>>4];*t++=m[*s++&15];}*t=0;return ths;} | 54 | #define TESTSET( i ) (scratch_space[index]) |
55 | #define RANDOM random() | ||
83 | 56 | ||
84 | ot_torrent add_peer_to_torrent( ot_hash hash, ot_peer peer ) { | 57 | ot_torrent add_peer_to_torrent( ot_hash hash, ot_peer peer ) { |
85 | ot_torrent torrent; | 58 | ot_torrent torrent; |
@@ -122,12 +95,6 @@ ot_torrent add_peer_to_torrent( ot_hash hash, ot_peer peer ) { | |||
122 | return torrent; | 95 | return torrent; |
123 | } | 96 | } |
124 | 97 | ||
125 | #define SETINVALID( i ) (scratch_space[index] = 3); | ||
126 | #define SETSELECTED( i ) (scratch_space[index] = 1); | ||
127 | #define TESTSELECTED( i ) (scratch_space[index] == 1 ) | ||
128 | #define TESTSET( i ) (scratch_space[index]) | ||
129 | #define RANDOM random() | ||
130 | |||
131 | inline int TESTVALIDPEER( ot_peer p ) { return p->death > NOW; } | 98 | inline int TESTVALIDPEER( ot_peer p ) { return p->death > NOW; } |
132 | 99 | ||
133 | // Compiles a list of random peers for a torrent | 100 | // Compiles a list of random peers for a torrent |
@@ -249,30 +216,8 @@ void dispose_torrent( ot_torrent torrent ) { | |||
249 | torrents_count--; | 216 | torrents_count--; |
250 | } | 217 | } |
251 | 218 | ||
252 | void *binary_search( const void *key, const void *base, | ||
253 | unsigned long member_count, const unsigned long member_size, | ||
254 | int (*compar) (const void *, const void *), | ||
255 | int *exactmatch ) { | ||
256 | ot_byte *lookat = ((ot_byte*)base) + member_size * (member_count >> 1); | ||
257 | *exactmatch = 1; | ||
258 | |||
259 | while( member_count ) { | ||
260 | int cmp = compar((void*)lookat, key); | ||
261 | if (cmp == 0) return (void *)lookat; | ||
262 | if (cmp < 0) { | ||
263 | base = (void*)(lookat + member_size); | ||
264 | --member_count; | ||
265 | } | ||
266 | member_count >>= 1; | ||
267 | lookat = ((ot_byte*)base) + member_size * (member_count >> 1); | ||
268 | } | ||
269 | *exactmatch = 0; | ||
270 | return (void*)lookat; | ||
271 | |||
272 | } | ||
273 | |||
274 | // This function maps a "huge" file into process space | 219 | // This function maps a "huge" file into process space |
275 | // * no name will aqcuire anonymous growable memory | 220 | // * giving no name will aqcuire anonymous growable memory |
276 | // * memory will not be "freed" from systems vm if once used, until unmap_file | 221 | // * memory will not be "freed" from systems vm if once used, until unmap_file |
277 | // * I guess, we should be checking for more errors... | 222 | // * I guess, we should be checking for more errors... |
278 | // | 223 | // |
@@ -281,6 +226,8 @@ void *map_file( char *file_name ) { | |||
281 | if( file_name ) { | 226 | if( file_name ) { |
282 | int file_desc=open(file_name,O_RDWR|O_CREAT|O_NDELAY,0644); | 227 | int file_desc=open(file_name,O_RDWR|O_CREAT|O_NDELAY,0644); |
283 | if( file_desc < 0) return 0; | 228 | if( file_desc < 0) return 0; |
229 | lseek( file_desc, OT_HUGE_FILESIZE, SEEK_SET ); | ||
230 | |||
284 | map=mmap(0,OT_HUGE_FILESIZE,PROT_READ|PROT_WRITE,MAP_SHARED,file_desc,0); | 231 | map=mmap(0,OT_HUGE_FILESIZE,PROT_READ|PROT_WRITE,MAP_SHARED,file_desc,0); |
285 | close(file_desc); | 232 | close(file_desc); |
286 | } else | 233 | } else |
@@ -295,14 +242,60 @@ void unmap_file( char *file_name, void *map, unsigned long real_size ) { | |||
295 | truncate( file_name, real_size ); | 242 | truncate( file_name, real_size ); |
296 | } | 243 | } |
297 | 244 | ||
245 | void count_peers_and_seeds( ot_peer peer_list, unsigned long *peers, unsigned long *seeds ) { | ||
246 | *peers = *seeds = 0; | ||
247 | if( peer_list[*peers].ip ) | ||
248 | do { | ||
249 | *seeds += peer_list[*peers++].flags & PEER_FLAG_SEEDING ? 1 : 0; | ||
250 | } while( compare_ip_port( peer_list + *peers, peer_list + *peers - 1 ) < 0 ); | ||
251 | } | ||
252 | |||
298 | int init_logic( ) { | 253 | int init_logic( ) { |
254 | glob_t globber; | ||
255 | int i; | ||
256 | |||
299 | scratch_space = map_file( "" ); | 257 | scratch_space = map_file( "" ); |
300 | torrents_list = map_file( "" ); | 258 | torrents_list = map_file( "" ); |
301 | torrents_count = 0; | 259 | torrents_count = 0; |
302 | 260 | ||
261 | if( !scratch_space || !torrents_list ) { | ||
262 | if( scratch_space || torrents_list ) | ||
263 | unmap_file( "", scratch_space ? (void*)scratch_space : (void*)torrents_list, 0 ); | ||
264 | return -1; | ||
265 | } | ||
266 | |||
303 | // Scan directory for filenames in the form [0-9A-F]{20} | 267 | // Scan directory for filenames in the form [0-9A-F]{20} |
304 | // ... | 268 | // * I know this looks ugly, but I've seen A-F to match umlauts as well in strange locales |
269 | // * lower case for .. better being safe than sorry, this is not expansive here :) | ||
270 | if( !glob( | ||
271 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
272 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
273 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
274 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
275 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
276 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
277 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
278 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
279 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
280 | "[0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef][0-9ABCDEFabcdef]" | ||
281 | , GLOB_NOCHECK, 0, &globber) ) | ||
282 | { | ||
283 | for( i=0; i<globber.gl_matchc; ++i ) { | ||
284 | #ifdef _DEBUG | ||
285 | printf( "Found dir: %s\n", globber.gl_pathv[i] ); | ||
286 | #endif | ||
287 | |||
288 | if( ( torrents_list[torrents_count].peer_list = map_file( globber.gl_pathv[i] ) ) ) { | ||
289 | MEMMOVE( &torrents_list[torrents_count].hash, globber.gl_pathv[i], sizeof( ot_hash ) ); | ||
290 | count_peers_and_seeds( torrents_list[torrents_count].peer_list, | ||
291 | &torrents_list[torrents_count].peer_count, | ||
292 | &torrents_list[torrents_count].seed_count ); | ||
293 | torrents_count++; | ||
294 | } | ||
295 | } | ||
296 | } | ||
305 | 297 | ||
298 | globfree( &globber ); | ||
306 | return 0; | 299 | return 0; |
307 | } | 300 | } |
308 | 301 | ||