mirror of
git://erdgeist.org/opentracker
synced 2025-02-05 03:26:25 +00:00
Documentation improved, some reindenting (again), variable types checked, unnecessary defines removed
This commit is contained in:
parent
cb12e922d5
commit
805e46450c
2
Makefile
2
Makefile
@ -2,7 +2,7 @@ CC?=gcc
|
|||||||
FEATURES=-DWANT_IP_FROM_QUERY_STRING #-DWANT_BLACKLIST -DWANT_CLOSED_TRACKER
|
FEATURES=-DWANT_IP_FROM_QUERY_STRING #-DWANT_BLACKLIST -DWANT_CLOSED_TRACKER
|
||||||
#DEBUG_OPTS=-g -ggdb -pg # -fprofile-arcs -ftest-coverage
|
#DEBUG_OPTS=-g -ggdb -pg # -fprofile-arcs -ftest-coverage
|
||||||
DEBUG_OPTS=-s -Os
|
DEBUG_OPTS=-s -Os
|
||||||
CFLAGS+=-I../libowfat -Wall -pipe
|
CFLAGS+=-I../libowfat -Wall -pipe # -pedantic -ansi
|
||||||
LDFLAGS+=-L../libowfat/ -lowfat -lm
|
LDFLAGS+=-L../libowfat/ -lowfat -lm
|
||||||
|
|
||||||
HEADERS=trackerlogic.h scan_urlencoded_query.h
|
HEADERS=trackerlogic.h scan_urlencoded_query.h
|
||||||
|
394
opentracker.c
394
opentracker.c
@ -6,8 +6,8 @@
|
|||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "ip6.h"
|
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
#include "byte.h"
|
||||||
#include "case.h"
|
#include "case.h"
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
@ -25,14 +25,14 @@
|
|||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
#include "scan_urlencoded_query.h"
|
#include "scan_urlencoded_query.h"
|
||||||
|
|
||||||
unsigned long const OT_CLIENT_TIMEOUT = 15;
|
unsigned int const OT_CLIENT_TIMEOUT = 15;
|
||||||
unsigned long const OT_CLIENT_TIMEOUT_CHECKINTERVAL = 5;
|
unsigned int const OT_CLIENT_TIMEOUT_CHECKINTERVAL = 5;
|
||||||
|
|
||||||
static unsigned int ot_overall_connections = 0;
|
static unsigned int ot_overall_connections = 0;
|
||||||
static time_t ot_start_time;
|
static time_t ot_start_time;
|
||||||
static const unsigned int SUCCESS_HTTP_HEADER_LENGTH = 80;
|
static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80;
|
||||||
static const unsigned int SUCCESS_HTTP_SIZE_OFF = 17;
|
static const size_t SUCCESS_HTTP_SIZE_OFF = 17;
|
||||||
// To always have space for error messages
|
/* To always have space for error messages ;) */
|
||||||
static char static_reply[8192];
|
static char static_reply[8192];
|
||||||
|
|
||||||
static void carp(const char* routine) {
|
static void carp(const char* routine) {
|
||||||
@ -49,13 +49,12 @@ static void panic(const char* routine) {
|
|||||||
|
|
||||||
struct http_data {
|
struct http_data {
|
||||||
array r;
|
array r;
|
||||||
unsigned long ip;
|
unsigned char ip[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
int header_complete(struct http_data* r) {
|
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);
|
const char* c = array_start(&r->r);
|
||||||
long i;
|
|
||||||
|
|
||||||
for (i=0; i+1<l; ++i) {
|
for (i=0; i+1<l; ++i) {
|
||||||
if (c[i]=='\n' && c[i+1]=='\n') return i+2;
|
if (c[i]=='\n' && c[i+1]=='\n') return i+2;
|
||||||
@ -64,7 +63,7 @@ int header_complete(struct http_data* r) {
|
|||||||
return 0;
|
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 ) {
|
void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) {
|
||||||
size_t written_size;
|
size_t written_size;
|
||||||
|
|
||||||
@ -73,7 +72,7 @@ void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) {
|
|||||||
if( ( written_size < 0 ) || ( written_size == size ) ) {
|
if( ( written_size < 0 ) || ( written_size == size ) ) {
|
||||||
free(h); io_close( s );
|
free(h); io_close( s );
|
||||||
} else {
|
} 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" );
|
fprintf( stderr, "Should have handled this.\n" );
|
||||||
free(h); io_close( s );
|
free(h); io_close( s );
|
||||||
}
|
}
|
||||||
@ -85,218 +84,225 @@ void httperror(int64 s,struct http_data* h,const char* title,const char* message
|
|||||||
senddata(s,h,static_reply,reply_size);
|
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) {
|
const char* http_header(struct http_data* r,const char* h) {
|
||||||
long i;
|
int i, l = array_bytes(&r->r);
|
||||||
|
int sl = strlen(h);
|
||||||
|
const char* c = array_start(&r->r);
|
||||||
|
|
||||||
long l = array_bytes(&r->r);
|
for (i=0; i+sl+2<l; ++i) {
|
||||||
long sl = strlen(h);
|
if (c[i]=='\n' && case_equalb(c+i+1,sl,h) && c[i+sl+1]==':') {
|
||||||
const char* c = array_start(&r->r);
|
c+=i+sl+1;
|
||||||
|
if (*c==' ' || *c=='\t') ++c;
|
||||||
for (i=0; i+sl+2<l; ++i)
|
return c;
|
||||||
{
|
|
||||||
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;
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpresponse(int64 s,struct http_data* h)
|
void httpresponse(int64 s,struct http_data* h)
|
||||||
{
|
{
|
||||||
char *c, *data; // must be enough
|
char *c, *data;
|
||||||
ot_peer peer;
|
ot_peer peer;
|
||||||
ot_torrent *torrent;
|
ot_torrent *torrent;
|
||||||
ot_hash *hash = NULL;
|
ot_hash *hash = NULL;
|
||||||
int numwant, tmp, scanon;
|
int numwant, tmp, scanon;
|
||||||
unsigned short port = htons(6881);
|
unsigned short port = htons(6881);
|
||||||
size_t reply_size = 0;
|
size_t reply_size = 0;
|
||||||
|
|
||||||
array_cat0(&h->r);
|
array_cat0(&h->r);
|
||||||
c = array_start(&h->r);
|
c = array_start(&h->r);
|
||||||
|
|
||||||
if (byte_diff(c,4,"GET ")) {
|
if (byte_diff(c,4,"GET ")) {
|
||||||
e400:
|
e400:
|
||||||
return httperror(s,h,"400 Invalid Request","This server only understands GET.");
|
return httperror(s,h,"400 Invalid Request","This server only understands GET.");
|
||||||
}
|
}
|
||||||
|
|
||||||
c+=4;
|
c+=4;
|
||||||
for (data=c; *data!=' '&&*data!='\t'&&*data!='\n'&&*data!='\r'; ++data) ;
|
for (data=c; *data!=' '&&*data!='\t'&&*data!='\n'&&*data!='\r'; ++data) ;
|
||||||
|
|
||||||
if (*data!=' ') goto e400;
|
if (*data!=' ') goto e400;
|
||||||
*data=0;
|
*data=0;
|
||||||
if (c[0]!='/') goto e404;
|
if (c[0]!='/') goto e404;
|
||||||
while (*c=='/') ++c;
|
while (*c=='/') ++c;
|
||||||
|
|
||||||
switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) )
|
switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) {
|
||||||
{
|
case 6: /* scrape ? */
|
||||||
case 6: /* scrape ? */
|
if (byte_diff(data,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;
|
goto e404;
|
||||||
scanon = 1;
|
case 9:
|
||||||
|
if(byte_diff(data,9,"info_hash")) {
|
||||||
while( scanon ) {
|
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
||||||
switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
|
continue;
|
||||||
case -2: /* terminator */
|
}
|
||||||
scanon = 0;
|
/* ignore this, when we have less than 20 bytes */
|
||||||
break;
|
if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) {
|
||||||
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:
|
e400_param:
|
||||||
return httperror(s,h,"400 Invalid Request","Invalid parameter");
|
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;
|
|
||||||
}
|
}
|
||||||
|
hash = (ot_hash*)data; /* Fall through intended */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Scanned whole query string, wo */
|
/* Scanned whole query string, wo */
|
||||||
if( !hash )
|
if( !hash )
|
||||||
return httperror(s,h,"400 Invalid Request","This server only serves specific scrapes.");
|
return httperror(s,h,"400 Invalid Request","This server only serves specific scrapes.");
|
||||||
|
|
||||||
// Enough for http header + whole scrape string
|
/* Enough for http header + whole scrape string */
|
||||||
if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 )
|
if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 )
|
||||||
goto e500;
|
goto e500;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
if( byte_diff(data,8,"announce"))
|
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;
|
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
|
#ifdef WANT_IP_FROM_QUERY_STRING
|
||||||
case 2:
|
case 2:
|
||||||
if(!byte_diff(data,2,"ip")) {
|
if(!byte_diff(data,2,"ip")) {
|
||||||
size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
|
size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
|
||||||
unsigned char ip[4];
|
unsigned char ip[4];
|
||||||
if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) goto e400_param;
|
if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) goto e400_param;
|
||||||
OT_SETIP ( &peer, ip );
|
OT_SETIP ( &peer, ip );
|
||||||
} else
|
} else
|
||||||
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 4:
|
case 4:
|
||||||
if(!byte_diff(data,4,"port")) {
|
if(!byte_diff(data,4,"port")) {
|
||||||
size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
|
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;
|
if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) goto e400_param;
|
||||||
port = htons( tmp ); OT_SETPORT ( &peer, &port );
|
port = htons( tmp ); OT_SETPORT ( &peer, &port );
|
||||||
} else if(!byte_diff(data,4,"left")) {
|
} else if(!byte_diff(data,4,"left")) {
|
||||||
size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
|
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( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param;
|
||||||
if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING;
|
if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING;
|
||||||
} else
|
} else
|
||||||
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if(byte_diff(data,5,"event"))
|
if(byte_diff(data,5,"event"))
|
||||||
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
||||||
else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) {
|
else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) {
|
||||||
case -1:
|
case -1:
|
||||||
goto e400_param;
|
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 7:
|
case 7:
|
||||||
if(!byte_diff(data,7,"numwant")) {
|
if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED;
|
||||||
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:
|
case 9:
|
||||||
if(byte_diff(data,9,"info_hash")) {
|
if(!byte_diff(data,9,"complete")) OT_FLAG( &peer ) |= PEER_FLAG_COMPLETED;
|
||||||
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
default: /* Fall through intended */
|
||||||
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;
|
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 );
|
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
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 ) {
|
/* Scanned whole query string */
|
||||||
size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_reply, 0, "%zd", reply_size );
|
if( !hash ) goto e400;
|
||||||
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';
|
if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) {
|
||||||
senddata( s, h, static_reply + reply_off, reply_size );
|
remove_peer_from_torrent( hash, &peer );
|
||||||
|
memmove( static_reply + SUCCESS_HTTP_HEADER_LENGTH, "d15:warning message4:Okaye", reply_size = 26 );
|
||||||
} else {
|
} else {
|
||||||
if( h ) array_reset(&h->r);
|
torrent = add_peer_to_torrent( hash, &peer );
|
||||||
free( h ); io_close( s );
|
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;
|
||||||
}
|
}
|
||||||
|
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 ) {
|
void graceful( int s ) {
|
||||||
@ -346,10 +352,10 @@ void help( char *name ) {
|
|||||||
int main( int argc, char **argv ) {
|
int main( int argc, char **argv ) {
|
||||||
int s=socket_tcp4();
|
int s=socket_tcp4();
|
||||||
tai6464 t, next_timeout_check;
|
tai6464 t, next_timeout_check;
|
||||||
unsigned long ip;
|
|
||||||
char *serverip = NULL;
|
char *serverip = NULL;
|
||||||
char *serverdir = ".";
|
char *serverdir = ".";
|
||||||
uint16 port = 6969;
|
uint16 port = 6969;
|
||||||
|
unsigned char ip[4];
|
||||||
|
|
||||||
while( 1 ) {
|
while( 1 ) {
|
||||||
switch( getopt(argc,argv,":i:p:d:ocbBh") ) {
|
switch( getopt(argc,argv,":i:p:d:ocbBh") ) {
|
||||||
@ -412,16 +418,16 @@ allparsed:
|
|||||||
}
|
}
|
||||||
|
|
||||||
while( ( i = io_canread() ) != -1 ) {
|
while( ( i = io_canread() ) != -1 ) {
|
||||||
if( i == s ) { // ist es der serversocket?
|
if( i == s ) {
|
||||||
int n;
|
int n;
|
||||||
while( ( n = socket_accept4( s, (void*)&ip, &port) ) != -1 ) {
|
while( ( n = socket_accept4( s, (char*)ip, &port) ) != -1 ) {
|
||||||
if( io_fd( n ) ) {
|
if( io_fd( n ) ) {
|
||||||
struct http_data* h=(struct http_data*)malloc(sizeof(struct http_data));
|
struct http_data* h=(struct http_data*)malloc(sizeof(struct http_data));
|
||||||
io_wantread(n);
|
io_wantread(n);
|
||||||
|
|
||||||
if (h) {
|
if (h) {
|
||||||
byte_zero(h,sizeof(struct http_data));
|
byte_zero(h,sizeof(struct http_data));
|
||||||
h->ip=ip;
|
memmove(h->ip,ip,sizeof(ip));
|
||||||
taia_now(&t);
|
taia_now(&t);
|
||||||
taia_addsec(&t,&t,OT_CLIENT_TIMEOUT);
|
taia_addsec(&t,&t,OT_CLIENT_TIMEOUT);
|
||||||
io_timeout(n,t);
|
io_timeout(n,t);
|
||||||
@ -437,7 +443,7 @@ allparsed:
|
|||||||
else
|
else
|
||||||
carp("socket_accept4");
|
carp("socket_accept4");
|
||||||
} else {
|
} else {
|
||||||
char buf[8192];
|
/* unsigned (sic!) */ char buf[8192];
|
||||||
struct http_data* h=io_getcookie(i);
|
struct http_data* h=io_getcookie(i);
|
||||||
|
|
||||||
int l=io_tryread(i,buf,sizeof buf);
|
int l=io_tryread(i,buf,sizeof buf);
|
||||||
|
@ -4,15 +4,15 @@
|
|||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
#include "scan_urlencoded_query.h"
|
#include "scan_urlencoded_query.h"
|
||||||
|
|
||||||
// Idea is to do a in place replacement or guarantee at least
|
/* Idea is to do a in place replacement or guarantee at least
|
||||||
// strlen( string ) bytes in deststring
|
strlen( string ) bytes in deststring
|
||||||
// watch http://www.ietf.org/rfc/rfc2396.txt
|
watch http://www.ietf.org/rfc/rfc2396.txt
|
||||||
// unreserved = alphanum | mark
|
unreserved = alphanum | mark
|
||||||
// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
|
mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
|
||||||
// we add '%' to the matrix to not stop at encoded chars.
|
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};
|
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));
|
if( ( c <= 32 ) || ( c >= 127 ) ) return 0; return 1&(reserved_matrix[(c-32)>>3]>>(c&7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,23 +8,26 @@
|
|||||||
#define SCAN_SEARCHPATH_PARAM 1
|
#define SCAN_SEARCHPATH_PARAM 1
|
||||||
#define SCAN_SEARCHPATH_VALUE 2
|
#define SCAN_SEARCHPATH_VALUE 2
|
||||||
|
|
||||||
// string pointer to source, pointer to after terminator on return
|
/* string pointer to source, pointer to after terminator on return
|
||||||
// deststring pointer to destination
|
deststring pointer to destination
|
||||||
// flags determines, what to parse
|
flags determines, what to parse
|
||||||
// returns number of valid converted characters in deststring
|
returns number of valid converted characters in deststring
|
||||||
// or -1 for parse error
|
or -1 for parse error
|
||||||
|
*/
|
||||||
size_t scan_urlencoded_query(char **string, char *deststring, int flags);
|
size_t scan_urlencoded_query(char **string, char *deststring, int flags);
|
||||||
|
|
||||||
// data pointer to len chars of string
|
/* data pointer to len chars of string
|
||||||
// len length of chars in data to parse
|
len length of chars in data to parse
|
||||||
// number number to receive result
|
number number to receive result
|
||||||
// returns number of bytes not parsed, mostly !=0 means fail
|
returns number of bytes not parsed, mostly !=0 means fail
|
||||||
|
*/
|
||||||
size_t scan_fixed_int( char *data, size_t len, int *number );
|
size_t scan_fixed_int( char *data, size_t len, int *number );
|
||||||
|
|
||||||
// data pointer to len chars of string
|
/* data pointer to len chars of string
|
||||||
// len length of chars in data to parse
|
len length of chars in data to parse
|
||||||
// ip buffer to receive result
|
ip buffer to receive result
|
||||||
// returns number of bytes not parsed, mostly !=0 means fail
|
returns number of bytes not parsed, mostly !=0 means fail
|
||||||
|
*/
|
||||||
size_t scan_fixed_ip( char *data, size_t len, unsigned char ip[4] );
|
size_t scan_fixed_ip( char *data, size_t len, unsigned char ip[4] );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
125
trackerlogic.c
125
trackerlogic.c
@ -22,8 +22,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// GLOBAL VARIABLES
|
/* GLOBAL VARIABLES */
|
||||||
//
|
|
||||||
static ot_vector all_torrents[256];
|
static ot_vector all_torrents[256];
|
||||||
|
|
||||||
#ifdef WANT_CLOSED_TRACKER
|
#ifdef WANT_CLOSED_TRACKER
|
||||||
@ -36,36 +35,37 @@ int g_check_blacklist = 1;
|
|||||||
static ot_torrent* const OT_TORRENT_ON_BLACKLIST = (ot_torrent*)2;
|
static ot_torrent* const OT_TORRENT_ON_BLACKLIST = (ot_torrent*)2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This function gives us a binary search that returns a pointer, even if
|
/* 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
|
no exact match is found. In that case it sets exactmatch 0 and gives
|
||||||
// calling functions the chance to insert data
|
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,
|
static void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size,
|
||||||
int compare_size, int *exactmatch ) {
|
size_t compare_size, int *exactmatch ) {
|
||||||
|
size_t mc = member_count;
|
||||||
ot_byte *lookat = ((ot_byte*)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( mc ) {
|
||||||
int cmp = memcmp( lookat, key, compare_size);
|
int cmp = memcmp( lookat, key, compare_size);
|
||||||
if (cmp == 0) return (void *)lookat;
|
if (cmp == 0) return (void *)lookat;
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
base = (void*)(lookat + member_size);
|
base = (void*)(lookat + member_size);
|
||||||
--member_count;
|
--mc;
|
||||||
}
|
}
|
||||||
member_count >>= 1;
|
mc >>= 1;
|
||||||
lookat = ((ot_byte*)base) + member_size * (member_count >> 1);
|
lookat = ((ot_byte*)base) + member_size * (mc >> 1);
|
||||||
}
|
}
|
||||||
*exactmatch = 0;
|
*exactmatch = 0;
|
||||||
return (void*)lookat;
|
return (void*)lookat;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converter function from memory to human readable hex strings
|
/* Converter function from memory to human readable hex strings
|
||||||
// * definitely not thread safe!!!
|
- 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;}
|
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 ) {
|
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;
|
if( *exactmatch ) return match;
|
||||||
|
|
||||||
@ -74,13 +74,13 @@ static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_
|
|||||||
ot_byte *new_data = realloc( vector->data, new_space * member_size );
|
ot_byte *new_data = realloc( vector->data, new_space * member_size );
|
||||||
if( !new_data ) return NULL;
|
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);
|
match = new_data + (match - (ot_byte*)vector->data);
|
||||||
|
|
||||||
vector->data = new_data;
|
vector->data = new_data;
|
||||||
vector->space = new_space;
|
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++;
|
vector->size++;
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
@ -91,11 +91,11 @@ static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) {
|
|||||||
ot_peer *match;
|
ot_peer *match;
|
||||||
|
|
||||||
if( !vector->size ) return 0;
|
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;
|
if( !exactmatch ) return 0;
|
||||||
exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1;
|
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 ) ) {
|
if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) {
|
||||||
vector->space /= OT_VECTOR_SHRINK_RATIO;
|
vector->space /= OT_VECTOR_SHRINK_RATIO;
|
||||||
vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) );
|
vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) );
|
||||||
@ -117,15 +117,15 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
|
|||||||
ot_torrent *match;
|
ot_torrent *match;
|
||||||
|
|
||||||
if( !vector->size ) return 0;
|
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( !exactmatch ) return 0;
|
||||||
|
|
||||||
// If this is being called after a unsuccessful malloc() for peer_list
|
/* If this is being called after a unsuccessful malloc() for peer_list
|
||||||
// in add_peer_to_torrent, match->peer_list actually might be NULL
|
in add_peer_to_torrent, match->peer_list actually might be NULL */
|
||||||
if( match->peer_list) free_peerlist( match->peer_list );
|
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 ) ) {
|
if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) {
|
||||||
vector->space /= OT_VECTOR_SHRINK_RATIO;
|
vector->space /= OT_VECTOR_SHRINK_RATIO;
|
||||||
vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) );
|
vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) );
|
||||||
@ -133,22 +133,21 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
|
|||||||
return 1;
|
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 ) {
|
static int clean_peerlist( ot_peerlist *peer_list ) {
|
||||||
long timedout = NOW-peer_list->base;
|
int i, timedout = (int)( NOW - peer_list->base );
|
||||||
int i;
|
|
||||||
|
|
||||||
if( !timedout ) return 0;
|
if( !timedout ) return 0;
|
||||||
if( timedout > OT_POOLS_COUNT ) timedout = OT_POOLS_COUNT;
|
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);
|
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 );
|
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) );
|
memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout) );
|
||||||
byte_zero( peer_list->seed_count, sizeof( unsigned long ) * timedout );
|
byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout );
|
||||||
|
|
||||||
peer_list->base = NOW;
|
peer_list->base = NOW;
|
||||||
return timedout == OT_POOLS_COUNT;
|
return timedout == OT_POOLS_COUNT;
|
||||||
@ -178,8 +177,8 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
|
|||||||
if( !torrent ) return NULL;
|
if( !torrent ) return NULL;
|
||||||
|
|
||||||
if( !exactmatch ) {
|
if( !exactmatch ) {
|
||||||
// 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 = malloc( sizeof (ot_peerlist) );
|
torrent->peer_list = malloc( sizeof (ot_peerlist) );
|
||||||
if( !torrent->peer_list ) {
|
if( !torrent->peer_list ) {
|
||||||
@ -195,11 +194,11 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
|
|||||||
peer_pool = &torrent->peer_list->peers[0];
|
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 );
|
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
|
/* If we hadn't had a match in current pool, create peer there and
|
||||||
// remove it from all older pools
|
remove it from all older pools */
|
||||||
if( !exactmatch ) {
|
if( !exactmatch ) {
|
||||||
int i;
|
int i;
|
||||||
MEMMOVE( peer_dest, peer, sizeof( ot_peer ) );
|
memmove( peer_dest, peer, sizeof( ot_peer ) );
|
||||||
if( OT_FLAG(peer) & PEER_FLAG_SEEDING )
|
if( OT_FLAG(peer) & PEER_FLAG_SEEDING )
|
||||||
torrent->peer_list->seed_count[0]++;
|
torrent->peer_list->seed_count[0]++;
|
||||||
for( i=1; i<OT_POOLS_COUNT; ++i ) {
|
for( i=1; i<OT_POOLS_COUNT; ++i ) {
|
||||||
@ -221,27 +220,30 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
|
|||||||
return torrent;
|
return torrent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compiles a list of random peers for a torrent
|
/* Compiles a list of random peers for a torrent
|
||||||
// * reply must have enough space to hold 24+6*amount bytes
|
* reply must have enough space to hold 24+6*amount bytes
|
||||||
// * Selector function can be anything, maybe test for seeds, etc.
|
* Selector function can be anything, maybe test for seeds, etc.
|
||||||
// * RANDOM may return huge values
|
* RANDOM may return huge values
|
||||||
// * does not yet check not to return self
|
* does not yet check not to return self
|
||||||
//
|
*/
|
||||||
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 ) {
|
||||||
char *r = reply;
|
char *r = reply;
|
||||||
unsigned long peer_count, seed_count, index;
|
unsigned int peer_count, seed_count, index;
|
||||||
signed long pool_offset = -1, pool_index = 0;
|
int pool_offset = -1, pool_index = 0, wert = -1;
|
||||||
signed long wert = -1;
|
|
||||||
|
|
||||||
#ifdef WANT_CLOSED_TRACKER
|
#ifdef WANT_CLOSED_TRACKER
|
||||||
if( torrent == OT_TORRENT_NOT_ON_WHITELIST ) {
|
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
|
#endif
|
||||||
|
|
||||||
#ifdef WANT_BLACKLIST
|
#ifdef WANT_BLACKLIST
|
||||||
if( torrent == OT_TORRENT_ON_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
|
#endif
|
||||||
|
|
||||||
@ -251,23 +253,19 @@ size_t return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char
|
|||||||
}
|
}
|
||||||
if( peer_count < amount ) amount = peer_count;
|
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 ) {
|
for( index = 0; index < amount; ++index ) {
|
||||||
double step = 1.8*((double)( peer_count - wert - 1 ))/((double)( amount - index ));
|
double step = 1.8*((double)( peer_count - wert - 1 ))/((double)( amount - index ));
|
||||||
int off = random() % (int)floor( step );
|
int off = random() % (int)floor( step );
|
||||||
off = 1 + ( off % ( peer_count - wert - 1 ));
|
off = 1 + ( off % ( peer_count - wert - 1 ));
|
||||||
wert += off; pool_offset += off;
|
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 ) {
|
while( pool_offset >= torrent->peer_list->peers[pool_index].size ) {
|
||||||
pool_offset -= torrent->peer_list->peers[pool_index].size;
|
pool_offset -= torrent->peer_list->peers[pool_index].size;
|
||||||
pool_index++;
|
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 += 6;
|
||||||
}
|
}
|
||||||
*r++ = 'e';
|
*r++ = 'e';
|
||||||
@ -275,12 +273,12 @@ size_t return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char
|
|||||||
return r - reply;
|
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 ) {
|
size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) {
|
||||||
char *r = reply;
|
char *r = reply;
|
||||||
int exactmatch, peers = 0, seeds = 0, i;
|
int exactmatch, peers = 0, seeds = 0, i;
|
||||||
ot_vector *torrents_list = &all_torrents[*hash[0]];
|
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;
|
if( !exactmatch ) return 0;
|
||||||
clean_peerlist( torrent->peer_list );
|
clean_peerlist( torrent->peer_list );
|
||||||
@ -290,8 +288,8 @@ size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) {
|
|||||||
seeds += torrent->peer_list->seed_count[i];
|
seeds += torrent->peer_list->seed_count[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
MEMMOVE( r, "d5:filesd20:", 12 ); MEMMOVE( r+12, hash, 20 );
|
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;
|
r += sprintf( r+32, "d8:completei%de10:downloadedi%de10:incompletei%deeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32;
|
||||||
|
|
||||||
return r - reply;
|
return r - reply;
|
||||||
}
|
}
|
||||||
@ -299,11 +297,11 @@ size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) {
|
|||||||
void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) {
|
void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) {
|
||||||
int exactmatch, i;
|
int exactmatch, i;
|
||||||
ot_vector *torrents_list = &all_torrents[*hash[0]];
|
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;
|
if( !exactmatch ) return;
|
||||||
|
|
||||||
// Maybe this does the job
|
/* Maybe this does the job */
|
||||||
if( clean_peerlist( torrent->peer_list ) ) {
|
if( clean_peerlist( torrent->peer_list ) ) {
|
||||||
#ifdef WANT_CLOSED_TRACKER
|
#ifdef WANT_CLOSED_TRACKER
|
||||||
if( !g_closedtracker )
|
if( !g_closedtracker )
|
||||||
@ -332,7 +330,7 @@ int init_logic( char *serverdir ) {
|
|||||||
|
|
||||||
srandom( time(NULL));
|
srandom( time(NULL));
|
||||||
|
|
||||||
// Initialize control structures
|
/* Initialize control structures */
|
||||||
byte_zero( all_torrents, sizeof (all_torrents));
|
byte_zero( all_torrents, sizeof (all_torrents));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -340,7 +338,8 @@ int init_logic( char *serverdir ) {
|
|||||||
|
|
||||||
void deinit_logic( ) {
|
void deinit_logic( ) {
|
||||||
int i, j;
|
int i, j;
|
||||||
// Free all torrents...
|
|
||||||
|
/* Free all torrents... */
|
||||||
for(i=0; i<256; ++i ) {
|
for(i=0; i<256; ++i ) {
|
||||||
if( all_torrents[i].size ) {
|
if( all_torrents[i].size ) {
|
||||||
ot_torrent *torrents_list = (ot_torrent*)all_torrents[i].data;
|
ot_torrent *torrents_list = (ot_torrent*)all_torrents[i].data;
|
||||||
|
@ -18,18 +18,12 @@ typedef ot_byte ot_hash[20];
|
|||||||
typedef ot_dword ot_ip;
|
typedef ot_dword ot_ip;
|
||||||
typedef time_t ot_time;
|
typedef time_t ot_time;
|
||||||
|
|
||||||
#define MEMMOVE memmove
|
/* We maintain a list of 256 pointers to sorted list of ot_torrent structs
|
||||||
#define BZERO bzero
|
Sort key is, of course, its hash */
|
||||||
#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
|
/* This list points to 9 pools of peers each grouped in five-minute-intervals
|
||||||
// Sort key is, of course, its hash
|
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_COUNT 9
|
||||||
#define OT_POOLS_TIMEOUT 300
|
#define OT_POOLS_TIMEOUT 300
|
||||||
@ -52,8 +46,8 @@ static const ot_byte PEER_FLAG_SEEDING = 0x80;
|
|||||||
static const ot_byte PEER_FLAG_COMPLETED = 0x40;
|
static const ot_byte PEER_FLAG_COMPLETED = 0x40;
|
||||||
static const ot_byte PEER_FLAG_STOPPED = 0x20;
|
static const ot_byte PEER_FLAG_STOPPED = 0x20;
|
||||||
|
|
||||||
#define OT_SETIP( peer, ip ) MEMMOVE((peer),(ip),4);
|
#define OT_SETIP( peer, ip ) memmove((peer),(ip),4);
|
||||||
#define OT_SETPORT( peer, port ) MEMMOVE(((ot_byte*)peer)+4,(port),2);
|
#define OT_SETPORT( peer, port ) memmove(((ot_byte*)peer)+4,(port),2);
|
||||||
#define OT_FLAG(peer) (((ot_byte*)(peer))[6])
|
#define OT_FLAG(peer) (((ot_byte*)(peer))[6])
|
||||||
|
|
||||||
#define OT_PEER_COMPARE_SIZE ((size_t)6)
|
#define OT_PEER_COMPARE_SIZE ((size_t)6)
|
||||||
@ -61,8 +55,8 @@ static const ot_byte PEER_FLAG_STOPPED = 0x20;
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ot_time base;
|
ot_time base;
|
||||||
unsigned long seed_count[ OT_POOLS_COUNT ];
|
size_t seed_count[ OT_POOLS_COUNT ];
|
||||||
unsigned long downloaded;
|
unsigned int downloaded;
|
||||||
ot_vector peers[ OT_POOLS_COUNT ];
|
ot_vector peers[ OT_POOLS_COUNT ];
|
||||||
} ot_peerlist;
|
} ot_peerlist;
|
||||||
|
|
||||||
@ -71,9 +65,9 @@ typedef struct {
|
|||||||
ot_peerlist *peer_list;
|
ot_peerlist *peer_list;
|
||||||
} ot_torrent;
|
} ot_torrent;
|
||||||
|
|
||||||
//
|
/*
|
||||||
// Exported functions
|
Exported functions
|
||||||
//
|
*/
|
||||||
|
|
||||||
int init_logic( char *serverdir );
|
int init_logic( char *serverdir );
|
||||||
void deinit_logic( );
|
void deinit_logic( );
|
||||||
@ -86,7 +80,7 @@ extern int g_check_blacklist;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer );
|
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 );
|
size_t return_scrape_for_torrent( ot_hash *hash, char *reply );
|
||||||
void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer );
|
void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer );
|
||||||
void cleanup_torrents( void );
|
void cleanup_torrents( void );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user