summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--trackerlogic.c164
1 files changed, 103 insertions, 61 deletions
diff --git a/trackerlogic.c b/trackerlogic.c
index d21fc01..4587300 100644
--- a/trackerlogic.c
+++ b/trackerlogic.c
@@ -1,15 +1,25 @@
1// THIS REALLY BELONGS INTO A HEADER FILE 1// THIS REALLY BELONGS INTO A HEADER FILE
2// 2//
3// 3//
4#include <stdlib.h>
4#include <string.h> 5#include <string.h>
5#include <stdio.h> 6#include <stdio.h>
6#include <fcntl.h> 7#include <fcntl.h>
7#include <sys/types.h> 8#include <sys/types.h>
8#include <sys/mman.h> 9#include <sys/mman.h>
9 10#include <unistd.h>
10typedef unsigned char ot_hash[20]; 11#include <time.h>
11typedef unsigned char ot_ip[ 4/*0*/ ]; 12
12typedef unsigned long ot_time; 13/* Should be called BYTE, WORD, DWORD - but some OSs already have that and there's no #iftypedef */
14/* They mark memory used as data instead of integer or human readable string -
15 they should be cast before used as integer/text */
16typedef unsigned char ot_byte;
17typedef unsigned short ot_word;
18typedef unsigned long ot_dword;
19
20typedef unsigned long ot_time;
21typedef ot_byte ot_hash[20];
22typedef ot_byte ot_ip[ 4/*0*/ ];
13// tunables 23// tunables
14const unsigned long OT_TIMEOUT = 2700; 24const unsigned long OT_TIMEOUT = 2700;
15const unsigned long OT_HUGE_FILESIZE = 1024*1024*256; // Thats 256MB per file, enough for 204800 peers of 128 bytes 25const unsigned long OT_HUGE_FILESIZE = 1024*1024*256; // Thats 256MB per file, enough for 204800 peers of 128 bytes
@@ -21,28 +31,30 @@ const unsigned long OT_HUGE_FILESIZE = 1024*1024*256; // Thats 256MB per file
21#define FORMAT_FIXED_STRING sprintf 31#define FORMAT_FIXED_STRING sprintf
22#define FORMAT_FORMAT_STRING sprintf 32#define FORMAT_FORMAT_STRING sprintf
23#define BINARY_FIND binary_search 33#define BINARY_FIND binary_search
34#define NOW time(NULL)
24 35
25typedef struct { 36typedef struct ot_peer {
26#ifndef OT_COMPACT_ONLY 37#ifndef OT_COMPACT_ONLY
27 ot_hash id; 38 ot_hash id;
28 ot_hash key; 39 ot_hash key;
29#endif 40#endif
30 ot_ip ip; 41 ot_ip ip;
31 unsigned short port; 42 ot_word port;
32 ot_time death; 43 ot_time death;
33 unsigned char flags; 44 ot_byte flags;
34} ot_peer; 45} *ot_peer;
35unsigned char PEER_FLAG_SEEDING = 0x80; 46ot_byte PEER_FLAG_SEEDING = 0x80;
36unsigned char PEER_IP_LENGTH_MASK = 0x3f; 47ot_byte PEER_IP_LENGTH_MASK = 0x3f;
37 48
38typedef struct { 49typedef struct {
39 ot_hash hash; 50 ot_hash hash;
40 ot_peer *peer_list; 51 ot_peer peer_list;
41 unsigned long peer_count; 52 unsigned long peer_count;
42 unsigned long seed_count; 53 unsigned long seed_count;
43} ot_torrent; 54} *ot_torrent;
44 55
45void *map_file( char *file_name ); 56void *map_file( char *file_name );
57void unmap_file( char *file_name, void *map, unsigned long real_size );
46 58
47// This behaves quite like bsearch but allows to find 59// This behaves quite like bsearch but allows to find
48// the insertion point for inserts after unsuccessful searches 60// the insertion point for inserts after unsuccessful searches
@@ -60,28 +72,33 @@ int compare_ip_port( const void *peer1, const void *peer2 ) { return memcmp( pee
60// 72//
61// END OF STUFF THAT BELONGS INTO A HEADER FILE 73// END OF STUFF THAT BELONGS INTO A HEADER FILE
62 74
63ot_torrent *torrents_pointer = 0;
64unsigned long torrents_count = 0; 75unsigned long torrents_count = 0;
65unsigned char *scratchspace; 76ot_torrent torrents_list = 0;
77ot_byte *scratch_space = 0;
78
79// Converter function from memory to human readable hex strings
80// * definitely not thread safe!!!
81//
82char 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;}
66 83
67ot_torrent *add_peer_to_torrent( ot_hash hash, ot_peer *peer ) { 84ot_torrent add_peer_to_torrent( ot_hash hash, ot_peer peer ) {
68 ot_torrent *torrent; 85 ot_torrent torrent;
69 ot_peer *peer_dest; 86 ot_peer peer_dest;
70 int exactmatch; 87 int exactmatch;
71 88
72 torrent = BINARY_FIND( hash, torrents_pointer, torrents_count, sizeof( ot_torrent ), compare_hash, &exactmatch ); 89 torrent = BINARY_FIND( hash, torrents_list, torrents_count, sizeof( *torrent ), compare_hash, &exactmatch );
73 if( !exactmatch ) { 90 if( !exactmatch ) {
74 // Assume, OS will provide us with space, after all, this is file backed 91 // Assume, OS will provide us with space, after all, this is file backed
75 MEMMOVE( torrent + 1, torrent, ( torrents_pointer + torrents_count ) - torrent ); 92 MEMMOVE( torrent + 1, torrent, ( torrents_list + torrents_count ) - torrent );
76 93
77 // Create a new torrent entry, then 94 // Create a new torrent entry, then
78 MEMMOVE( &torrent->hash, hash, sizeof( ot_hash ) ); 95 MEMMOVE( &torrent->hash, hash, sizeof( ot_hash ) );
79 torrent->peer_list = map_file( hash ); 96 torrent->peer_list = map_file( to_hex( hash ) );
80 torrent->peer_count = 0; 97 torrent->peer_count = 0;
81 torrent->seed_count = 0; 98 torrent->seed_count = 0;
82 } 99 }
83 100
84 peer_dest = BINARY_FIND( peer, torrent->peer_list, torrent->peer_count, sizeof( ot_peer ), compare_ip_port, &exactmatch ); 101 peer_dest = BINARY_FIND( peer, torrent->peer_list, torrent->peer_count, sizeof( *peer_dest ), compare_ip_port, &exactmatch );
85 if( exactmatch ) { 102 if( exactmatch ) {
86 // If peer was a seeder but isn't anymore, decrease seeder count 103 // If peer was a seeder but isn't anymore, decrease seeder count
87 if( ( peer_dest->flags & PEER_FLAG_SEEDING ) && !( peer->flags & PEER_FLAG_SEEDING ) ) 104 if( ( peer_dest->flags & PEER_FLAG_SEEDING ) && !( peer->flags & PEER_FLAG_SEEDING ) )
@@ -100,18 +117,18 @@ ot_torrent *add_peer_to_torrent( ot_hash hash, ot_peer *peer ) {
100 } 117 }
101 118
102 // Set new time out time 119 // Set new time out time
103 peer_dest->death = now() + OT_TIMEOUT; 120 peer_dest->death = NOW + OT_TIMEOUT;
104 121
105 return torrent; 122 return torrent;
106} 123}
107 124
108#define SETINVALID( i ) (scratchspace[index] = 3); 125#define SETINVALID( i ) (scratch_space[index] = 3);
109#define SETSELECTED( i ) (scratchspace[index] = 1); 126#define SETSELECTED( i ) (scratch_space[index] = 1);
110#define TESTSELECTED( i ) (scratchspace[index] == 1 ) 127#define TESTSELECTED( i ) (scratch_space[index] == 1 )
111#define TESTSET( i ) (scratchspace[index]) 128#define TESTSET( i ) (scratch_space[index])
112#define RANDOM random() 129#define RANDOM random()
113 130
114inline int TESTVALIDPEER( ot_peer *p ) { return p->death > now(); } 131inline int TESTVALIDPEER( ot_peer p ) { return p->death > NOW; }
115 132
116// Compiles a list of random peers for a torrent 133// Compiles a list of random peers for a torrent
117// * scratch space keeps track of death or already selected peers 134// * scratch space keeps track of death or already selected peers
@@ -122,14 +139,14 @@ inline int TESTVALIDPEER( ot_peer *p ) { return p->death > now(); }
122// * it is not guaranteed to see all peers, so no assumptions on active seeders/peers may be done 139// * it is not guaranteed to see all peers, so no assumptions on active seeders/peers may be done
123// * since compact format cannot handle v6 addresses, it must be enabled by OT_COMPACT_ONLY 140// * since compact format cannot handle v6 addresses, it must be enabled by OT_COMPACT_ONLY
124// 141//
125void return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char *reply ) { 142void return_peers_for_torrent( ot_torrent torrent, unsigned long amount, char *reply ) {
126 register ot_peer *peer_base = torrent->peer_list; 143 register ot_peer peer_base = torrent->peer_list;
127 unsigned long peer_count = torrent->peer_count; 144 unsigned long peer_count = torrent->peer_count;
128 unsigned long selected_count = 0, invalid_count = 0; 145 unsigned long selected_count = 0, invalid_count = 0;
129 unsigned long index = 0; 146 unsigned long index = 0;
130 147
131 // optimize later ;) 148 // optimize later ;)
132 BZERO( scratchspace, peer_count ); 149 BZERO( scratch_space, peer_count );
133 150
134 while( ( selected_count < amount ) && ( selected_count + invalid_count < peer_count ) ) { 151 while( ( selected_count < amount ) && ( selected_count + invalid_count < peer_count ) ) {
135 // skip to first non-flagged peer 152 // skip to first non-flagged peer
@@ -150,11 +167,11 @@ void return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char *
150#ifndef OT_COMPACT_ONLY 167#ifndef OT_COMPACT_ONLY
151 reply += FORMAT_FIXED_STRING( reply, "d5:peersl" ); 168 reply += FORMAT_FIXED_STRING( reply, "d5:peersl" );
152#else 169#else
153 reply += FORMAT_FORMAT_STRING( reply, "d5:peers%i:",6*selected_count ); 170 reply += FORMAT_FORMAT_STRING( reply, "d5:peers%li:",6*selected_count );
154#endif 171#endif
155 172
156 while( selected_count-- ) { 173 while( selected_count-- ) {
157 ot_peer *peer; 174 ot_peer peer;
158 while( !TESTSELECTED( index ) ) ++index; 175 while( !TESTSELECTED( index ) ) ++index;
159 peer = peer_base + index; 176 peer = peer_base + index;
160#ifdef OT_COMPACT_ONLY 177#ifdef OT_COMPACT_ONLY
@@ -181,11 +198,11 @@ void return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char *
181// * is rather expansive 198// * is rather expansive
182// * if this fails, torrent file is invalid, should add flag 199// * if this fails, torrent file is invalid, should add flag
183// 200//
184void heal_torrent( ot_torrent *torrent ) { 201void heal_torrent( ot_torrent torrent ) {
185 unsigned long index = 0, base = 0, end, seed_count = 0; 202 unsigned long index = 0, base = 0, end, seed_count = 0, now = NOW;
186 203
187 // Initialize base to first dead peer. 204 // Initialize base to first dead peer.
188 while( ( base < torrent->peer_count ) && torrent->peer_list[base].death <= now() ) { 205 while( ( base < torrent->peer_count ) && torrent->peer_list[base].death <= now ) {
189 seed_count += ( torrent->peer_list[base].flags & PEER_FLAG_SEEDING ) ? 1 : 0; 206 seed_count += ( torrent->peer_list[base].flags & PEER_FLAG_SEEDING ) ? 1 : 0;
190 base++; 207 base++;
191 } 208 }
@@ -199,7 +216,7 @@ void heal_torrent( ot_torrent *torrent ) {
199 216
200 while( 1 ) { 217 while( 1 ) {
201 // Let index search for next living peer 218 // Let index search for next living peer
202 while( ( index < torrent->peer_count ) && torrent->peer_list[index].death > now() ) index++; 219 while( ( index < torrent->peer_count ) && torrent->peer_list[index].death > now ) index++;
203 220
204 // No further living peers found - base is our new peer count 221 // No further living peers found - base is our new peer count
205 if( index == torrent->peer_count ) { 222 if( index == torrent->peer_count ) {
@@ -211,25 +228,32 @@ void heal_torrent( ot_torrent *torrent ) {
211 end = index + 1; 228 end = index + 1;
212 229
213 // Let end search for next dead peer (end of living peers) 230 // Let end search for next dead peer (end of living peers)
214 while( ( end < torrent->peer_count ) && torrent->peer_list[end].death <= now() ) { 231 while( ( end < torrent->peer_count ) && torrent->peer_list[end].death <= now ) {
215 seed_count += ( torrent->peer_list[end].flags & PEER_FLAG_SEEDING ) ? 1 : 0; 232 seed_count += ( torrent->peer_list[end].flags & PEER_FLAG_SEEDING ) ? 1 : 0;
216 end++; 233 end++;
217 } 234 }
218 235
219 // We either hit a dead peer or the end of our peers 236 // We either hit a dead peer or the end of our peers
220 // In both cases: move block towards base 237 // In both cases: move block towards base
221 MEMMOVE( torrent->peer_list + base, torrent->peer_list + index, ( end - index ) * sizeof( ot_peer ) ); 238 MEMMOVE( torrent->peer_list + base, torrent->peer_list + index, ( end - index ) * sizeof( struct ot_peer ) );
222 base += end - index; 239 base += end - index;
223 240
224 index = end; 241 index = end;
225 } 242 }
226} 243}
227 244
245void dispose_torrent( ot_torrent torrent ) {
246 unmap_file( "", torrent->peer_list, 0 );
247 unlink( to_hex( torrent->hash ) );
248 MEMMOVE( torrent, torrent + 1, ( torrents_list + torrents_count ) - ( torrent + 1 ) );
249 torrents_count--;
250}
251
228void *binary_search( const void *key, const void *base, 252void *binary_search( const void *key, const void *base,
229 unsigned long member_count, const unsigned long member_size, 253 unsigned long member_count, const unsigned long member_size,
230 int (*compar) (const void *, const void *), 254 int (*compar) (const void *, const void *),
231 int *exactmatch ) { 255 int *exactmatch ) {
232 unsigned char *lookat = ((unsigned char*)base) + member_size * (member_count >> 1); 256 ot_byte *lookat = ((ot_byte*)base) + member_size * (member_count >> 1);
233 *exactmatch = 1; 257 *exactmatch = 1;
234 258
235 while( member_count ) { 259 while( member_count ) {
@@ -240,7 +264,7 @@ void *binary_search( const void *key, const void *base,
240 --member_count; 264 --member_count;
241 } 265 }
242 member_count >>= 1; 266 member_count >>= 1;
243 lookat = ((unsigned char*)base) + member_size * (member_count >> 1); 267 lookat = ((ot_byte*)base) + member_size * (member_count >> 1);
244 } 268 }
245 *exactmatch = 0; 269 *exactmatch = 0;
246 return (void*)lookat; 270 return (void*)lookat;
@@ -248,26 +272,44 @@ void *binary_search( const void *key, const void *base,
248} 272}
249 273
250// This function maps a "huge" file into process space 274// This function maps a "huge" file into process space
275// * no name will aqcuire anonymous growable memory
276// * memory will not be "freed" from systems vm if once used, until unmap_file
251// * I guess, we should be checking for more errors... 277// * I guess, we should be checking for more errors...
278//
252void *map_file( char *file_name ) { 279void *map_file( char *file_name ) {
253 char *map; 280 char *map;
254 int file_desc=open(file_name,O_RDWR|O_CREAT|O_NDELAY,0644); 281 if( file_name ) {
255 282 int file_desc=open(file_name,O_RDWR|O_CREAT|O_NDELAY,0644);
256 if( file_desc < 0) return 0; 283 if( file_desc < 0) return 0;
257 284 map=mmap(0,OT_HUGE_FILESIZE,PROT_READ|PROT_WRITE,MAP_SHARED,file_desc,0);
258 map=mmap(0,OT_HUGE_FILESIZE,PROT_READ|PROT_WRITE,MAP_SHARED,file_desc,0); 285 close(file_desc);
259 close(file_desc); 286 } else
287 map=mmap(0,OT_HUGE_FILESIZE,PROT_READ|PROT_WRITE,MAP_ANON,-1,0);
260 288
261 return (map == (char*)-1) ? 0 : map; 289 return (map == (char*)-1) ? 0 : map;
262} 290}
263 291
292void unmap_file( char *file_name, void *map, unsigned long real_size ) {
293 munmap( map, OT_HUGE_FILESIZE );
294 if( file_name)
295 truncate( file_name, real_size );
296}
297
264int init_logic( ) { 298int init_logic( ) {
265 unlink( "./opentracker_map_index.idx" ); 299 scratch_space = map_file( "" );
266 torrents_pointer = map_file( "./opentracker_map_index.idx" ); 300 torrents_list = map_file( "" );
267 torrents_count = 0; 301 torrents_count = 0;
268 scratchspace = map_file( "./scratchspace" ); 302
303 // Scan directory for filenames in the form [0-9A-F]{20}
304 // ...
305
306 return 0;
269} 307}
270 308
271void deinit_logic( ) { 309void deinit_logic( ) {
272 unmap_file( torrents_pointer ); 310 // For all torrents... blablabla
311 while( torrents_count-- )
312 unmap_file( to_hex(torrents_list[torrents_count].hash), torrents_list[torrents_count].peer_list, torrents_list[torrents_count].peer_count * sizeof(struct ot_peer) );
313 unmap_file( "", torrents_list, 0 );
314 unmap_file( "", scratch_space, 0 );
273} 315}