FEATURES=-DWANT_IP_FROM_QUERY_STRING #-DWANT_BLACKLIST -DWANT_CLOSED_TRACKER
#DEBUG_OPTS=-g -ggdb -pg # -fprofile-arcs -ftest-coverage
DEBUG_OPTS=-s -Os
-CFLAGS+=-I../libowfat -Wall -pipe
+CFLAGS+=-I../libowfat -Wall -pipe # -pedantic -ansi
LDFLAGS+=-L../libowfat/ -lowfat -lm
HEADERS=trackerlogic.h scan_urlencoded_query.h
#include "socket.h"
#include "io.h"
#include "buffer.h"
-#include "ip6.h"
#include "array.h"
+#include "byte.h"
#include "case.h"
#include "fmt.h"
#include "str.h"
#include "trackerlogic.h"
#include "scan_urlencoded_query.h"
-unsigned long const OT_CLIENT_TIMEOUT = 15;
-unsigned long const OT_CLIENT_TIMEOUT_CHECKINTERVAL = 5;
+unsigned int const OT_CLIENT_TIMEOUT = 15;
+unsigned int const OT_CLIENT_TIMEOUT_CHECKINTERVAL = 5;
static unsigned int ot_overall_connections = 0;
static time_t ot_start_time;
-static const unsigned int SUCCESS_HTTP_HEADER_LENGTH = 80;
-static const unsigned int SUCCESS_HTTP_SIZE_OFF = 17;
-// To always have space for error messages
+static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80;
+static const size_t SUCCESS_HTTP_SIZE_OFF = 17;
+/* To always have space for error messages ;) */
static char static_reply[8192];
static void carp(const char* routine) {
struct http_data {
array r;
- unsigned long ip;
+ unsigned char ip[4];
};
int header_complete(struct http_data* r) {
- long l = array_bytes(&r->r);
+ int l = array_bytes(&r->r), i;
const char* c = array_start(&r->r);
- long i;
for (i=0; i+1<l; ++i) {
if (c[i]=='\n' && c[i+1]=='\n') return i+2;
return 0;
}
-// whoever sends data is not interested in its input-array
+/* whoever sends data is not interested in its input-array */
void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) {
size_t written_size;
if( ( written_size < 0 ) || ( written_size == size ) ) {
free(h); io_close( s );
} else {
- // here we would take a copy of the buffer and remember it
+ /* here we would take a copy of the buffer and remember it */
fprintf( stderr, "Should have handled this.\n" );
free(h); io_close( s );
}
senddata(s,h,static_reply,reply_size);
}
-// bestimmten http parameter auslesen und adresse zurueckgeben
const char* http_header(struct http_data* r,const char* h) {
- long i;
-
- long l = array_bytes(&r->r);
- long sl = strlen(h);
- const char* c = array_start(&r->r);
-
- for (i=0; i+sl+2<l; ++i)
- {
- if (c[i]=='\n' && case_equalb(c+i+1,sl,h) && c[i+sl+1]==':')
- {
- c+=i+sl+1;
- if (*c==' ' || *c=='\t') ++c;
- return c;
- }
- return 0;
+ int i, l = array_bytes(&r->r);
+ int sl = strlen(h);
+ const char* c = array_start(&r->r);
+
+ for (i=0; i+sl+2<l; ++i) {
+ if (c[i]=='\n' && case_equalb(c+i+1,sl,h) && c[i+sl+1]==':') {
+ c+=i+sl+1;
+ if (*c==' ' || *c=='\t') ++c;
+ return c;
}
return 0;
+ }
+ return 0;
}
void httpresponse(int64 s,struct http_data* h)
{
- char *c, *data; // must be enough
- ot_peer peer;
- ot_torrent *torrent;
- ot_hash *hash = NULL;
- int numwant, tmp, scanon;
- unsigned short port = htons(6881);
- size_t reply_size = 0;
-
- array_cat0(&h->r);
- c = array_start(&h->r);
-
- if (byte_diff(c,4,"GET ")) {
+ char *c, *data;
+ ot_peer peer;
+ ot_torrent *torrent;
+ ot_hash *hash = NULL;
+ int numwant, tmp, scanon;
+ unsigned short port = htons(6881);
+ size_t reply_size = 0;
+
+ array_cat0(&h->r);
+ c = array_start(&h->r);
+
+ if (byte_diff(c,4,"GET ")) {
e400:
- return httperror(s,h,"400 Invalid Request","This server only understands GET.");
- }
-
- c+=4;
- for (data=c; *data!=' '&&*data!='\t'&&*data!='\n'&&*data!='\r'; ++data) ;
-
- if (*data!=' ') goto e400;
- *data=0;
- if (c[0]!='/') goto e404;
- while (*c=='/') ++c;
+ return httperror(s,h,"400 Invalid Request","This server only understands GET.");
+ }
- switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) )
- {
- case 6: /* scrape ? */
- if (byte_diff(data,6,"scrape"))
+ c+=4;
+ for (data=c; *data!=' '&&*data!='\t'&&*data!='\n'&&*data!='\r'; ++data) ;
+
+ if (*data!=' ') goto e400;
+ *data=0;
+ if (c[0]!='/') goto e404;
+ while (*c=='/') ++c;
+
+ switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) {
+ case 6: /* scrape ? */
+ if (byte_diff(data,6,"scrape"))
+ goto e404;
+ scanon = 1;
+
+ while( scanon ) {
+ switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
+ case -2: /* terminator */
+ scanon = 0;
+ break;
+ case -1: /* error */
goto e404;
- scanon = 1;
-
- while( scanon ) {
- switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
- case -2: /* terminator */
- scanon = 0;
- break;
- case -1: /* error */
- goto e404;
- case 9:
- if(byte_diff(data,9,"info_hash")) {
- scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
- continue;
- }
- /* ignore this, when we have less than 20 bytes */
- if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) {
-e400_param:
- return httperror(s,h,"400 Invalid Request","Invalid parameter");
- }
- hash = (ot_hash*)data; /* Fall through intended */
- break;
- default:
+ case 9:
+ if(byte_diff(data,9,"info_hash")) {
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
- break;
+ continue;
+ }
+ /* ignore this, when we have less than 20 bytes */
+ if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) {
+e400_param:
+ return httperror(s,h,"400 Invalid Request","Invalid parameter");
}
+ hash = (ot_hash*)data; /* Fall through intended */
+ break;
+ default:
+ scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ break;
}
+ }
- /* Scanned whole query string, wo */
- if( !hash )
- return httperror(s,h,"400 Invalid Request","This server only serves specific scrapes.");
-
- // Enough for http header + whole scrape string
- if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 )
- goto e500;
- break;
- case 8:
- if( byte_diff(data,8,"announce"))
+ /* Scanned whole query string, wo */
+ if( !hash )
+ return httperror(s,h,"400 Invalid Request","This server only serves specific scrapes.");
+
+ /* Enough for http header + whole scrape string */
+ if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 )
+ goto e500;
+ break;
+ case 8:
+ if( byte_diff(data,8,"announce"))
+ goto e404;
+
+ OT_SETIP( &peer, h->ip);
+ OT_SETPORT( &peer, &port );
+ OT_FLAG( &peer ) = 0;
+ numwant = 50;
+ scanon = 1;
+
+ while( scanon ) {
+ switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
+ case -2: /* terminator */
+ scanon = 0;
+ break;
+ case -1: /* error */
goto e404;
-
- OT_SETIP( &peer, &h->ip);
- OT_SETPORT( &peer, &port );
- OT_FLAG( &peer ) = 0;
- numwant = 50;
- scanon = 1;
-
- while( scanon ) {
- switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
- case -2: /* terminator */
- scanon = 0;
- break;
- case -1: /* error */
- goto e404;
#ifdef WANT_IP_FROM_QUERY_STRING
- case 2:
- if(!byte_diff(data,2,"ip")) {
- size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
- unsigned char ip[4];
- if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) goto e400_param;
- OT_SETIP ( &peer, ip );
- } else
- scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
- break;
+ case 2:
+ if(!byte_diff(data,2,"ip")) {
+ size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
+ unsigned char ip[4];
+ if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) goto e400_param;
+ OT_SETIP ( &peer, ip );
+ } else
+ scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ break;
#endif
- case 4:
- if(!byte_diff(data,4,"port")) {
- size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
- if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) goto e400_param;
- port = htons( tmp ); OT_SETPORT ( &peer, &port );
- } else if(!byte_diff(data,4,"left")) {
- size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
- if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param;
- if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING;
- } else
- scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
- break;
- case 5:
- if(byte_diff(data,5,"event"))
- scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
- else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) {
- case -1:
- goto e400_param;
- case 7:
- if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED;
- break;
- case 9:
- if(!byte_diff(data,9,"complete")) OT_FLAG( &peer ) |= PEER_FLAG_COMPLETED;
- default: // Fall through intended
- break;
- }
- break;
+ case 4:
+ if(!byte_diff(data,4,"port")) {
+ size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
+ if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) goto e400_param;
+ port = htons( tmp ); OT_SETPORT ( &peer, &port );
+ } else if(!byte_diff(data,4,"left")) {
+ size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
+ if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param;
+ if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING;
+ } else
+ scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ break;
+ case 5:
+ if(byte_diff(data,5,"event"))
+ scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) {
+ case -1:
+ goto e400_param;
case 7:
- if(!byte_diff(data,7,"numwant")) {
- size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
- if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) goto e400_param;
- if( numwant > 200 ) numwant = 200;
- } else if(!byte_diff(data,7,"compact")) {
- size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
- if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param;
- if( !tmp )
- return httperror(s,h,"400 Invalid Request","This server only delivers compact results.");
- } else
- scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED;
break;
case 9:
- if(byte_diff(data,9,"info_hash")) {
- scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
- continue;
- }
- /* ignore this, when we have less than 20 bytes */
- if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 )
- goto e400;
- hash = (ot_hash*)data;
+ if(!byte_diff(data,9,"complete")) OT_FLAG( &peer ) |= PEER_FLAG_COMPLETED;
+ default: /* Fall through intended */
break;
- default:
+ }
+ break;
+ case 7:
+ if(!byte_diff(data,7,"numwant")) {
+ size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
+ if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) goto e400_param;
+ if( numwant > 200 ) numwant = 200;
+ } else if(!byte_diff(data,7,"compact")) {
+ size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
+ if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param;
+ if( !tmp )
+ return httperror(s,h,"400 Invalid Request","This server only delivers compact results.");
+ } else
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
- break;
+ break;
+ case 9:
+ if(byte_diff(data,9,"info_hash")) {
+ scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ continue;
}
+ /* ignore this, when we have less than 20 bytes */
+ if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 )
+ goto e400;
+ hash = (ot_hash*)data;
+ break;
+ default:
+ scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ break;
}
+ }
- /* Scanned whole query string */
- if( !hash ) goto e400;
+ /* Scanned whole query string */
+ if( !hash ) goto e400;
- if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) {
- remove_peer_from_torrent( hash, &peer );
- MEMMOVE( static_reply + SUCCESS_HTTP_HEADER_LENGTH, "d15:warning message4:Okaye", reply_size = 26 );
- } else {
- torrent = add_peer_to_torrent( hash, &peer );
- if( !torrent ) {
+ if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) {
+ remove_peer_from_torrent( hash, &peer );
+ memmove( static_reply + SUCCESS_HTTP_HEADER_LENGTH, "d15:warning message4:Okaye", reply_size = 26 );
+ } else {
+ torrent = add_peer_to_torrent( hash, &peer );
+ if( !torrent ) {
e500:
- return httperror(s,h,"500 Internal Server Error","A server error has occured. Please retry later.");
- }
- if( ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 )
- goto e500;
+ return httperror(s,h,"500 Internal Server Error","A server error has occured. Please retry later.");
}
- break;
- case 11:
- if( byte_diff(data,11,"mrtg_scrape"))
- goto e404;
- {
- unsigned long seconds_elapsed = time( NULL ) - ot_start_time;
- reply_size = sprintf( static_reply + SUCCESS_HTTP_HEADER_LENGTH,
- "%d\n%d\nUp: %ld seconds (%ld hours)\nPretuned by german engineers, currently handling %li connections per second.",
- ot_overall_connections, ot_overall_connections, seconds_elapsed,
- seconds_elapsed / 3600, ot_overall_connections / ( seconds_elapsed ? seconds_elapsed : 1 ) );
- }
- break;
- default: /* neither *scrape nor announce */
-e404:
- return httperror(s,h,"404 Not Found","No such file or directory.");
+ if( ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 )
+ goto e500;
}
-
- if( reply_size ) {
- size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_reply, 0, "%zd", reply_size );
- reply_size += 1 + sprintf( static_reply + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size );
- static_reply[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n';
- senddata( s, h, static_reply + reply_off, reply_size );
- } else {
- if( h ) array_reset(&h->r);
- free( h ); io_close( s );
+ break;
+ case 11:
+ if( byte_diff(data,11,"mrtg_scrape"))
+ goto e404;
+ {
+ time_t seconds_elapsed = time( NULL ) - ot_start_time;
+ reply_size = sprintf( static_reply + SUCCESS_HTTP_HEADER_LENGTH,
+ "%d\n%d\nUp: %ld seconds (%ld hours)\nPretuned by german engineers, currently handling %li connections per second.",
+ ot_overall_connections, ot_overall_connections, seconds_elapsed,
+ seconds_elapsed / 3600, ot_overall_connections / ( seconds_elapsed ? seconds_elapsed : 1 ) );
}
+ break;
+ default: /* neither *scrape nor announce */
+e404:
+ return httperror(s,h,"404 Not Found","No such file or directory.");
+ }
+
+ if( reply_size ) {
+ /* This one is rather ugly, so I take you step by step through it.
+
+ 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to
+ write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string
+ plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate
+ the space NOT needed to expand in reply_off
+ */
+ size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_reply, 0, "%zd", reply_size );
+
+ /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete
+ packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */
+ reply_size += 1 + sprintf( static_reply + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size );
+
+ /* 3. Finally we join both blocks neatly */
+ static_reply[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n';
+
+ senddata( s, h, static_reply + reply_off, reply_size );
+ } else {
+ if( h ) array_reset(&h->r);
+ free( h ); io_close( s );
+ }
}
void graceful( int s ) {
int main( int argc, char **argv ) {
int s=socket_tcp4();
tai6464 t, next_timeout_check;
- unsigned long ip;
char *serverip = NULL;
char *serverdir = ".";
uint16 port = 6969;
+ unsigned char ip[4];
while( 1 ) {
switch( getopt(argc,argv,":i:p:d:ocbBh") ) {
}
while( ( i = io_canread() ) != -1 ) {
- if( i == s ) { // ist es der serversocket?
+ if( i == s ) {
int n;
- while( ( n = socket_accept4( s, (void*)&ip, &port) ) != -1 ) {
+ while( ( n = socket_accept4( s, (char*)ip, &port) ) != -1 ) {
if( io_fd( n ) ) {
struct http_data* h=(struct http_data*)malloc(sizeof(struct http_data));
io_wantread(n);
if (h) {
byte_zero(h,sizeof(struct http_data));
- h->ip=ip;
+ memmove(h->ip,ip,sizeof(ip));
taia_now(&t);
taia_addsec(&t,&t,OT_CLIENT_TIMEOUT);
io_timeout(n,t);
else
carp("socket_accept4");
} else {
- char buf[8192];
+ /* unsigned (sic!) */ char buf[8192];
struct http_data* h=io_getcookie(i);
int l=io_tryread(i,buf,sizeof buf);
#include "scan.h"
#include "scan_urlencoded_query.h"
-// Idea is to do a in place replacement or guarantee at least
-// strlen( string ) bytes in deststring
-// watch http://www.ietf.org/rfc/rfc2396.txt
-// unreserved = alphanum | mark
-// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
-// we add '%' to the matrix to not stop at encoded chars.
-
+/* Idea is to do a in place replacement or guarantee at least
+ strlen( string ) bytes in deststring
+ watch http://www.ietf.org/rfc/rfc2396.txt
+ unreserved = alphanum | mark
+ mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+ we add '%' to the matrix to not stop at encoded chars.
+*/
static const unsigned char reserved_matrix[] = { 0xA2, 0x63, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x47};
-inline int is_unreserved( unsigned char c ) {
+static int is_unreserved( unsigned char c ) {
if( ( c <= 32 ) || ( c >= 127 ) ) return 0; return 1&(reserved_matrix[(c-32)>>3]>>(c&7));
}
#define SCAN_SEARCHPATH_PARAM 1
#define SCAN_SEARCHPATH_VALUE 2
-// string pointer to source, pointer to after terminator on return
-// deststring pointer to destination
-// flags determines, what to parse
-// returns number of valid converted characters in deststring
-// or -1 for parse error
+/* string pointer to source, pointer to after terminator on return
+ deststring pointer to destination
+ flags determines, what to parse
+ returns number of valid converted characters in deststring
+ or -1 for parse error
+*/
size_t scan_urlencoded_query(char **string, char *deststring, int flags);
-// data pointer to len chars of string
-// len length of chars in data to parse
-// number number to receive result
-// returns number of bytes not parsed, mostly !=0 means fail
+/* data pointer to len chars of string
+ len length of chars in data to parse
+ number number to receive result
+ returns number of bytes not parsed, mostly !=0 means fail
+*/
size_t scan_fixed_int( char *data, size_t len, int *number );
-// data pointer to len chars of string
-// len length of chars in data to parse
-// ip buffer to receive result
-// returns number of bytes not parsed, mostly !=0 means fail
+/* data pointer to len chars of string
+ len length of chars in data to parse
+ ip buffer to receive result
+ returns number of bytes not parsed, mostly !=0 means fail
+*/
size_t scan_fixed_ip( char *data, size_t len, unsigned char ip[4] );
#endif
#include <sys/stat.h>
#endif
-// GLOBAL VARIABLES
-//
+/* GLOBAL VARIABLES */
static ot_vector all_torrents[256];
#ifdef WANT_CLOSED_TRACKER
static ot_torrent* const OT_TORRENT_ON_BLACKLIST = (ot_torrent*)2;
#endif
-// This function gives us a binary search that returns a pointer, even if
-// no exact match is found. In that case it sets exactmatch 0 and gives
-// calling functions the chance to insert data
-//
-static void *binary_search( const void *key, const void *base, unsigned long member_count, const unsigned long member_size,
- int compare_size, int *exactmatch ) {
+/* This function gives us a binary search that returns a pointer, even if
+ no exact match is found. In that case it sets exactmatch 0 and gives
+ calling functions the chance to insert data
+*/
+static void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size,
+ size_t compare_size, int *exactmatch ) {
+ size_t mc = member_count;
ot_byte *lookat = ((ot_byte*)base) + member_size * (member_count >> 1);
*exactmatch = 1;
- while( member_count ) {
+ while( mc ) {
int cmp = memcmp( lookat, key, compare_size);
if (cmp == 0) return (void *)lookat;
if (cmp < 0) {
base = (void*)(lookat + member_size);
- --member_count;
+ --mc;
}
- member_count >>= 1;
- lookat = ((ot_byte*)base) + member_size * (member_count >> 1);
+ mc >>= 1;
+ lookat = ((ot_byte*)base) + member_size * (mc >> 1);
}
*exactmatch = 0;
return (void*)lookat;
}
-// Converter function from memory to human readable hex strings
-// * definitely not thread safe!!!
-//
+/* Converter function from memory to human readable hex strings
+ - definitely not thread safe!!!
+*/
char ths[2+2*20]="-";char*to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+41;char*t=ths+1;while(t<e){*t++=m[*s>>4];*t++=m[*s++&15];}*t=0;return ths+1;}
static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, int compare_size, int *exactmatch ) {
- ot_byte *match = BINARY_FIND( key, vector->data, vector->size, member_size, compare_size, exactmatch );
+ ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch );
if( *exactmatch ) return match;
ot_byte *new_data = realloc( vector->data, new_space * member_size );
if( !new_data ) return NULL;
- // Adjust pointer if it moved by realloc
+ /* Adjust pointer if it moved by realloc */
match = new_data + (match - (ot_byte*)vector->data);
vector->data = new_data;
vector->space = new_space;
}
- MEMMOVE( match + member_size, match, ((ot_byte*)vector->data) + member_size * vector->size - match );
+ memmove( match + member_size, match, ((ot_byte*)vector->data) + member_size * vector->size - match );
vector->size++;
return match;
}
ot_peer *match;
if( !vector->size ) return 0;
- match = BINARY_FIND( peer, vector->data, vector->size, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch );
+ match = binary_search( peer, vector->data, vector->size, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch );
if( !exactmatch ) return 0;
exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1;
- MEMMOVE( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) );
+ memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) );
if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) {
vector->space /= OT_VECTOR_SHRINK_RATIO;
vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) );
ot_torrent *match;
if( !vector->size ) return 0;
- match = BINARY_FIND( hash, vector->data, vector->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
+ match = binary_search( hash, vector->data, vector->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
if( !exactmatch ) return 0;
- // If this is being called after a unsuccessful malloc() for peer_list
- // in add_peer_to_torrent, match->peer_list actually might be NULL
+ /* If this is being called after a unsuccessful malloc() for peer_list
+ in add_peer_to_torrent, match->peer_list actually might be NULL */
if( match->peer_list) free_peerlist( match->peer_list );
- MEMMOVE( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) );
+ memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) );
if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) {
vector->space /= OT_VECTOR_SHRINK_RATIO;
vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) );
return 1;
}
-// Returns 1, if torrent is gone, 0 otherwise
+/* Returns 1, if torrent is gone, 0 otherwise */
static int clean_peerlist( ot_peerlist *peer_list ) {
- long timedout = NOW-peer_list->base;
- int i;
+ int i, timedout = (int)( NOW - peer_list->base );
if( !timedout ) return 0;
if( timedout > OT_POOLS_COUNT ) timedout = OT_POOLS_COUNT;
- for( i=OT_POOLS_COUNT-timedout; i<OT_POOLS_COUNT; ++i )
+ for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i )
free( peer_list->peers[i].data);
- MEMMOVE( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * (OT_POOLS_COUNT-timedout) );
+ memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * (OT_POOLS_COUNT-timedout) );
byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout );
- MEMMOVE( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( unsigned long ) * (OT_POOLS_COUNT-timedout) );
- byte_zero( peer_list->seed_count, sizeof( unsigned long ) * timedout );
+ memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout) );
+ byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout );
peer_list->base = NOW;
return timedout == OT_POOLS_COUNT;
if( !torrent ) return NULL;
if( !exactmatch ) {
- // Create a new torrent entry, then
- MEMMOVE( &torrent->hash, hash, sizeof( ot_hash ) );
+ /* Create a new torrent entry, then */
+ memmove( &torrent->hash, hash, sizeof( ot_hash ) );
torrent->peer_list = malloc( sizeof (ot_peerlist) );
if( !torrent->peer_list ) {
peer_pool = &torrent->peer_list->peers[0];
peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch );
- // If we hadn't had a match in current pool, create peer there and
- // remove it from all older pools
+ /* If we hadn't had a match in current pool, create peer there and
+ remove it from all older pools */
if( !exactmatch ) {
int i;
- MEMMOVE( peer_dest, peer, sizeof( ot_peer ) );
+ memmove( peer_dest, peer, sizeof( ot_peer ) );
if( OT_FLAG(peer) & PEER_FLAG_SEEDING )
torrent->peer_list->seed_count[0]++;
for( i=1; i<OT_POOLS_COUNT; ++i ) {
return torrent;
}
-// Compiles a list of random peers for a torrent
-// * reply must have enough space to hold 24+6*amount bytes
-// * Selector function can be anything, maybe test for seeds, etc.
-// * RANDOM may return huge values
-// * does not yet check not to return self
-//
-size_t return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char *reply ) {
- char *r = reply;
- unsigned long peer_count, seed_count, index;
- signed long pool_offset = -1, pool_index = 0;
- signed long wert = -1;
+/* Compiles a list of random peers for a torrent
+ * reply must have enough space to hold 24+6*amount bytes
+ * Selector function can be anything, maybe test for seeds, etc.
+ * RANDOM may return huge values
+ * does not yet check not to return self
+*/
+size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char *reply ) {
+ char *r = reply;
+ unsigned int peer_count, seed_count, index;
+ int pool_offset = -1, pool_index = 0, wert = -1;
#ifdef WANT_CLOSED_TRACKER
if( torrent == OT_TORRENT_NOT_ON_WHITELIST ) {
- return( FORMAT_FORMAT_STRING( reply, "d14:failure reason43:This torrent is not served by this tracker.e" ) );
+ const char * const notvalid = "d14:failure reason43:This torrent is not served by this tracker.e";
+ memmove( reply, notvalid, sizeof(notvalid));
+ return sizeof(notvalid);
}
#endif
#ifdef WANT_BLACKLIST
if( torrent == OT_TORRENT_ON_BLACKLIST ) {
- return( FORMAT_FORMAT_STRING( reply, "d14:failure reason29:This torrent is black listed.e" ) );
+ const char * const blacklisted = "d14:failure reason29:This torrent is black listed.e";
+ memmove( reply, blacklisted, sizeof(blacklisted));
+ return sizeof(blacklisted);
}
#endif
}
if( peer_count < amount ) amount = peer_count;
- r += FORMAT_FORMAT_STRING( r, "d8:completei%lie10:incompletei%lie8:intervali600e5:peers%li:", seed_count, peer_count-seed_count, 6*amount );
+ r += sprintf( r, "d8:completei%ie10:incompletei%ie8:intervali600e5:peers%i:", seed_count, peer_count-seed_count, 6*amount );
for( index = 0; index < amount; ++index ) {
double step = 1.8*((double)( peer_count - wert - 1 ))/((double)( amount - index ));
int off = random() % (int)floor( step );
off = 1 + ( off % ( peer_count - wert - 1 ));
wert += off; pool_offset += off;
- // In some rare occasions random gets the last peer a round to early
- // correct that and return last peer twice
- // if( wert >= peer_count ) { wert--; pool_offset--; }
-
while( pool_offset >= torrent->peer_list->peers[pool_index].size ) {
pool_offset -= torrent->peer_list->peers[pool_index].size;
pool_index++;
}
- MEMMOVE( r, ((ot_peer*)torrent->peer_list->peers[pool_index].data) + pool_offset, 6 );
+ memmove( r, ((ot_peer*)torrent->peer_list->peers[pool_index].data) + pool_offset, 6 );
r += 6;
}
*r++ = 'e';
return r - reply;
}
-// Fetches scrape info for a specific torrent
+/* Fetches scrape info for a specific torrent */
size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) {
char *r = reply;
int exactmatch, peers = 0, seeds = 0, i;
ot_vector *torrents_list = &all_torrents[*hash[0]];
- ot_torrent *torrent = BINARY_FIND( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
+ ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
if( !exactmatch ) return 0;
clean_peerlist( torrent->peer_list );
seeds += torrent->peer_list->seed_count[i];
}
- MEMMOVE( r, "d5:filesd20:", 12 ); MEMMOVE( r+12, hash, 20 );
- r += FORMAT_FORMAT_STRING( r+32, "d8:completei%de10:downloadedi%lde10:incompletei%deeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32;
+ memmove( r, "d5:filesd20:", 12 ); memmove( r+12, hash, 20 );
+ r += sprintf( r+32, "d8:completei%de10:downloadedi%de10:incompletei%deeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32;
return r - reply;
}
void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) {
int exactmatch, i;
ot_vector *torrents_list = &all_torrents[*hash[0]];
- ot_torrent *torrent = BINARY_FIND( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
+ ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
if( !exactmatch ) return;
- // Maybe this does the job
+ /* Maybe this does the job */
if( clean_peerlist( torrent->peer_list ) ) {
#ifdef WANT_CLOSED_TRACKER
if( !g_closedtracker )
srandom( time(NULL));
- // Initialize control structures
+ /* Initialize control structures */
byte_zero( all_torrents, sizeof (all_torrents));
return 0;
void deinit_logic( ) {
int i, j;
- // Free all torrents...
+
+ /* Free all torrents... */
for(i=0; i<256; ++i ) {
if( all_torrents[i].size ) {
ot_torrent *torrents_list = (ot_torrent*)all_torrents[i].data;
typedef ot_dword ot_ip;
typedef time_t ot_time;
-#define MEMMOVE memmove
-#define BZERO bzero
-#define FORMAT_FIXED_STRING sprintf
-#define FORMAT_FORMAT_STRING sprintf
-#define BINARY_FIND binary_search
+/* We maintain a list of 256 pointers to sorted list of ot_torrent structs
+ Sort key is, of course, its hash */
-// We maintain a list of 256 pointers to sorted list of ot_torrent structs
-// Sort key is, of course, its hash
-
-// This list points to 9 pools of peers each grouped in five-minute-intervals
-// thus achieving a timeout of 2700s or 45 minutes
-// These pools are sorted by its binary content
+/* This list points to 9 pools of peers each grouped in five-minute-intervals
+ thus achieving a timeout of 2700s or 45 minutes
+ These pools are sorted by its binary content */
#define OT_POOLS_COUNT 9
#define OT_POOLS_TIMEOUT 300
static const ot_byte PEER_FLAG_COMPLETED = 0x40;
static const ot_byte PEER_FLAG_STOPPED = 0x20;
-#define OT_SETIP( peer, ip ) MEMMOVE((peer),(ip),4);
-#define OT_SETPORT( peer, port ) MEMMOVE(((ot_byte*)peer)+4,(port),2);
+#define OT_SETIP( peer, ip ) memmove((peer),(ip),4);
+#define OT_SETPORT( peer, port ) memmove(((ot_byte*)peer)+4,(port),2);
#define OT_FLAG(peer) (((ot_byte*)(peer))[6])
#define OT_PEER_COMPARE_SIZE ((size_t)6)
typedef struct {
ot_time base;
- unsigned long seed_count[ OT_POOLS_COUNT ];
- unsigned long downloaded;
+ size_t seed_count[ OT_POOLS_COUNT ];
+ unsigned int downloaded;
ot_vector peers[ OT_POOLS_COUNT ];
} ot_peerlist;
ot_peerlist *peer_list;
} ot_torrent;
-//
-// Exported functions
-//
+/*
+ Exported functions
+*/
int init_logic( char *serverdir );
void deinit_logic( );
#endif
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer );
-size_t return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char *reply );
+size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char *reply );
size_t return_scrape_for_torrent( ot_hash *hash, char *reply );
void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer );
void cleanup_torrents( void );