added live sync code

added a config file parser
added tracker id
changed WANT_CLOSED_TRACKER and WANT_BLACKLIST into WANT_ACCESS_WHITE and WANT_ACCESS_BLACK
changed WANT_TRACKER_SYNC to WANT_SYNC_BATCH and added WANT_SYNC_LIVE
added an option to switch off fullscrapes

cleaned up many internal hardcoded values, like PROTO_FLAG,
dynamic-accesslists
erdgeist 16 years ago
parent 8cbfc8602c
commit e534db03c6

@ -8,12 +8,14 @@
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <pwd.h>
#include <ctype.h>
#include <arpa/inet.h>
/* Libowfat */
@ -21,6 +23,7 @@
#include "io.h"
#include "iob.h"
#include "array.h"
#include "byte.h"
#include "fmt.h"
#include "scan.h"
#include "ip4.h"
@ -34,17 +37,18 @@
#include "ot_clean.h"
#include "ot_accesslist.h"
#include "ot_stats.h"
#include "ot_livesync.h"
/* Globals */
time_t g_now;
char * g_redirecturl = NULL;
time_t g_now;
char * g_redirecturl = NULL;
uint32_t g_tracker_id;
static char * g_serverdir = NULL;
/* To always have space for error messages ;) */
static char static_inbuf[8192];
static char *FLAG_TCP = "T";
static char *FLAG_UDP = "U";
static void panic( const char *routine ) {
fprintf( stderr, "%s: %s\n", routine, strerror(errno) );
exit( 111 );
@ -63,10 +67,10 @@ static void signal_handler( int s ) {
}
static void usage( char *name ) {
fprintf( stderr, "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-A ip]"
#ifdef WANT_BLACKLISTING
fprintf( stderr, "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-A ip] [-f config] [-s livesyncport]"
#ifdef WANT_ACCESSLIST_BLACK
" [-b blacklistfile]"
#elif defined ( WANT_CLOSED_TRACKER )
#elif defined ( WANT_ACCESSLIST_WHITE )
" [-w whitelistfile]"
#endif
"\n", name );
@ -82,9 +86,9 @@ static void help( char *name ) {
HELPLINE("-r redirecturl","specify url where / should be redirected to (default none)");
HELPLINE("-d dir","specify directory to try to chroot to (default: \".\")");
HELPLINE("-A ip","bless an ip address as admin address (e.g. to allow syncs from this address)");
#ifdef WANT_BLACKLISTING
#ifdef WANT_ACCESSLIST_BLACK
HELPLINE("-b file","specify blacklist file.");
#elif defined( WANT_CLOSED_TRACKER )
#elif defined( WANT_ACCESSLIST_WHITE )
HELPLINE("-w file","specify whitelist file.");
#endif
@ -168,7 +172,7 @@ static void handle_accept( const int64 serversocket ) {
memset( h, 0, sizeof( struct http_data ) );
memmove( h->ip, ip, sizeof( ip ) );
stats_issue_event( EVENT_ACCEPT, 1, ntohl(*(uint32_t*)ip));
stats_issue_event( EVENT_ACCEPT, FLAG_TCP, ntohl(*(uint32_t*)ip));
/* That breaks taia encapsulation. But there is no way to take system
time this often in FreeBSD and libowfat does not allow to set unix time */
@ -194,10 +198,12 @@ static void server_mainloop( ) {
while( ( i = io_canread( ) ) != -1 ) {
const void *cookie = io_getcookie( i );
if( cookie == FLAG_TCP )
if( (int)cookie == FLAG_TCP )
handle_accept( i );
else if( cookie == FLAG_UDP )
else if( (int)cookie == FLAG_UDP )
handle_udp4( i );
else if( (int)cookie == FLAG_MCA )
handle_livesync(i);
else
handle_read( i );
}
@ -214,6 +220,8 @@ static void server_mainloop( ) {
next_timeout_check = g_now + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
}
livesync_ticker();
/* See if we need to move our pools */
if( NOW != ot_last_clean_time ) {
ot_last_clean_time = NOW;
@ -225,55 +233,148 @@ static void server_mainloop( ) {
}
}
static void ot_try_bind( char ip[4], uint16 port, int is_tcp ) {
int64 s = is_tcp ? socket_tcp4( ) : socket_udp4();
int64_t ot_try_bind( char ip[4], uint16_t port, PROTO_FLAG proto ) {
int64 s = proto == FLAG_TCP ? socket_tcp4( ) : socket_udp4();
if( socket_bind4_reuse( s, ip, port ) == -1 )
panic( "socket_bind4_reuse" );
if( is_tcp && ( socket_listen( s, SOMAXCONN) == -1 ) )
if( ( proto == FLAG_TCP ) && ( socket_listen( s, SOMAXCONN) == -1 ) )
panic( "socket_listen" );
if( !io_fd( s ) )
panic( "io_fd" );
io_setcookie( s, is_tcp ? FLAG_TCP : FLAG_UDP );
io_setcookie( s, (void*)proto );
io_wantread( s );
return s;
}
char * set_config_option( char **option, char *value ) {
while( isspace(*value) ) ++value;
if( *option ) free( *option );
return *option = strdup( value );
}
/* WARNING! Does not behave like scan_ip4 regarding return values */
static int scan_ip4_port( const char *src, char *ip, uint16 *port ) {
int off;
while( isspace(*src) ) ++src;
if( !(off = scan_ip4( src, ip ) ) )
return -1;
src += off;
if( *src == 0 ) return 0;
if( *src != ':' )
return -1;
*port = atol(src+1);
return 0;
}
int parse_configfile( char * config_filename ) {
FILE * accesslist_filehandle;
char inbuf[512], tmpip[4];
int bound = 0;
accesslist_filehandle = fopen( config_filename, "r" );
if( accesslist_filehandle == NULL ) {
fprintf( stderr, "Warning: Can't open config file: %s.", config_filename );
return 0;
}
while( fgets( inbuf, sizeof(inbuf), accesslist_filehandle ) ) {
char *newl;
char *p = inbuf;
/* Skip white spaces */
while(isspace(*p)) ++p;
/* Ignore comments and empty lines */
if((*p=='#')||(*p=='\n')||(*p==0)) continue;
/* chomp */
if(( newl = strchr(p, '\n' ))) *newl = 0;
/* Scan for commands */
if(!byte_diff(p,15,"tracker.rootdir" ) && isspace(p[15])) {
set_config_option( &g_serverdir, p+16 );
} else if(!byte_diff(p,10,"listen.tcp" ) && isspace(p[10])) {
uint16_t tmpport = 6969;
if( scan_ip4_port( p+11, tmpip, &tmpport )) goto parse_error;
ot_try_bind( tmpip, tmpport, FLAG_TCP );
++bound;
} else if(!byte_diff(p, 10, "listen.udp" ) && isspace(p[10])) {
uint16_t tmpport = 6969;
if( scan_ip4_port( p+11, tmpip, &tmpport )) goto parse_error;
ot_try_bind( tmpip, tmpport, FLAG_UDP );
++bound;
#ifdef WANT_ACCESSLIST_BLACK
} else if(!byte_diff(p, 16, "access.whitelist" ) && isspace(p[16])) {
set_config_option( &g_accesslist_filename, p+17 );
#elif defined( WANT_ACCESSLIST_WHITE )
} else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) {
set_config_option( &g_accesslist_filename, p+17 );
#endif
} else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) {
set_config_option( &g_redirecturl, p+21 );
#ifdef WANT_SYNC_BATCH
} else if(!byte_diff(p, 26, "batchsync.cluster.admin_ip" ) && isspace(p[26])) {
if(!scan_ip4( p+27, tmpip )) goto parse_error;
accesslist_blessip( tmpip, OT_PERMISSION_MAY_SYNC );
#endif
#ifdef WANT_SYNC_LIVE
} else if(!byte_diff(p, 24, "livesync.cluster.node_ip" ) && isspace(p[24])) {
if( !scan_ip4( p+25, tmpip )) goto parse_error;
accesslist_blessip( tmpip, OT_PERMISSION_MAY_LIVESYNC );
} else if(!byte_diff(p, 23, "livesync.cluster.listen" ) && isspace(p[23])) {
uint16_t tmpport = LIVESYNC_PORT;
if( scan_ip4_port( p+24, tmpip, &tmpport )) goto parse_error;
livesync_bind_mcast( tmpip, tmpport );
#endif
} else
fprintf( stderr, "Unhandled line in config file: %s\n", inbuf );
continue;
parse_error:
fprintf( stderr, "Parse error in config file: %s\n", inbuf);
}
fclose( accesslist_filehandle );
return bound;
}
int main( int argc, char **argv ) {
struct passwd *pws = NULL;
char serverip[4] = {0,0,0,0}, tmpip[4];
char *serverdir = ".";
int bound = 0, scanon = 1;
#ifdef WANT_ACCESS_CONTROL
char *accesslist_filename = NULL;
#endif
while( scanon ) {
switch( getopt( argc, argv, ":i:p:A:P:d:r:v"
#ifdef WANT_BLACKLISTING
while( scanon ) {
switch( getopt( argc, argv, ":i:p:A:P:d:r:s:f:v"
#ifdef WANT_ACCESSLIST_BLACK
"b:"
#elif defined( WANT_CLOSED_TRACKER )
#elif defined( WANT_ACCESSLIST_WHITE )
"w:"
#endif
"h" ) ) {
case -1 : scanon = 0; break;
case 'i': scan_ip4( optarg, serverip ); break;
#ifdef WANT_BLACKLISTING
case 'b': accesslist_filename = optarg; break;
#elif defined( WANT_CLOSED_TRACKER )
case 'w': accesslist_filename = optarg; break;
#ifdef WANT_ACCESSLIST_BLACK
case 'b': set_config_option( &g_accesslist_filename, optarg); break;
#elif defined( WANT_ACCESSLIST_WHITE )
case 'w': set_config_option( &g_accesslist_filename, optarg); break;
#endif
case 'p': ot_try_bind( serverip, (uint16)atol( optarg ), FLAG_TCP ); bound++; break;
case 'P': ot_try_bind( serverip, (uint16)atol( optarg ), FLAG_UDP ); bound++; break;
#ifdef WANT_SYNC_LIVE
case 's': livesync_bind_mcast( serverip, (uint16)atol( optarg )); break;
#endif
case 'p': ot_try_bind( serverip, (uint16)atol( optarg ), 1 ); bound++; break;
case 'P': ot_try_bind( serverip, (uint16)atol( optarg ), 0 ); bound++; break;
case 'd': serverdir = optarg; break;
case 'r': g_redirecturl = optarg; break;
case 'd': set_config_option( &g_serverdir, optarg ); break;
case 'r': set_config_option( &g_redirecturl, optarg ); break;
case 'A':
scan_ip4( optarg, tmpip );
accesslist_blessip( tmpip, 0xffff ); /* Allow everything for now */
break;
case 'f': bound += parse_configfile( optarg ); break;
case 'h': help( argv[0] ); exit( 0 );
case 'v': write( 2, static_inbuf, stats_return_tracker_version( static_inbuf )); exit( 0 );
default:
@ -283,8 +384,8 @@ int main( int argc, char **argv ) {
/* Bind to our default tcp/udp ports */
if( !bound) {
ot_try_bind( serverip, 6969, 1 );
ot_try_bind( serverip, 6969, 0 );
ot_try_bind( serverip, 6969, FLAG_TCP );
ot_try_bind( serverip, 6969, FLAG_UDP );
}
/* Drop permissions */
@ -298,15 +399,13 @@ int main( int argc, char **argv ) {
}
endpwent();
accesslist_init( accesslist_filename );
signal( SIGPIPE, SIG_IGN );
signal( SIGINT, signal_handler );
signal( SIGALRM, signal_handler );
g_now = time( NULL );
if( trackerlogic_init( serverdir ) == -1 )
if( trackerlogic_init( g_serverdir ? g_serverdir : "." ) == -1 )
panic( "Logic not started" );
alarm(5);

@ -21,6 +21,7 @@
65542EE80CE0CA6B00469330 /* ot_udp.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542EE70CE0CA6B00469330 /* ot_udp.c */; };
65542F920CE17CA900469330 /* ot_fullscrape.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542F910CE17CA900469330 /* ot_fullscrape.c */; };
65B8DF3C0D0310D20017149E /* ot_http.c in Sources */ = {isa = PBXBuildFile; fileRef = 65B8DF3B0D0310D20017149E /* ot_http.c */; };
65FA33990E7EF09200F7D5A5 /* ot_livesync.c in Sources */ = {isa = PBXBuildFile; fileRef = 65FA33980E7EF09200F7D5A5 /* ot_livesync.c */; };
8DD76FB00486AB0100D96B5E /* opentracker.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6A0FF2C0290799A04C91782 /* opentracker.1 */; };
/* End PBXBuildFile section */
@ -66,6 +67,8 @@
65542F910CE17CA900469330 /* ot_fullscrape.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_fullscrape.c; sourceTree = "<group>"; };
65B8DF3A0D0310D20017149E /* ot_http.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_http.h; sourceTree = "<group>"; };
65B8DF3B0D0310D20017149E /* ot_http.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_http.c; sourceTree = "<group>"; };
65FA33970E7EF09200F7D5A5 /* ot_livesync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_livesync.h; sourceTree = "<group>"; };
65FA33980E7EF09200F7D5A5 /* ot_livesync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_livesync.c; sourceTree = "<group>"; };
C6A0FF2C0290799A04C91782 /* opentracker.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = opentracker.1; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -107,6 +110,7 @@
65542E740CE08B9100469330 /* ot_clean.c */,
65542F910CE17CA900469330 /* ot_fullscrape.c */,
65B8DF3B0D0310D20017149E /* ot_http.c */,
65FA33980E7EF09200F7D5A5 /* ot_livesync.c */,
653A56B40CE28EC5000CF140 /* ot_iovec.c */,
65542D8F0CE07CED00469330 /* ot_mutex.c */,
65542D910CE07CED00469330 /* ot_stats.c */,
@ -132,6 +136,7 @@
65542D810CE0786F00469330 /* Headers */ = {
isa = PBXGroup;
children = (
65FA33970E7EF09200F7D5A5 /* ot_livesync.h */,
653A320A0CE7F475007F0D03 /* ot_accesslist.h */,
65542E730CE08B9100469330 /* ot_clean.h */,
65542F900CE17CA900469330 /* ot_fullscrape.h */,
@ -248,6 +253,7 @@
653A56B50CE28EC5000CF140 /* ot_iovec.c in Sources */,
653A320C0CE7F475007F0D03 /* ot_accesslist.c in Sources */,
65B8DF3C0D0310D20017149E /* ot_http.c in Sources */,
65FA33990E7EF09200F7D5A5 /* ot_livesync.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

@ -18,8 +18,8 @@
#include "ot_accesslist.h"
/* GLOBAL VARIABLES */
#ifdef WANT_ACCESS_CONTROL
static char *accesslist_filename = NULL;
#ifdef WANT_ACCESSLIST
char *g_accesslist_filename = NULL;
static ot_vector accesslist;
static void accesslist_reset( void ) {
@ -46,13 +46,13 @@ static void accesslist_readfile( int foo ) {
char inbuf[512];
foo = foo;
accesslist_filehandle = fopen( accesslist_filename, "r" );
accesslist_filehandle = fopen( g_accesslist_filename, "r" );
/* Free accesslist vector in trackerlogic.c*/
accesslist_reset();
if( accesslist_filehandle == NULL ) {
fprintf( stderr, "Warning: Can't open accesslist file: %s (but will try to create it later, if necessary and possible).", accesslist_filename );
fprintf( stderr, "Warning: Can't open accesslist file: %s (but will try to create it later, if necessary and possible).", g_accesslist_filename );
return;
}
@ -79,21 +79,20 @@ int accesslist_hashisvalid( ot_hash *hash ) {
int exactmatch;
binary_search( hash, accesslist.data, accesslist.size, OT_HASH_COMPARE_SIZE, OT_HASH_COMPARE_SIZE, &exactmatch );
#ifdef WANT_BLACKLISTING
#ifdef WANT_ACCESSLIST_BLACK
exactmatch = !exactmatch;
#endif
return exactmatch;
}
void accesslist_init( char *accesslist_filename_in ) {
void accesslist_init( ) {
byte_zero( &accesslist, sizeof( accesslist ) );
/* Passing "0" since read_blacklist_file also is SIGHUP handler */
if( accesslist_filename_in ) {
accesslist_filename = accesslist_filename_in;
if( g_accesslist_filename ) {
accesslist_readfile( 0 );
signal( SIGHUP, accesslist_readfile );
signal( SIGHUP, accesslist_readfile );
}
}
@ -108,6 +107,7 @@ int accesslist_blessip( char *ip, ot_permissions permissions ) {
return -1;
memmove( g_adminip_addresses + g_adminip_count, ip, 4 );
g_adminip_permissions[ g_adminip_count++ ] = permissions;
// fprintf( stderr, "Blessing ip address %d.%d.%d.%d with %02x\n", (uint8_t)ip[0], (uint8_t)ip[1], (uint8_t)ip[2], (uint8_t)ip[3], permissions );
return 0;
}

@ -6,14 +6,17 @@
#ifndef __OT_ACCESSLIST_H__
#define __OT_ACCESSLIST_H__
#if defined ( WANT_BLACKLISTING ) && defined (WANT_CLOSED_TRACKER )
#error WANT_BLACKLISTING and WANT_CLOSED_TRACKER are exclusive.
#if defined ( WANT_ACCESSLIST_BLACK ) && defined (WANT_ACCESSLIST_WHITE )
#error WANT_ACCESSLIST_BLACK and WANT_ACCESSLIST_WHITE are exclusive.
#endif
#if defined ( WANT_BLACKLISTING ) || defined (WANT_CLOSED_TRACKER )
#define WANT_ACCESS_CONTROL
void accesslist_init( char *accesslist_filename );
#if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE )
#define WANT_ACCESSLIST
void accesslist_init( );
int accesslist_hashisvalid( ot_hash *hash );
extern char *g_accesslist_filename;
#else
#define accesslist_init( accesslist_filename )
#define accesslist_hashisvalid( hash ) 1
@ -22,7 +25,8 @@ int accesslist_hashisvalid( ot_hash *hash );
typedef enum {
OT_PERMISSION_MAY_FULLSCRAPE,
OT_PERMISSION_MAY_SYNC,
OT_PERMISSION_MAY_STAT
OT_PERMISSION_MAY_STAT,
OT_PERMISSION_MAY_LIVESYNC
} ot_permissions;
int accesslist_blessip( char * ip, ot_permissions permissions );

@ -25,7 +25,7 @@ int clean_single_torrent( ot_torrent *torrent ) {
size_t peers_count = 0, seeds_count;
time_t timedout = (int)( NOW - peer_list->base );
int i;
#ifdef WANT_TRACKER_SYNC
#ifdef WANT_SYNC_BATCH
char *new_peers;
#endif
@ -55,7 +55,7 @@ int clean_single_torrent( ot_torrent *torrent ) {
memmove( peer_list->seed_counts + timedout, peer_list->seed_counts, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) );
byte_zero( peer_list->seed_counts, sizeof( size_t ) * timedout );
#ifdef WANT_TRACKER_SYNC
#ifdef WANT_SYNC_BATCH
/* Save the block modified within last OT_POOLS_TIMEOUT */
if( peer_list->peers[1].size &&
( new_peers = realloc( peer_list->changeset.data, sizeof( ot_peer ) * peer_list->peers[1].size ) ) )

@ -3,6 +3,8 @@
$id$ */
#ifdef WANT_FULLSCRAPE
/* System */
#include <sys/param.h>
#include <sys/uio.h>
@ -226,5 +228,6 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas
/* Release unused memory in current output buffer */
iovec_fixlast( iovec_entries, iovector, r );
}
#endif
const char *g_version_fullscrape_c = "$Source$: $Revision$\n";

@ -6,8 +6,17 @@
#ifndef __OT_FULLSCRAPE_H__
#define __OT_FULLSCRAPE_H__
#ifdef WANT_FULLSCRAPE
void fullscrape_init( );
void fullscrape_deinit( );
void fullscrape_deliver( int64 socket, ot_tasktype tasktype );
#else
#define fullscrape_init()
#define fullscrape_deinit()
#endif
#endif

@ -28,10 +28,6 @@
#include "ot_accesslist.h"
#include "ot_sync.h"
#ifndef WANT_TRACKER_SYNC
#define add_peer_to_torrent(A,B,C) add_peer_to_torrent(A,B)
#endif
#define OT_MAXMULTISCRAPE_COUNT 64
static ot_hash multiscrape_buf[OT_MAXMULTISCRAPE_COUNT];
extern char *g_redirecturl;
@ -103,7 +99,7 @@ ssize_t http_issue_error( const int64 client_socket, int code ) {
#ifdef _DEBUG_HTTPERROR
fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request );
#endif
stats_issue_event( EVENT_FAILED, 1, code );
stats_issue_event( EVENT_FAILED, FLAG_TCP, code );
http_senddata( client_socket, static_outbuf, reply_size);
return -2;
}
@ -169,7 +165,7 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct
return 0;
}
#ifdef WANT_TRACKER_SYNC
#ifdef WANT_SYNC_BATCH
static ssize_t http_handle_sync( const int64 client_socket, char *data ) {
struct http_data* h = io_getcookie( client_socket );
size_t len;
@ -193,7 +189,7 @@ static ssize_t http_handle_sync( const int64 client_socket, char *data ) {
if( ( len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) < 10 ) HTTPERROR_400_PARAM;
if( add_changeset_to_tracker( (uint8_t*)data, len ) ) HTTPERROR_400_PARAM;
if( mode == SYNC_OUT ) {
stats_issue_event( EVENT_SYNC_IN, 1, 0 );
stats_issue_event( EVENT_SYNC_IN, FLAG_TCP, 0 );
mode = SYNC_IN;
}
break;
@ -203,7 +199,7 @@ static ssize_t http_handle_sync( const int64 client_socket, char *data ) {
if( mode == SYNC_OUT ) {
/* Pass this task to the worker thread */
h->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK;
stats_issue_event( EVENT_SYNC_OUT_REQUEST, 1, 0 );
stats_issue_event( EVENT_SYNC_OUT_REQUEST, FLAG_TCP, 0 );
sync_deliver( client_socket );
io_dontwantread( client_socket );
return -2;
@ -216,7 +212,6 @@ static ssize_t http_handle_sync( const int64 client_socket, char *data ) {
#endif
static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d, size_t l ) {
struct http_data* h = io_getcookie( client_socket );
char *c = data;
int mode = TASK_STATS_PEERS, scanon = 1, format = 0;
@ -284,7 +279,11 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d
}
}
/* Touch variable */
d=d;
#ifdef WANT_FULLSCRAPE
if( mode == TASK_STATS_TPB ) {
struct http_data* h = io_getcookie( client_socket );
tai6464 t;
#ifdef WANT_COMPRESSION_GZIP
d[l-1] = 0;
@ -292,9 +291,6 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d
h->flag |= STRUCT_HTTP_FLAG_GZIP;
format |= TASK_FLAG_GZIP;
}
#else
/* Touch variable */
d=d;
#endif
/* Pass this task to the worker thread */
h->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK;
@ -305,12 +301,14 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d
io_dontwantread( client_socket );
return -2;
}
#endif
/* default format for now */
if( !( l = return_stats_for_tracker( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, mode, 0 ) ) ) HTTPERROR_500;
return l;
}
#ifdef WANT_FULLSCRAPE
static ssize_t http_handle_fullscrape( const int64 client_socket, char *d, size_t l ) {
struct http_data* h = io_getcookie( client_socket );
int format = 0;
@ -341,6 +339,7 @@ write( 2, debug_request, l );
io_dontwantread( client_socket );
return -2;
}
#endif
static ssize_t http_handle_scrape( const int64 client_socket, char *data ) {
int scanon = 1, numwant = 0;
@ -387,7 +386,7 @@ UTORRENT1600_WORKAROUND:
/* Enough for http header + whole scrape string */
if( !( l = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf ) ) ) HTTPERROR_500;
stats_issue_event( EVENT_SCRAPE, 1, l );
stats_issue_event( EVENT_SCRAPE, FLAG_TCP, l );
return l;
}
@ -486,12 +485,12 @@ static ssize_t http_handle_announce( const int64 client_socket, char *data ) {
return sprintf( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, "d14:failure reason81:Your client forgot to send your torrent's info_hash. Please upgrade your client.e" );
if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED )
len = remove_peer_from_torrent( hash, &peer, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, 1 );
len = remove_peer_from_torrent( hash, &peer, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, FLAG_TCP );
else {
torrent = add_peer_to_torrent( hash, &peer, 0 );
torrent = add_peer_to_torrent( hash, &peer WANT_SYNC_PARAM( 0 ) );
if( !torrent || !( len = return_peers_for_torrent( hash, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, 1 ) ) ) HTTPERROR_500;
}
stats_issue_event( EVENT_ANNOUNCE, 1, len);
stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, len);
return len;
}
@ -529,14 +528,16 @@ ssize_t http_handle_request( const int64 client_socket, char *data, size_t recv_
/* This is the hardcore match for announce*/
if( ( *data == 'a' ) || ( *data == '?' ) )
reply_size = http_handle_announce( client_socket, c );
#ifdef WANT_FULLSCRAPE
else if( !byte_diff( data, 12, "scrape HTTP/" ) )
reply_size = http_handle_fullscrape( client_socket, recv_header, recv_length );
#endif
/* This is the hardcore match for scrape */
else if( !byte_diff( data, 2, "sc" ) )
reply_size = http_handle_scrape( client_socket, c );
/* All the rest is matched the standard way */
else switch( len ) {
#ifdef WANT_TRACKER_SYNC
#ifdef WANT_SYNC_BATCH
case 4: /* sync ? */
if( byte_diff( data, 4, "sync") ) HTTPERROR_404;
reply_size = http_handle_sync( client_socket, c );

@ -443,13 +443,13 @@ static size_t stats_httperrors_txt ( char * reply ) {
extern const char
*g_version_opentracker_c, *g_version_accesslist_c, *g_version_clean_c, *g_version_fullscrape_c, *g_version_http_c,
*g_version_iovec_c, *g_version_mutex_c, *g_version_stats_c, *g_version_sync_c, *g_version_udp_c, *g_version_vector_c,
*g_version_scan_urlencoded_query_c, *g_version_trackerlogic_c;
*g_version_scan_urlencoded_query_c, *g_version_trackerlogic_c, *g_version_livesync_c;
size_t stats_return_tracker_version( char *reply ) {
return sprintf( reply, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
return sprintf( reply, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
g_version_opentracker_c, g_version_accesslist_c, g_version_clean_c, g_version_fullscrape_c, g_version_http_c,
g_version_iovec_c, g_version_mutex_c, g_version_stats_c, g_version_sync_c, g_version_udp_c, g_version_vector_c,
g_version_scan_urlencoded_query_c, g_version_trackerlogic_c );
g_version_scan_urlencoded_query_c, g_version_trackerlogic_c, g_version_livesync_c );
}
size_t return_stats_for_tracker( char *reply, int mode, int format ) {
@ -490,36 +490,36 @@ size_t return_stats_for_tracker( char *reply, int mode, int format ) {
}
}
void stats_issue_event( ot_status_event event, int is_tcp, uint32_t event_data ) {
void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data ) {
switch( event ) {
case EVENT_ACCEPT:
if( is_tcp ) ot_overall_tcp_connections++; else ot_overall_udp_connections++;
if( proto == FLAG_TCP ) ot_overall_tcp_connections++; else ot_overall_udp_connections++;
#ifdef WANT_LOG_NETWORKS
stat_increase_network_count( &stats_network_counters_root, 0, event_data );
#endif
break;
case EVENT_ANNOUNCE:
if( is_tcp ) ot_overall_tcp_successfulannounces++; else ot_overall_udp_successfulannounces++;
if( proto == FLAG_TCP ) ot_overall_tcp_successfulannounces++; else ot_overall_udp_successfulannounces++;
break;
case EVENT_CONNECT:
if( is_tcp ) ot_overall_tcp_connects++; else ot_overall_udp_connects++;
if( proto == FLAG_TCP ) ot_overall_tcp_connects++; else ot_overall_udp_connects++;
break;
case EVENT_SCRAPE:
if( is_tcp ) ot_overall_tcp_successfulscrapes++; else ot_overall_udp_successfulscrapes++;
if( proto == FLAG_TCP ) ot_overall_tcp_successfulscrapes++; else ot_overall_udp_successfulscrapes++;
case EVENT_FULLSCRAPE:
ot_full_scrape_count++;
ot_full_scrape_size += event_data;
break;
case EVENT_FULLSCRAPE_REQUEST:
{
unsigned char ip[4]; *(int*)ip = is_tcp; /* ugly hack to transfer ip to stats */
unsigned char ip[4]; *(int*)ip = (int)proto; /* ugly hack to transfer ip to stats */
LOG_TO_STDERR( "[%08d] scrp: %d.%d.%d.%d - FULL SCRAPE\n", (unsigned int)(g_now - ot_start_time), ip[0], ip[1], ip[2], ip[3] );
ot_full_scrape_request_count++;
}
break;
case EVENT_FULLSCRAPE_REQUEST_GZIP:
{
unsigned char ip[4]; *(int*)ip = is_tcp; /* ugly hack to transfer ip to stats */
unsigned char ip[4]; *(int*)ip = (int)proto; /* ugly hack to transfer ip to stats */
LOG_TO_STDERR( "[%08d] scrp: %d.%d.%d.%d - FULL SCRAPE GZIP\n", (unsigned int)(g_now - ot_start_time), ip[0], ip[1], ip[2], ip[3] );
ot_full_scrape_request_count++;
}

@ -34,7 +34,7 @@ enum {
CODE_HTTPERROR_COUNT
};
void stats_issue_event( ot_status_event event, int is_tcp, uint32_t event_data );
void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data );
size_t return_stats_for_tracker( char *reply, int mode, int format );
size_t stats_return_tracker_version( char *reply );
void stats_init( );

@ -23,7 +23,7 @@
#include "ot_stats.h"
#include "ot_iovec.h"
#ifdef WANT_TRACKER_SYNC
#ifdef WANT_SYNC_BATCH
#define OT_SYNC_CHUNK_SIZE (512*1024)
@ -141,7 +141,7 @@ static void * sync_worker( void * args) {
ot_tasktype tasktype = TASK_SYNC_OUT;
ot_taskid taskid = mutex_workqueue_poptask( &tasktype );
sync_make( &iovec_entries, &iovector );
stats_issue_event( EVENT_SYNC_OUT, 1, iovec_length( &iovec_entries, &iovector) );
stats_issue_event( EVENT_SYNC_OUT, FLAG_TCP, iovec_length( &iovec_entries, &iovector) );
if( mutex_workqueue_pushresult( taskid, iovec_entries, iovector ) )
iovec_free( &iovec_entries, &iovector );
}

@ -6,7 +6,7 @@
#ifndef __OT_SYNC_H__
#define __OT_SYNC_H__
#ifdef WANT_TRACKER_SYNC
#ifdef WANT_SYNC_BATCH
enum { SYNC_IN, SYNC_OUT };
void sync_init( );
@ -14,6 +14,11 @@ void sync_deinit( );
void sync_deliver( int64 socket );
int add_changeset_to_tracker( uint8_t *data, size_t len );
#else
#define sync_init()
#define sync_deinit()
#endif
#endif

@ -52,8 +52,8 @@ void handle_udp4( int64 serversocket ) {
r = socket_recv4( serversocket, static_inbuf, sizeof( static_inbuf ), remoteip, &remoteport);
stats_issue_event( EVENT_ACCEPT, 0, ntohl(*(uint32_t*)remoteip) );
stats_issue_event( EVENT_READ, 0, r );
stats_issue_event( EVENT_ACCEPT, FLAG_UDP, ntohl(*(uint32_t*)remoteip) );
stats_issue_event( EVENT_READ, FLAG_UDP, r );
/* Minimum udp tracker packet size, also catches error */
if( r < 16 )
@ -72,7 +72,7 @@ void handle_udp4( int64 serversocket ) {
udp_make_connectionid( outpacket + 2, remoteip );
socket_send4( serversocket, static_outbuf, 16, remoteip, remoteport );
stats_issue_event( EVENT_CONNECT, 0, 16 );
stats_issue_event( EVENT_CONNECT, FLAG_UDP, 16 );
break;
case 1: /* This is an announce action */
/* Minimum udp announce packet size */
@ -109,9 +109,9 @@ void handle_udp4( int64 serversocket ) {
outpacket[1] = inpacket[12/4];
if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) /* Peer is gone. */
r = remove_peer_from_torrent( hash, &peer, static_outbuf, 0 );
r = remove_peer_from_torrent( hash, &peer, static_outbuf, FLAG_UDP );
else {
torrent = add_peer_to_torrent( hash, &peer WANT_TRACKER_SYNC_PARAM( 0 ) );
torrent = add_peer_to_torrent( hash, &peer WANT_SYNC_PARAM( 0 ) );
if( !torrent )
return; /* XXX maybe send error */
@ -119,7 +119,7 @@ void handle_udp4( int64 serversocket ) {
}
socket_send4( serversocket, static_outbuf, r, remoteip, remoteport );
stats_issue_event( EVENT_ANNOUNCE, 0, r );
stats_issue_event( EVENT_ANNOUNCE, FLAG_UDP, r );
break;
case 2: /* This is a scrape action */
@ -133,7 +133,7 @@ void handle_udp4( int64 serversocket ) {
return_udp_scrape_for_torrent( (ot_hash*)( static_inbuf + 16 + 20 * r_out ), static_outbuf + 8 + 12 * r_out );
socket_send4( serversocket, static_outbuf, 8 + 12 * r_out, remoteip, remoteport );
stats_issue_event( EVENT_SCRAPE, 0, r );
stats_issue_event( EVENT_SCRAPE, FLAG_UDP, r );
break;
}
}

@ -64,13 +64,13 @@ void scan_urlencoded_skipvalue( char **string ) {
ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags) {
const unsigned char* s=*(const unsigned char**) string;
unsigned char *d = (unsigned char*)deststring;
unsigned char b, c, f;
unsigned char b, c;
/* This is the main decoding loop.
'flag' determines, which characters are non-terminating in current context
(ie. stop at '=' and '&' if scanning for a 'param'; stop at '?' if scanning for the path )
*/
while( ( f = is_unreserved[ c = *s++ ] ) & flags ) {
while( is_unreserved[ c = *s++ ] & flags ) {
/* When encountering an url escaped character, try to decode */
if( c=='%') {

@ -0,0 +1,14 @@
#!/bin/sh
while true; do
request_string="GET /announce?info_hash=012345678901234567\
%$(printf %02X $(( $RANDOM & 0xff )) )\
%$(printf %02X $(( $RANDOM & 0xff )) )\
&ip=$(( $RANDOM & 0xff )).17.13.15&port=$(( $RANDOM & 0xff )) HTTP/1.0\n"
echo $request_string
echo
echo $request_string | nc 10.0.1.3 6969 >/dev/null
echo
done

@ -14,6 +14,7 @@
#include <unistd.h>
#include <time.h>
#include <math.h>
#include <errno.h>
/* Libowfat */
#include "scan.h"
@ -28,19 +29,20 @@
#include "ot_accesslist.h"
#include "ot_fullscrape.h"
#include "ot_sync.h"
#include "ot_livesync.h"
void free_peerlist( ot_peerlist *peer_list ) {
size_t i;
for( i=0; i<OT_POOLS_COUNT; ++i )
if( peer_list->peers[i].data )
free( peer_list->peers[i].data );
#ifdef WANT_TRACKER_SYNC
#ifdef WANT_SYNC_BATCH
free( peer_list->changeset.data );
#endif
free( peer_list );
}
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC_PARAM( int from_changeset ) ) {
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_changeset ) ) {
int exactmatch;
ot_torrent *torrent;
ot_peer *peer_dest;
@ -58,6 +60,11 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC
return NULL;
}
#ifdef WANT_SYNC_LIVE
if( !from_changeset )
livesync_tell( hash, peer, PEER_FLAG_LEECHING );
#endif
if( !exactmatch ) {
/* Create a new torrent entry, then */
memmove( &torrent->hash, hash, sizeof( ot_hash ) );
@ -79,7 +86,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC
if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
OT_FLAG( peer ) ^= PEER_FLAG_COMPLETED;
#ifdef WANT_TRACKER_SYNC
#ifdef WANT_SYNC
if( from_changeset ) {
/* Check, whether peer already is in current pool, do nothing if so */
peer_pool = &torrent->peer_list->peers[0];
@ -148,7 +155,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC
* RANDOM may return huge values
* does not yet check not to return self
*/
size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int is_tcp ) {
size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, PROTO_FLAG proto ) {
char *r = reply;
int exactmatch;
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
@ -164,7 +171,7 @@ size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int
if( peer_list->peer_count < amount )
amount = peer_list->peer_count;
if( is_tcp )
if( proto == FLAG_TCP )
r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie5:peers%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount );
else {
*(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
@ -204,7 +211,7 @@ size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int
r += 6;
}
}
if( is_tcp )
if( proto == FLAG_TCP )
*r++ = 'e';
mutex_bucket_unlock_by_hash( hash );
@ -263,23 +270,33 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl
return r - reply;
}
size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) {
size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto ) {
int exactmatch;
size_t index;
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
ot_peerlist *peer_list;
#ifdef WANT_SYNC_LIVE
if( proto != FLAG_MCA )
livesync_tell( hash, peer, PEER_FLAG_STOPPED );
#endif
if( !exactmatch ) {
mutex_bucket_unlock_by_hash( hash );
if( is_tcp )
if( proto == FLAG_TCP )
return sprintf( reply, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM );
/* Create fake packet to satisfy parser on the other end */
((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
((uint32_t*)reply)[3] = ((uint32_t*)reply)[4] = 0;
return (size_t)20;
if( proto == FLAG_UDP ) {
((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
((uint32_t*)reply)[3] = ((uint32_t*)reply)[4] = 0;
return (size_t)20;
}
if( proto == FLAG_MCA )
return 0;
}
peer_list = torrent->peer_list;
@ -296,37 +313,46 @@ size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int
exit_loop:
if( is_tcp ) {
if( proto == FLAG_TCP ) {
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 );
mutex_bucket_unlock_by_hash( hash );
return reply_size;
}
/* else { Handle UDP reply */
((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
((uint32_t*)reply)[3] = htonl( peer_list->peer_count - peer_list->seed_count );
((uint32_t*)reply)[4] = htonl( peer_list->seed_count);
/* Handle UDP reply */
if( proto == FLAG_TCP ) {
((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
((uint32_t*)reply)[3] = htonl( peer_list->peer_count - peer_list->seed_count );
((uint32_t*)reply)[4] = htonl( peer_list->seed_count);
}
mutex_bucket_unlock_by_hash( hash );
return (size_t)20;
}
void exerr( char * message ) {
fprintf( stderr, "%s\n", message );
exit( 111 );
}
int trackerlogic_init( const char * const serverdir ) {
if( serverdir && chdir( serverdir ) ) {
fprintf( stderr, "Could not chdir() to %s\n", serverdir );
fprintf( stderr, "Could not chdir() to %s, because %s\n", serverdir, strerror(errno) );
return -1;
}
srandom( time(NULL) );
g_tracker_id = random();
/* Initialise background worker threads */
mutex_init( );
clean_init( );
fullscrape_init( );
#ifdef WANT_TRACKER_SYNC
accesslist_init( );
livesync_init( );
sync_init( );
#endif
stats_init( );
return 0;
}
@ -349,9 +375,9 @@ void trackerlogic_deinit( void ) {
/* Deinitialise background worker threads */
stats_deinit( );
#ifdef WANT_TRACKER_SYNC
sync_deinit( );
#endif
livesync_init( );
accesslist_init( );
fullscrape_deinit( );
clean_deinit( );
mutex_deinit( );

@ -43,6 +43,11 @@ typedef time_t ot_time;
/* From opentracker.c */
extern time_t g_now;
#define NOW (g_now/OT_POOLS_TIMEOUT)
extern uint32_t g_tracker_id;
typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA } PROTO_FLAG;
/* Try to bind to ip:port pair. May call exit() on failure */
int64_t ot_try_bind( char ip[4], uint16_t port, PROTO_FLAG proto );
typedef struct {
uint8_t data[8];
@ -50,6 +55,7 @@ typedef struct {
static const uint8_t PEER_FLAG_SEEDING = 0x80;
static const uint8_t PEER_FLAG_COMPLETED = 0x40;
static const uint8_t PEER_FLAG_STOPPED = 0x20;
static const uint8_t PEER_FLAG_LEECHING = 0x00;
#define OT_SETIP( peer, ip ) memmove((peer),(ip),4);
#define OT_SETPORT( peer, port ) memmove(((uint8_t*)peer)+4,(port),2);
@ -74,7 +80,7 @@ struct ot_peerlist {
size_t down_count;
size_t seed_counts[ OT_POOLS_COUNT ];
ot_vector peers[ OT_POOLS_COUNT ];
#ifdef WANT_TRACKER_SYNC
#ifdef WANT_SYNC_BATCH
ot_vector changeset;
#endif
};
@ -83,18 +89,23 @@ struct ot_peerlist {
Exported functions
*/
#ifdef WANT_TRACKER_SYNC
#define WANT_TRACKER_SYNC_PARAM( param ) , param
#if defined( WANT_SYNC_BATCH ) || defined( WANT_SYNC_LIVE )
#define WANT_SYNC
#endif
#ifdef WANT_SYNC
#define WANT_SYNC_PARAM( param ) , param
#else
#define WANT_TRACKER_SYNC_PARAM( param )
#define WANT_SYNC_PARAM( param )
#endif
int trackerlogic_init( const char * const serverdir );
void trackerlogic_deinit( void );
void exerr( char * message );
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC_PARAM( int from_changeset ) );
size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp );
size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int is_tcp );
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_changeset ) );
size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto );
size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, PROTO_FLAG proto );
size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply );
size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply );

Loading…
Cancel
Save