@ -1,15 +1,25 @@
// THIS REALLY BELONGS INTO A HEADER FILE
// THIS REALLY BELONGS INTO A HEADER FILE
//
//
//
//
# include <stdlib.h>
# include <string.h>
# include <string.h>
# include <stdio.h>
# include <stdio.h>
# include <fcntl.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/types.h>
# include <sys/mman.h>
# include <sys/mman.h>
# include <unistd.h>
typedef unsigned char ot_hash [ 20 ] ;
# include <time.h>
typedef unsigned char ot_ip [ 4 /*0*/ ] ;
typedef unsigned long ot_time ;
/* Should be called BYTE, WORD, DWORD - but some OSs already have that and there's no #iftypedef */
/* They mark memory used as data instead of integer or human readable string -
they should be cast before used as integer / text */
typedef unsigned char ot_byte ;
typedef unsigned short ot_word ;
typedef unsigned long ot_dword ;
typedef unsigned long ot_time ;
typedef ot_byte ot_hash [ 20 ] ;
typedef ot_byte ot_ip [ 4 /*0*/ ] ;
// tunables
// tunables
const unsigned long OT_TIMEOUT = 2700 ;
const unsigned long OT_TIMEOUT = 2700 ;
const unsigned long OT_HUGE_FILESIZE = 1024 * 1024 * 256 ; // Thats 256MB per file, enough for 204800 peers of 128 bytes
const 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
# define FORMAT_FIXED_STRING sprintf
# define FORMAT_FIXED_STRING sprintf
# define FORMAT_FORMAT_STRING sprintf
# define FORMAT_FORMAT_STRING sprintf
# define BINARY_FIND binary_search
# define BINARY_FIND binary_search
# define NOW time(NULL)
typedef struct {
typedef struct ot_peer {
# ifndef OT_COMPACT_ONLY
# ifndef OT_COMPACT_ONLY
ot_hash id ;
ot_hash id ;
ot_hash key ;
ot_hash key ;
# endif
# endif
ot_ip ip ;
ot_ip ip ;
unsigned short port ;
ot_word port ;
ot_time death ;
ot_time death ;
unsigned char flags ;
ot_byte flags ;
} ot_peer ;
} * ot_peer ;
unsigned char PEER_FLAG_SEEDING = 0x80 ;
ot_byte PEER_FLAG_SEEDING = 0x80 ;
unsigned char PEER_IP_LENGTH_MASK = 0x3f ;
ot_byte PEER_IP_LENGTH_MASK = 0x3f ;
typedef struct {
typedef struct {
ot_hash hash ;
ot_hash hash ;
ot_peer * peer_list ;
ot_peer peer_list ;
unsigned long peer_count ;
unsigned long peer_count ;
unsigned long seed_count ;
unsigned long seed_count ;
} ot_torrent ;
} * ot_torrent ;
void * map_file ( char * file_name ) ;
void * map_file ( char * file_name ) ;
void unmap_file ( char * file_name , void * map , unsigned long real_size ) ;
// This behaves quite like bsearch but allows to find
// This behaves quite like bsearch but allows to find
// the insertion point for inserts after unsuccessful searches
// 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
//
//
// END OF STUFF THAT BELONGS INTO A HEADER FILE
// END OF STUFF THAT BELONGS INTO A HEADER FILE
ot_torrent * torrents_pointer = 0 ;
unsigned long torrents_count = 0 ;
unsigned long torrents_count = 0 ;
unsigned char * scratchspace ;
ot_torrent torrents_list = 0 ;
ot_byte * scratch_space = 0 ;
// Converter function from memory to human readable hex strings
// * definitely not thread safe!!!
//
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 ; }
ot_torrent * add_peer_to_torrent ( ot_hash hash , ot_peer * peer ) {
ot_torrent add_peer_to_torrent ( ot_hash hash , ot_peer peer ) {
ot_torrent * torrent ;
ot_torrent torrent ;
ot_peer * peer_dest ;
ot_peer peer_dest ;
int exactmatch ;
int exactmatch ;
torrent = BINARY_FIND ( hash , torrents_pointer , torrents_count , sizeof ( ot_ torrent ) , compare_hash , & exactmatch ) ;
torrent = BINARY_FIND ( hash , torrents_list , torrents_count , sizeof ( * torrent ) , compare_hash , & exactmatch ) ;
if ( ! exactmatch ) {
if ( ! exactmatch ) {
// Assume, OS will provide us with space, after all, this is file backed
// Assume, OS will provide us with space, after all, this is file backed
MEMMOVE ( torrent + 1 , torrent , ( torrents_pointer + torrents_count ) - torrent ) ;
MEMMOVE ( torrent + 1 , torrent , ( torrents_list + torrents_count ) - torrent ) ;
// Create a new torrent entry, then
// Create a new torrent entry, then
MEMMOVE ( & torrent - > hash , hash , sizeof ( ot_hash ) ) ;
MEMMOVE ( & torrent - > hash , hash , sizeof ( ot_hash ) ) ;
torrent - > peer_list = map_file ( hash ) ;
torrent - > peer_list = map_file ( to_hex ( hash ) ) ;
torrent - > peer_count = 0 ;
torrent - > peer_count = 0 ;
torrent - > seed_count = 0 ;
torrent - > seed_count = 0 ;
}
}
peer_dest = BINARY_FIND ( peer , torrent - > peer_list , torrent - > peer_count , sizeof ( ot_ peer ) , compare_ip_port , & exactmatch ) ;
peer_dest = BINARY_FIND ( peer , torrent - > peer_list , torrent - > peer_count , sizeof ( * peer_dest ) , compare_ip_port , & exactmatch ) ;
if ( exactmatch ) {
if ( exactmatch ) {
// If peer was a seeder but isn't anymore, decrease seeder count
// If peer was a seeder but isn't anymore, decrease seeder count
if ( ( peer_dest - > flags & PEER_FLAG_SEEDING ) & & ! ( peer - > flags & PEER_FLAG_SEEDING ) )
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 ) {
}
}
// Set new time out time
// Set new time out time
peer_dest - > death = now ( ) + OT_TIMEOUT ;
peer_dest - > death = NOW + OT_TIMEOUT ;
return torrent ;
return torrent ;
}
}
# define SETINVALID( i ) (scratchspace[index] = 3);
# define SETINVALID( i ) (scratch_ space[index] = 3);
# define SETSELECTED( i ) (scratchspace[index] = 1);
# define SETSELECTED( i ) (scratch_ space[index] = 1);
# define TESTSELECTED( i ) (scratchspace[index] == 1 )
# define TESTSELECTED( i ) (scratch_ space[index] == 1 )
# define TESTSET( i ) (scratchspace[index])
# define TESTSET( i ) (scratch_ space[index])
# define RANDOM random()
# define RANDOM random()
inline int TESTVALIDPEER ( ot_peer * p ) { return p - > death > now ( ) ; }
inline int TESTVALIDPEER ( ot_peer p ) { return p - > death > NOW ; }
// Compiles a list of random peers for a torrent
// Compiles a list of random peers for a torrent
// * scratch space keeps track of death or already selected peers
// * scratch space keeps track of death or already selected peers
@ -122,14 +139,14 @@ inline int TESTVALIDPEER( ot_peer *p ) { return p->death > now(); }
// * it is not guaranteed to see all peers, so no assumptions on active seeders/peers may be done
// * it is not guaranteed to see all peers, so no assumptions on active seeders/peers may be done
// * since compact format cannot handle v6 addresses, it must be enabled by OT_COMPACT_ONLY
// * since compact format cannot handle v6 addresses, it must be enabled by OT_COMPACT_ONLY
//
//
void return_peers_for_torrent ( ot_torrent * torrent , unsigned long amount , char * reply ) {
void return_peers_for_torrent ( ot_torrent torrent , unsigned long amount , char * reply ) {
register ot_peer * peer_base = torrent - > peer_list ;
register ot_peer peer_base = torrent - > peer_list ;
unsigned long peer_count = torrent - > peer_count ;
unsigned long peer_count = torrent - > peer_count ;
unsigned long selected_count = 0 , invalid_count = 0 ;
unsigned long selected_count = 0 , invalid_count = 0 ;
unsigned long index = 0 ;
unsigned long index = 0 ;
// optimize later ;)
// optimize later ;)
BZERO ( scratchspace , peer_count ) ;
BZERO ( scratch_ space , peer_count ) ;
while ( ( selected_count < amount ) & & ( selected_count + invalid_count < peer_count ) ) {
while ( ( selected_count < amount ) & & ( selected_count + invalid_count < peer_count ) ) {
// skip to first non-flagged peer
// skip to first non-flagged peer
@ -150,11 +167,11 @@ void return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char *
# ifndef OT_COMPACT_ONLY
# ifndef OT_COMPACT_ONLY
reply + = FORMAT_FIXED_STRING ( reply , " d5:peersl " ) ;
reply + = FORMAT_FIXED_STRING ( reply , " d5:peersl " ) ;
# else
# else
reply + = FORMAT_FORMAT_STRING ( reply , " d5:peers%i: " , 6 * selected_count ) ;
reply + = FORMAT_FORMAT_STRING ( reply , " d5:peers%l i: " , 6 * selected_count ) ;
# endif
# endif
while ( selected_count - - ) {
while ( selected_count - - ) {
ot_peer * peer ;
ot_peer peer ;
while ( ! TESTSELECTED ( index ) ) + + index ;
while ( ! TESTSELECTED ( index ) ) + + index ;
peer = peer_base + index ;
peer = peer_base + index ;
# ifdef OT_COMPACT_ONLY
# ifdef OT_COMPACT_ONLY
@ -181,11 +198,11 @@ void return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char *
// * is rather expansive
// * is rather expansive
// * if this fails, torrent file is invalid, should add flag
// * if this fails, torrent file is invalid, should add flag
//
//
void heal_torrent ( ot_torrent * torrent ) {
void heal_torrent ( ot_torrent torrent ) {
unsigned long index = 0 , base = 0 , end , seed_count = 0 ;
unsigned long index = 0 , base = 0 , end , seed_count = 0 , now = NOW ;
// Initialize base to first dead peer.
// Initialize base to first dead peer.
while ( ( base < torrent - > peer_count ) & & torrent - > peer_list [ base ] . death < = now ( ) ) {
while ( ( base < torrent - > peer_count ) & & torrent - > peer_list [ base ] . death < = now ) {
seed_count + = ( torrent - > peer_list [ base ] . flags & PEER_FLAG_SEEDING ) ? 1 : 0 ;
seed_count + = ( torrent - > peer_list [ base ] . flags & PEER_FLAG_SEEDING ) ? 1 : 0 ;
base + + ;
base + + ;
}
}
@ -199,7 +216,7 @@ void heal_torrent( ot_torrent *torrent ) {
while ( 1 ) {
while ( 1 ) {
// Let index search for next living peer
// Let index search for next living peer
while ( ( index < torrent - > peer_count ) & & torrent - > peer_list [ index ] . death > now ( ) ) index + + ;
while ( ( index < torrent - > peer_count ) & & torrent - > peer_list [ index ] . death > now ) index + + ;
// No further living peers found - base is our new peer count
// No further living peers found - base is our new peer count
if ( index = = torrent - > peer_count ) {
if ( index = = torrent - > peer_count ) {
@ -211,25 +228,32 @@ void heal_torrent( ot_torrent *torrent ) {
end = index + 1 ;
end = index + 1 ;
// Let end search for next dead peer (end of living peers)
// Let end search for next dead peer (end of living peers)
while ( ( end < torrent - > peer_count ) & & torrent - > peer_list [ end ] . death < = now ( ) ) {
while ( ( end < torrent - > peer_count ) & & torrent - > peer_list [ end ] . death < = now ) {
seed_count + = ( torrent - > peer_list [ end ] . flags & PEER_FLAG_SEEDING ) ? 1 : 0 ;
seed_count + = ( torrent - > peer_list [ end ] . flags & PEER_FLAG_SEEDING ) ? 1 : 0 ;
end + + ;
end + + ;
}
}
// We either hit a dead peer or the end of our peers
// We either hit a dead peer or the end of our peers
// In both cases: move block towards base
// In both cases: move block towards base
MEMMOVE ( torrent - > peer_list + base , torrent - > peer_list + index , ( end - index ) * sizeof ( ot_peer ) ) ;
MEMMOVE ( torrent - > peer_list + base , torrent - > peer_list + index , ( end - index ) * sizeof ( struct ot_peer ) ) ;
base + = end - index ;
base + = end - index ;
index = end ;
index = end ;
}
}
}
}
void dispose_torrent ( ot_torrent torrent ) {
unmap_file ( " " , torrent - > peer_list , 0 ) ;
unlink ( to_hex ( torrent - > hash ) ) ;
MEMMOVE ( torrent , torrent + 1 , ( torrents_list + torrents_count ) - ( torrent + 1 ) ) ;
torrents_count - - ;
}
void * binary_search ( const void * key , const void * base ,
void * binary_search ( const void * key , const void * base ,
unsigned long member_count , const unsigned long member_size ,
unsigned long member_count , const unsigned long member_size ,
int ( * compar ) ( const void * , const void * ) ,
int ( * compar ) ( const void * , const void * ) ,
int * exactmatch ) {
int * exactmatch ) {
unsigned char * lookat = ( ( unsigned char * ) base ) + member_size * ( member_count > > 1 ) ;
ot_byte * lookat = ( ( ot_byte * ) base ) + member_size * ( member_count > > 1 ) ;
* exactmatch = 1 ;
* exactmatch = 1 ;
while ( member_count ) {
while ( member_count ) {
@ -240,7 +264,7 @@ void *binary_search( const void *key, const void *base,
- - member_count ;
- - member_count ;
}
}
member_count > > = 1 ;
member_count > > = 1 ;
lookat = ( ( unsigned char * ) base ) + member_size * ( member_count > > 1 ) ;
lookat = ( ( ot_byte * ) base ) + member_size * ( member_count > > 1 ) ;
}
}
* exactmatch = 0 ;
* exactmatch = 0 ;
return ( void * ) lookat ;
return ( void * ) lookat ;
@ -248,26 +272,44 @@ void *binary_search( const void *key, const void *base,
}
}
// This function maps a "huge" file into process space
// This function maps a "huge" file into process space
// * no name will aqcuire anonymous growable memory
// * memory will not be "freed" from systems vm if once used, until unmap_file
// * I guess, we should be checking for more errors...
// * I guess, we should be checking for more errors...
//
void * map_file ( char * file_name ) {
void * map_file ( char * file_name ) {
char * map ;
char * map ;
int file_desc = open ( file_name , O_RDWR | O_CREAT | O_NDELAY , 0644 ) ;
if ( file_name ) {
int file_desc = open ( file_name , O_RDWR | O_CREAT | O_NDELAY , 0644 ) ;
if ( file_desc < 0 ) return 0 ;
if ( file_desc < 0 ) return 0 ;
map = mmap ( 0 , OT_HUGE_FILESIZE , PROT_READ | PROT_WRITE , MAP_SHARED , file_desc , 0 ) ;
map = mmap ( 0 , OT_HUGE_FILESIZE , PROT_READ | PROT_WRITE , MAP_SHARED , file_desc , 0 ) ;
close ( file_desc ) ;
close ( file_desc ) ;
} else
map = mmap ( 0 , OT_HUGE_FILESIZE , PROT_READ | PROT_WRITE , MAP_ANON , - 1 , 0 ) ;
return ( map = = ( char * ) - 1 ) ? 0 : map ;
return ( map = = ( char * ) - 1 ) ? 0 : map ;
}
}
void unmap_file ( char * file_name , void * map , unsigned long real_size ) {
munmap ( map , OT_HUGE_FILESIZE ) ;
if ( file_name )
truncate ( file_name , real_size ) ;
}
int init_logic ( ) {
int init_logic ( ) {
unlink ( " ./opentracker_map_index.idx " ) ;
scratch_space = map_file ( " " ) ;
torrents_pointer = map_file ( " ./opentracker_map_index.idx " ) ;
torrents_list = map_file ( " " ) ;
torrents_count = 0 ;
torrents_count = 0 ;
scratchspace = map_file ( " ./scratchspace " ) ;
// Scan directory for filenames in the form [0-9A-F]{20}
// ...
return 0 ;
}
}
void deinit_logic ( ) {
void deinit_logic ( ) {
unmap_file ( torrents_pointer ) ;
// For all torrents... blablabla
while ( torrents_count - - )
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 ) ) ;
unmap_file ( " " , torrents_list , 0 ) ;
unmap_file ( " " , scratch_space , 0 ) ;
}
}