Browse Source

clang-format

master
Dirk Engling 7 months ago
parent
commit
7c633c259e
  1. 739
      opentracker.c
  2. 256
      ot_accesslist.c
  3. 45
      ot_accesslist.h
  4. 98
      ot_clean.c
  5. 8
      ot_clean.h
  6. 225
      ot_fullscrape.c
  7. 8
      ot_fullscrape.h
  8. 628
      ot_http.c
  9. 6
      ot_http.h
  10. 51
      ot_iovec.c
  11. 12
      ot_iovec.h
  12. 154
      ot_livesync.c
  13. 8
      ot_livesync.h
  14. 125
      ot_mutex.c
  15. 25
      ot_mutex.h
  16. 777
      ot_stats.c
  17. 16
      ot_stats.h
  18. 169
      ot_udp.c
  19. 4
      ot_udp.h
  20. 212
      ot_vector.c
  21. 17
      ot_vector.h
  22. 89
      scan_urlencoded_query.c
  23. 6
      scan_urlencoded_query.h
  24. 476
      trackerlogic.c
  25. 81
      trackerlogic.h

739
opentracker.c

File diff suppressed because it is too large Load Diff

256
ot_accesslist.c

@ -5,28 +5,28 @@
/* System */ /* System */
#include <pthread.h> #include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h> #include <unistd.h>
#ifdef WANT_DYNAMIC_ACCESSLIST #ifdef WANT_DYNAMIC_ACCESSLIST
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif #endif
/* Libowfat */ /* Libowfat */
#include "byte.h" #include "byte.h"
#include "scan.h" #include "fmt.h"
#include "ip6.h" #include "ip6.h"
#include "mmap.h" #include "mmap.h"
#include "fmt.h" #include "scan.h"
/* Opentracker */ /* Opentracker */
#include "trackerlogic.h"
#include "ot_accesslist.h" #include "ot_accesslist.h"
#include "ot_vector.h" #include "ot_vector.h"
#include "trackerlogic.h"
/* GLOBAL VARIABLES */ /* GLOBAL VARIABLES */
#ifdef WANT_ACCESSLIST #ifdef WANT_ACCESSLIST
@ -55,20 +55,18 @@ struct ot_accesslist {
ot_time base; ot_time base;
ot_accesslist *next; ot_accesslist *next;
}; };
static ot_accesslist * _Atomic g_accesslist = NULL; static ot_accesslist *_Atomic g_accesslist = NULL;
#ifdef WANT_DYNAMIC_ACCESSLIST #ifdef WANT_DYNAMIC_ACCESSLIST
static ot_accesslist * _Atomic g_accesslist_add = NULL; static ot_accesslist *_Atomic g_accesslist_add = NULL;
static ot_accesslist * _Atomic g_accesslist_delete = NULL; static ot_accesslist *_Atomic g_accesslist_delete = NULL;
#endif #endif
/* Helpers to work on access lists */ /* Helpers to work on access lists */
static int vector_compare_hash(const void *hash1, const void *hash2 ) { static int vector_compare_hash(const void *hash1, const void *hash2) { return memcmp(hash1, hash2, OT_HASH_COMPARE_SIZE); }
return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE );
}
static ot_accesslist * accesslist_free(ot_accesslist *accesslist) { static ot_accesslist *accesslist_free(ot_accesslist *accesslist) {
while (accesslist) { while (accesslist) {
ot_accesslist * this_accesslist = accesslist; ot_accesslist *this_accesslist = accesslist;
accesslist = this_accesslist->next; accesslist = this_accesslist->next;
free(this_accesslist->list); free(this_accesslist->list);
free(this_accesslist); free(this_accesslist);
@ -76,8 +74,8 @@ static ot_accesslist * accesslist_free(ot_accesslist *accesslist) {
return NULL; return NULL;
} }
static ot_accesslist * accesslist_make(ot_accesslist *next, size_t size) { static ot_accesslist *accesslist_make(ot_accesslist *next, size_t size) {
ot_accesslist * accesslist_new = malloc(sizeof(ot_accesslist)); ot_accesslist *accesslist_new = malloc(sizeof(ot_accesslist));
if (accesslist_new) { if (accesslist_new) {
accesslist_new->list = size ? malloc(sizeof(ot_hash) * size) : NULL; accesslist_new->list = size ? malloc(sizeof(ot_hash) * size) : NULL;
accesslist_new->size = size; accesslist_new->size = size;
@ -102,25 +100,25 @@ static void accesslist_clean(ot_accesslist *accesslist) {
} }
/* Read initial access list */ /* Read initial access list */
static void accesslist_readfile( void ) { static void accesslist_readfile(void) {
ot_accesslist * accesslist_new; ot_accesslist *accesslist_new;
ot_hash *info_hash; ot_hash *info_hash;
const char *map, *map_end, *read_offs; const char *map, *map_end, *read_offs;
size_t maplen; size_t maplen;
if( ( map = mmap_read( g_accesslist_filename, &maplen ) ) == NULL ) { if ((map = mmap_read(g_accesslist_filename, &maplen)) == NULL) {
char *wd = getcwd( NULL, 0 ); char *wd = getcwd(NULL, 0);
fprintf( stderr, "Warning: Can't open accesslist file: %s (but will try to create it later, if necessary and possible).\nPWD: %s\n", g_accesslist_filename, wd ); fprintf(stderr, "Warning: Can't open accesslist file: %s (but will try to create it later, if necessary and possible).\nPWD: %s\n", g_accesslist_filename, wd);
free( wd ); free(wd);
return; return;
} }
/* You need at least 41 bytes to pass an info_hash, make enough room /* You need at least 41 bytes to pass an info_hash, make enough room
for the maximum amount of them */ for the maximum amount of them */
accesslist_new = accesslist_make(g_accesslist, maplen / 41); accesslist_new = accesslist_make(g_accesslist, maplen / 41);
if( !accesslist_new ) { if (!accesslist_new) {
fprintf( stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", ( maplen / 41 ) * 20 ); fprintf(stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", (maplen / 41) * 20);
mmap_unmap( map, maplen); mmap_unmap(map, maplen);
return; return;
} }
info_hash = accesslist_new->list; info_hash = accesslist_new->list;
@ -130,34 +128,35 @@ static void accesslist_readfile( void ) {
read_offs = map; read_offs = map;
/* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" */ /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" */
while( read_offs <= map_end ) { while (read_offs <= map_end) {
int i; int i;
for( i=0; i<(int)sizeof(ot_hash); ++i ) { for (i = 0; i < (int)sizeof(ot_hash); ++i) {
int eger1 = scan_fromhex( (unsigned char)read_offs[ 2*i ] ); int eger1 = scan_fromhex((unsigned char)read_offs[2 * i]);
int eger2 = scan_fromhex( (unsigned char)read_offs[ 1 + 2*i ] ); int eger2 = scan_fromhex((unsigned char)read_offs[1 + 2 * i]);
if( eger1 < 0 || eger2 < 0 ) if (eger1 < 0 || eger2 < 0)
break; break;
(*info_hash)[i] = (uint8_t)(eger1 * 16 + eger2); (*info_hash)[i] = (uint8_t)(eger1 * 16 + eger2);
} }
if( i == sizeof(ot_hash) ) { if (i == sizeof(ot_hash)) {
read_offs += 40; read_offs += 40;
/* Append accesslist to accesslist vector */ /* Append accesslist to accesslist vector */
if( read_offs == map_end || scan_fromhex( (unsigned char)*read_offs ) < 0 ) if (read_offs == map_end || scan_fromhex((unsigned char)*read_offs) < 0)
++info_hash; ++info_hash;
} }
/* Find start of next line */ /* Find start of next line */
while( read_offs <= map_end && *(read_offs++) != '\n' ); while (read_offs <= map_end && *(read_offs++) != '\n')
;
} }
#ifdef _DEBUG #ifdef _DEBUG
fprintf( stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new->list) ); fprintf(stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new->list));
#endif #endif
mmap_unmap( map, maplen); mmap_unmap(map, maplen);
qsort( accesslist_new->list, info_hash - accesslist_new->list, sizeof( *info_hash ), vector_compare_hash ); qsort(accesslist_new->list, info_hash - accesslist_new->list, sizeof(*info_hash), vector_compare_hash);
accesslist_new->size = info_hash - accesslist_new->list; accesslist_new->size = info_hash - accesslist_new->list;
/* Now exchange the accesslist vector in the least race condition prone way */ /* Now exchange the accesslist vector in the least race condition prone way */
@ -179,26 +178,26 @@ static void accesslist_readfile( void ) {
pthread_mutex_unlock(&g_accesslist_mutex); pthread_mutex_unlock(&g_accesslist_mutex);
} }
int accesslist_hashisvalid( ot_hash hash ) { int accesslist_hashisvalid(ot_hash hash) {
/* Get working copy of current access list */ /* Get working copy of current access list */
ot_accesslist * accesslist = g_accesslist; ot_accesslist *accesslist = g_accesslist;
#ifdef WANT_DYNAMIC_ACCESSLIST #ifdef WANT_DYNAMIC_ACCESSLIST
ot_accesslist * accesslist_add, * accesslist_delete; ot_accesslist *accesslist_add, *accesslist_delete;
#endif #endif
void * exactmatch = NULL; void *exactmatch = NULL;
if (accesslist) if (accesslist)
exactmatch = bsearch( hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); exactmatch = bsearch(hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
#ifdef WANT_DYNAMIC_ACCESSLIST #ifdef WANT_DYNAMIC_ACCESSLIST
/* If we had no match on the main list, scan the list of dynamically added hashes */ /* If we had no match on the main list, scan the list of dynamically added hashes */
accesslist_add = g_accesslist_add; accesslist_add = g_accesslist_add;
if ((exactmatch == NULL) && accesslist_add) if ((exactmatch == NULL) && accesslist_add)
exactmatch = bsearch( hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); exactmatch = bsearch(hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
/* If we found a matching hash on the main list, scan the list of dynamically deleted hashes */ /* If we found a matching hash on the main list, scan the list of dynamically deleted hashes */
accesslist_delete = g_accesslist_delete; accesslist_delete = g_accesslist_delete;
if ((exactmatch != NULL) && accesslist_delete && bsearch( hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash )) if ((exactmatch != NULL) && accesslist_delete && bsearch(hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash))
exactmatch = NULL; exactmatch = NULL;
#endif #endif
@ -209,7 +208,7 @@ int accesslist_hashisvalid( ot_hash hash ) {
#endif #endif
} }
static void * accesslist_worker( void * args ) { static void *accesslist_worker(void *args) {
int sig; int sig;
sigset_t signal_mask; sigset_t signal_mask;
@ -218,22 +217,23 @@ static void * accesslist_worker( void * args ) {
(void)args; (void)args;
while( 1 ) { while (1) {
if (!g_opentracker_running) if (!g_opentracker_running)
return NULL; return NULL;
/* Initial attempt to read accesslist */ /* Initial attempt to read accesslist */
accesslist_readfile( ); accesslist_readfile();
/* Wait for signals */ /* Wait for signals */
while( sigwait (&signal_mask, &sig) != 0 && sig != SIGHUP ); while (sigwait(&signal_mask, &sig) != 0 && sig != SIGHUP)
;
} }
return NULL; return NULL;
} }
#ifdef WANT_DYNAMIC_ACCESSLIST #ifdef WANT_DYNAMIC_ACCESSLIST
static pthread_t thread_adder_id, thread_deleter_id; static pthread_t thread_adder_id, thread_deleter_id;
static void * accesslist_adddel_worker(char * fifoname, ot_accesslist * _Atomic * adding_to, ot_accesslist * _Atomic * removing_from) { static void *accesslist_adddel_worker(char *fifoname, ot_accesslist *_Atomic *adding_to, ot_accesslist *_Atomic *removing_from) {
struct stat st; struct stat st;
if (!stat(fifoname, &st)) { if (!stat(fifoname, &st)) {
@ -250,7 +250,7 @@ static void * accesslist_adddel_worker(char * fifoname, ot_accesslist * _Atomic
} }
while (g_opentracker_running) { while (g_opentracker_running) {
FILE * fifo = fopen(fifoname, "r"); FILE *fifo = fopen(fifoname, "r");
char *line = NULL; char *line = NULL;
size_t linecap = 0; size_t linecap = 0;
ssize_t linelen; ssize_t linelen;
@ -270,15 +270,15 @@ static void * accesslist_adddel_worker(char * fifoname, ot_accesslist * _Atomic
if (linelen < 41) if (linelen < 41)
continue; continue;
for( i=0; i<(int)sizeof(ot_hash); ++i ) { for (i = 0; i < (int)sizeof(ot_hash); ++i) {
int eger1 = scan_fromhex( (unsigned char)line[ 2*i ] ); int eger1 = scan_fromhex((unsigned char)line[2 * i]);
int eger2 = scan_fromhex( (unsigned char)line[ 1 + 2*i ] ); int eger2 = scan_fromhex((unsigned char)line[1 + 2 * i]);
if( eger1 < 0 || eger2 < 0 ) if (eger1 < 0 || eger2 < 0)
break; break;
((uint8_t*)info_hash)[i] = (uint8_t)(eger1 * 16 + eger2); ((uint8_t *)info_hash)[i] = (uint8_t)(eger1 * 16 + eger2);
} }
printf("parsed info_hash %20s\n", info_hash); printf("parsed info_hash %20s\n", info_hash);
if( i != sizeof(ot_hash) ) if (i != sizeof(ot_hash))
continue; continue;
/* From now on we modify g_accesslist_add and g_accesslist_delete, so prevent the /* From now on we modify g_accesslist_add and g_accesslist_delete, so prevent the
@ -287,10 +287,10 @@ printf("parsed info_hash %20s\n", info_hash);
/* If the info hash is in the removing_from list, create a new head without that entry */ /* If the info hash is in the removing_from list, create a new head without that entry */
if (*removing_from && (*removing_from)->list) { if (*removing_from && (*removing_from)->list) {
ot_hash * exactmatch = bsearch( info_hash, (*removing_from)->list, (*removing_from)->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); ot_hash *exactmatch = bsearch(info_hash, (*removing_from)->list, (*removing_from)->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
if (exactmatch) { if (exactmatch) {
ptrdiff_t off = exactmatch - (*removing_from)->list; ptrdiff_t off = exactmatch - (*removing_from)->list;
ot_accesslist * accesslist_new = accesslist_make(*removing_from, (*removing_from)->size - 1); ot_accesslist *accesslist_new = accesslist_make(*removing_from, (*removing_from)->size - 1);
if (accesslist_new) { if (accesslist_new) {
memcpy(accesslist_new->list, (*removing_from)->list, sizeof(ot_hash) * off); memcpy(accesslist_new->list, (*removing_from)->list, sizeof(ot_hash) * off);
memcpy(accesslist_new->list + off, (*removing_from)->list + off + 1, (*removing_from)->size - off - 1); memcpy(accesslist_new->list + off, (*removing_from)->list + off + 1, (*removing_from)->size - off - 1);
@ -301,18 +301,18 @@ printf("parsed info_hash %20s\n", info_hash);
/* Simple case: there's no adding_to list yet, create one with one member */ /* Simple case: there's no adding_to list yet, create one with one member */
if (!*adding_to) { if (!*adding_to) {
ot_accesslist * accesslist_new = accesslist_make(NULL, 1); ot_accesslist *accesslist_new = accesslist_make(NULL, 1);
if (accesslist_new) { if (accesslist_new) {
memcpy(accesslist_new->list, info_hash, sizeof(ot_hash)); memcpy(accesslist_new->list, info_hash, sizeof(ot_hash));
*adding_to = accesslist_new; *adding_to = accesslist_new;
} }
} else { } else {
int exactmatch = 0; int exactmatch = 0;
ot_hash * insert_point = binary_search( info_hash, (*adding_to)->list, (*adding_to)->size, OT_HASH_COMPARE_SIZE, sizeof(ot_hash), &exactmatch ); ot_hash *insert_point = binary_search(info_hash, (*adding_to)->list, (*adding_to)->size, OT_HASH_COMPARE_SIZE, sizeof(ot_hash), &exactmatch);
/* Only if the info hash is not in the adding_to list, create a new head with that entry */ /* Only if the info hash is not in the adding_to list, create a new head with that entry */
if (!exactmatch) { if (!exactmatch) {
ot_accesslist * accesslist_new = accesslist_make(*adding_to, (*adding_to)->size + 1); ot_accesslist *accesslist_new = accesslist_make(*adding_to, (*adding_to)->size + 1);
ptrdiff_t off = insert_point - (*adding_to)->list; ptrdiff_t off = insert_point - (*adding_to)->list;
if (accesslist_new) { if (accesslist_new) {
memcpy(accesslist_new->list, (*adding_to)->list, sizeof(ot_hash) * off); memcpy(accesslist_new->list, (*adding_to)->list, sizeof(ot_hash) * off);
@ -331,29 +331,29 @@ printf("parsed info_hash %20s\n", info_hash);
return NULL; return NULL;
} }
static void * accesslist_adder_worker( void * args ) { static void *accesslist_adder_worker(void *args) {
(void)args; (void)args;
return accesslist_adddel_worker(g_accesslist_pipe_add, &g_accesslist_add, &g_accesslist_delete); return accesslist_adddel_worker(g_accesslist_pipe_add, &g_accesslist_add, &g_accesslist_delete);
} }
static void * accesslist_deleter_worker( void * args ) { static void *accesslist_deleter_worker(void *args) {
(void)args; (void)args;
return accesslist_adddel_worker(g_accesslist_pipe_delete, &g_accesslist_delete, &g_accesslist_add); return accesslist_adddel_worker(g_accesslist_pipe_delete, &g_accesslist_delete, &g_accesslist_add);
} }
#endif #endif
static pthread_t thread_id; static pthread_t thread_id;
void accesslist_init( ) { void accesslist_init() {
pthread_mutex_init(&g_accesslist_mutex, NULL); pthread_mutex_init(&g_accesslist_mutex, NULL);
pthread_create( &thread_id, NULL, accesslist_worker, NULL ); pthread_create(&thread_id, NULL, accesslist_worker, NULL);
#ifdef WANT_DYNAMIC_ACCESSLIST #ifdef WANT_DYNAMIC_ACCESSLIST
if (g_accesslist_pipe_add) if (g_accesslist_pipe_add)
pthread_create( &thread_adder_id, NULL, accesslist_adder_worker, NULL ); pthread_create(&thread_adder_id, NULL, accesslist_adder_worker, NULL);
if (g_accesslist_pipe_delete) if (g_accesslist_pipe_delete)
pthread_create( &thread_deleter_id, NULL, accesslist_deleter_worker, NULL ); pthread_create(&thread_deleter_id, NULL, accesslist_deleter_worker, NULL);
#endif #endif
} }
void accesslist_deinit( void ) { void accesslist_deinit(void) {
/* Wake up sleeping worker */ /* Wake up sleeping worker */
pthread_kill(thread_id, SIGHUP); pthread_kill(thread_id, SIGHUP);
@ -367,11 +367,11 @@ void accesslist_deinit( void ) {
#endif #endif
pthread_mutex_unlock(&g_accesslist_mutex); pthread_mutex_unlock(&g_accesslist_mutex);
pthread_cancel( thread_id ); pthread_cancel(thread_id);
pthread_mutex_destroy(&g_accesslist_mutex); pthread_mutex_destroy(&g_accesslist_mutex);
} }
void accesslist_cleanup( void ) { void accesslist_cleanup(void) {
pthread_mutex_lock(&g_accesslist_mutex); pthread_mutex_lock(&g_accesslist_mutex);
accesslist_clean(g_accesslist); accesslist_clean(g_accesslist);
@ -384,35 +384,34 @@ void accesslist_cleanup( void ) {
} }
#endif #endif
int address_in_net( const ot_ip6 address, const ot_net *net ) { int address_in_net(const ot_ip6 address, const ot_net *net) {
int bits = net->bits, checkbits = ( 0x7f00 >> ( bits & 7 )); int bits = net->bits, checkbits = (0x7f00 >> (bits & 7));
int result = memcmp( address, &net->address, bits >> 3 ); int result = memcmp(address, &net->address, bits >> 3);
if( !result && ( bits & 7 ) ) if (!result && (bits & 7))
result = ( checkbits & address[bits>>3] ) - ( checkbits & net->address[bits>>3]); result = (checkbits & address[bits >> 3]) - (checkbits & net->address[bits >> 3]);
return result == 0; return result == 0;
} }
void *set_value_for_net( const ot_net *net, ot_vector *vector, const void *value, const size_t member_size ) { void *set_value_for_net(const ot_net *net, ot_vector *vector, const void *value, const size_t member_size) {
size_t i; size_t i;
int exactmatch; int exactmatch;
/* Caller must have a concept of ot_net in it's member */ /* Caller must have a concept of ot_net in it's member */
if( member_size < sizeof(ot_net) ) if (member_size < sizeof(ot_net))
return 0; return 0;
/* Check each net in vector for overlap */ /* Check each net in vector for overlap */
uint8_t *member = ((uint8_t*)vector->data); uint8_t *member = ((uint8_t *)vector->data);
for( i=0; i<vector->size; ++i ) { for (i = 0; i < vector->size; ++i) {
if( address_in_net( *(ot_ip6*)member, net ) || if (address_in_net(*(ot_ip6 *)member, net) || address_in_net(net->address, (ot_net *)member))
address_in_net( net->address, (ot_net*)member ) )
return 0; return 0;
member += member_size; member += member_size;
} }
member = vector_find_or_insert( vector, (void*)net, member_size, sizeof(ot_net), &exactmatch ); member = vector_find_or_insert(vector, (void *)net, member_size, sizeof(ot_net), &exactmatch);
if( member ) { if (member) {
memcpy( member, net, sizeof(ot_net)); memcpy(member, net, sizeof(ot_net));
memcpy( member + sizeof(ot_net), value, member_size - sizeof(ot_net)); memcpy(member + sizeof(ot_net), value, member_size - sizeof(ot_net));
} }
return member; return member;
@ -420,43 +419,43 @@ void *set_value_for_net( const ot_net *net, ot_vector *vector, const void *value
/* Takes a vector filled with { ot_net net, uint8_t[x] value }; /* Takes a vector filled with { ot_net net, uint8_t[x] value };
Returns value associated with the net, or NULL if not found */ Returns value associated with the net, or NULL if not found */
void *get_value_for_net( const ot_ip6 address, const ot_vector *vector, const size_t member_size ) { void *get_value_for_net(const ot_ip6 address, const ot_vector *vector, const size_t member_size) {
int exactmatch; int exactmatch;
/* This binary search will return a pointer to the first non-containing network... */ /* This binary search will return a pointer to the first non-containing network... */
ot_net *net = binary_search( address, vector->data, vector->size, member_size, sizeof(ot_ip6), &exactmatch ); ot_net *net = binary_search(address, vector->data, vector->size, member_size, sizeof(ot_ip6), &exactmatch);
if( !net ) if (!net)
return NULL; return NULL;
/* ... so we'll need to move back one step unless we've exactly hit the first address in network */ /* ... so we'll need to move back one step unless we've exactly hit the first address in network */
if( !exactmatch && ( (void*)net > vector->data ) ) if (!exactmatch && ((void *)net > vector->data))
--net; --net;
if( !address_in_net( address, net ) ) if (!address_in_net(address, net))
return NULL; return NULL;
return (void*)net; return (void *)net;
} }
#ifdef WANT_FULLLOG_NETWORKS #ifdef WANT_FULLLOG_NETWORKS
static ot_vector g_lognets_list; static ot_vector g_lognets_list;
ot_log *g_logchain_first, *g_logchain_last; ot_log *g_logchain_first, *g_logchain_last;
static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER;
void loglist_add_network( const ot_net *net ) {
void loglist_add_network(const ot_net *net) {
pthread_mutex_lock(&g_lognets_list_mutex); pthread_mutex_lock(&g_lognets_list_mutex);
set_value_for_net( net, &g_lognets_list, NULL, sizeof(ot_net)); set_value_for_net(net, &g_lognets_list, NULL, sizeof(ot_net));
pthread_mutex_unlock(&g_lognets_list_mutex); pthread_mutex_unlock(&g_lognets_list_mutex);
} }
void loglist_reset( ) { void loglist_reset() {
pthread_mutex_lock(&g_lognets_list_mutex); pthread_mutex_lock(&g_lognets_list_mutex);
free( g_lognets_list.data ); free(g_lognets_list.data);
g_lognets_list.data = 0; g_lognets_list.data = 0;
g_lognets_list.size = g_lognets_list.space = 0; g_lognets_list.size = g_lognets_list.space = 0;
pthread_mutex_unlock(&g_lognets_list_mutex); pthread_mutex_unlock(&g_lognets_list_mutex);
} }
int loglist_check_address( const ot_ip6 address ) { int loglist_check_address(const ot_ip6 address) {
int result; int result;
pthread_mutex_lock(&g_lognets_list_mutex); pthread_mutex_lock(&g_lognets_list_mutex);
result = ( NULL != get_value_for_net( address, &g_lognets_list, sizeof(ot_net)) ); result = (NULL != get_value_for_net(address, &g_lognets_list, sizeof(ot_net)));
pthread_mutex_unlock(&g_lognets_list_mutex); pthread_mutex_unlock(&g_lognets_list_mutex);
return result; return result;
} }
@ -471,37 +470,37 @@ typedef struct {
static ot_vector g_proxies_list; static ot_vector g_proxies_list;
static pthread_mutex_t g_proxies_list_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t g_proxies_list_mutex = PTHREAD_MUTEX_INITIALIZER;
int proxylist_add_network( const ot_net *proxy, const ot_net *net ) { int proxylist_add_network(const ot_net *proxy, const ot_net *net) {
ot_proxymap *map; ot_proxymap *map;
int exactmatch, result = 1; int exactmatch, result = 1;
pthread_mutex_lock(&g_proxies_list_mutex); pthread_mutex_lock(&g_proxies_list_mutex);
/* If we have a direct hit, use and extend the vector there */ /* If we have a direct hit, use and extend the vector there */
map = binary_search( proxy, g_proxies_list.data, g_proxies_list.size, sizeof(ot_proxymap), sizeof(ot_net), &exactmatch ); map = binary_search(proxy, g_proxies_list.data, g_proxies_list.size, sizeof(ot_proxymap), sizeof(ot_net), &exactmatch);
if( !map || !exactmatch ) { if (!map || !exactmatch) {
/* else see, if we've got overlapping networks /* else see, if we've got overlapping networks
and get a new empty vector if not */ and get a new empty vector if not */
ot_vector empty; ot_vector empty;
memset( &empty, 0, sizeof( ot_vector ) ); memset(&empty, 0, sizeof(ot_vector));
map = set_value_for_net( proxy, &g_proxies_list, &empty, sizeof(ot_proxymap)); map = set_value_for_net(proxy, &g_proxies_list, &empty, sizeof(ot_proxymap));
} }
if( map && set_value_for_net( net, &map->networks, NULL, sizeof(ot_net) ) ) if (map && set_value_for_net(net, &map->networks, NULL, sizeof(ot_net)))
result = 1; result = 1;
pthread_mutex_unlock(&g_proxies_list_mutex); pthread_mutex_unlock(&g_proxies_list_mutex);
return result; return result;
} }
int proxylist_check_proxy( const ot_ip6 proxy, const ot_ip6 address ) { int proxylist_check_proxy(const ot_ip6 proxy, const ot_ip6 address) {
int result = 0; int result = 0;
ot_proxymap *map; ot_proxymap *map;
pthread_mutex_lock(&g_proxies_list_mutex); pthread_mutex_lock(&g_proxies_list_mutex);
if( ( map = get_value_for_net( proxy, &g_proxies_list, sizeof(ot_proxymap) ) ) ) if ((map = get_value_for_net(proxy, &g_proxies_list, sizeof(ot_proxymap))))
if( !address || get_value_for_net( address, &map->networks, sizeof(ot_net) ) ) if (!address || get_value_for_net(address, &map->networks, sizeof(ot_net)))
result = 1; result = 1;
pthread_mutex_unlock(&g_proxies_list_mutex); pthread_mutex_unlock(&g_proxies_list_mutex);
@ -514,44 +513,49 @@ static ot_net g_admin_nets[OT_ADMINIP_MAX];
static ot_permissions g_admin_nets_permissions[OT_ADMINIP_MAX]; static ot_permissions g_admin_nets_permissions[OT_ADMINIP_MAX];
static unsigned int g_admin_nets_count = 0; static unsigned int g_admin_nets_count = 0;
int accesslist_bless_net( ot_net *net, ot_permissions permissions ) { int accesslist_bless_net(ot_net *net, ot_permissions permissions) {
if( g_admin_nets_count >= OT_ADMINIP_MAX ) if (g_admin_nets_count >= OT_ADMINIP_MAX)
return -1; return -1;
memcpy(g_admin_nets + g_admin_nets_count, net, sizeof(ot_net)); memcpy(g_admin_nets + g_admin_nets_count, net, sizeof(ot_net));
g_admin_nets_permissions[ g_admin_nets_count++ ] = permissions; g_admin_nets_permissions[g_admin_nets_count++] = permissions;
#ifdef _DEBUG #ifdef _DEBUG
{ {
char _debug[512]; char _debug[512];
int off = snprintf( _debug, sizeof(_debug), "Blessing ip net " ); int off = snprintf(_debug, sizeof(_debug), "Blessing ip net ");
off += fmt_ip6c(_debug+off, net->address ); off += fmt_ip6c(_debug + off, net->address);
if( net->bits < 128) { if (net->bits < 128) {
_debug[off++] = '/'; _debug[off++] = '/';
if( ip6_isv4mapped(net->address) ) if (ip6_isv4mapped(net->address))
off += fmt_long(_debug+off, net->bits-96); off += fmt_long(_debug + off, net->bits - 96);
else else
off += fmt_long(_debug+off, net->bits); off += fmt_long(_debug + off, net->bits);
} }
if( permissions & OT_PERMISSION_MAY_STAT ) off += snprintf( _debug+off, 512-off, " may_fetch_stats" ); if (permissions & OT_PERMISSION_MAY_STAT)
if( permissions & OT_PERMISSION_MAY_LIVESYNC ) off += snprintf( _debug+off, 512-off, " may_sync_live" ); off += snprintf(_debug + off, 512 - off, " may_fetch_stats");
if( permissions & OT_PERMISSION_MAY_FULLSCRAPE ) off += snprintf( _debug+off, 512-off, " may_fetch_fullscrapes" ); if (permissions & OT_PERMISSION_MAY_LIVESYNC)
if( permissions & OT_PERMISSION_MAY_PROXY ) off += snprintf( _debug+off, 512-off, " may_proxy" ); off += snprintf(_debug + off, 512 - off, " may_sync_live");
if( !permissions ) off += snprintf( _debug+off, sizeof(_debug)-off, " nothing" ); if (permissions & OT_PERMISSION_MAY_FULLSCRAPE)
off += snprintf(_debug + off, 512 - off, " may_fetch_fullscrapes");
if (permissions & OT_PERMISSION_MAY_PROXY)
off += snprintf(_debug + off, 512 - off, " may_proxy");
if (!permissions)
off += snprintf(_debug + off, sizeof(_debug) - off, " nothing");
_debug[off++] = '.'; _debug[off++] = '.';
_debug[off++] = '\n'; _debug[off++] = '\n';
(void)write( 2, _debug, off ); (void)write(2, _debug, off);
} }
#endif #endif
return 0; return 0;
} }
int accesslist_is_blessed( ot_ip6 ip, ot_permissions permissions ) { int accesslist_is_blessed(ot_ip6 ip, ot_permissions permissions) {
unsigned int i; unsigned int i;
for( i=0; i<g_admin_nets_count; ++i ) for (i = 0; i < g_admin_nets_count; ++i)
if( address_in_net(ip, g_admin_nets + i) && (g_admin_nets_permissions[ i ] & permissions )) if (address_in_net(ip, g_admin_nets + i) && (g_admin_nets_permissions[i] & permissions))
return 1; return 1;
return 0; return 0;
} }

45
ot_accesslist.h

@ -6,16 +6,18 @@
#ifndef OT_ACCESSLIST_H__ #ifndef OT_ACCESSLIST_H__
#define OT_ACCESSLIST_H__ #define OT_ACCESSLIST_H__
#if defined ( WANT_ACCESSLIST_BLACK ) && defined ( WANT_ACCESSLIST_WHITE ) #include "trackerlogic.h"
# error WANT_ACCESSLIST_BLACK and WANT_ACCESSLIST_WHITE are exclusive.
#if defined(WANT_ACCESSLIST_BLACK) && defined(WANT_ACCESSLIST_WHITE)
#error WANT_ACCESSLIST_BLACK and WANT_ACCESSLIST_WHITE are exclusive.
#endif #endif
#if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE ) #if defined(WANT_ACCESSLIST_BLACK) || defined(WANT_ACCESSLIST_WHITE)
#define WANT_ACCESSLIST #define WANT_ACCESSLIST
void accesslist_init( void ); void accesslist_init(void);
void accesslist_deinit( void ); void accesslist_deinit(void);
int accesslist_hashisvalid( ot_hash hash ); int accesslist_hashisvalid(ot_hash hash);
void accesslist_cleanup( void ); void accesslist_cleanup(void);
extern char *g_accesslist_filename; extern char *g_accesslist_filename;
#ifdef WANT_DYNAMIC_ACCESSLIST #ifdef WANT_DYNAMIC_ACCESSLIST
@ -25,16 +27,16 @@ extern char *g_accesslist_pipe_delete;
#else #else
#ifdef WANT_DYNAMIC_ACCESSLIST #ifdef WANT_DYNAMIC_ACCESSLIST
# error WANT_DYNAMIC_ACCESSLIST needs either WANT_ACCESSLIST_BLACK or WANT_ACCESSLIST_WHITE #error WANT_DYNAMIC_ACCESSLIST needs either WANT_ACCESSLIST_BLACK or WANT_ACCESSLIST_WHITE
#endif #endif
#define accesslist_init( accesslist_filename ) #define accesslist_init(accesslist_filename)
#define accesslist_deinit( ) #define accesslist_deinit()
#define accesslist_hashisvalid( hash ) 1 #define accesslist_hashisvalid(hash) 1
#endif #endif
/* Test if an address is subset of an ot_net, return value is considered a bool */ /* Test if an address is subset of an ot_net, return value is considered a bool */
int address_in_net( const ot_ip6 address, const ot_net *net ); int address_in_net(const ot_ip6 address, const ot_net *net);
/* Store a value into a vector of struct { ot_net net, uint8_t[x] value } member; /* Store a value into a vector of struct { ot_net net, uint8_t[x] value } member;
returns NULL returns NULL
@ -45,18 +47,17 @@ int address_in_net( const ot_ip6 address, const ot_net *net );
returns pointer to new member in vector for success returns pointer to new member in vector for success
member_size can be sizeof(ot_net) to reduce the lookup to a boolean mapping member_size can be sizeof(ot_net) to reduce the lookup to a boolean mapping
*/ */
void *set_value_for_net( const ot_net *net, ot_vector *vector, const void *value, const size_t member_size ); void *set_value_for_net(const ot_net *net, ot_vector *vector, const void *value, const size_t member_size);
/* Takes a vector filled with struct { ot_net net, uint8_t[x] value } member; /* Takes a vector filled with struct { ot_net net, uint8_t[x] value } member;
Returns pointer to _member_ associated with the net, or NULL if not found Returns pointer to _member_ associated with the net, or NULL if not found
member_size can be sizeof(ot_net) to reduce the lookup to a boolean mapping member_size can be sizeof(ot_net) to reduce the lookup to a boolean mapping
*/ */
void *get_value_for_net( const ot_ip6 address, const ot_vector *vector, const size_t member_size ); void *get_value_for_net(const ot_ip6 address, const ot_vector *vector, const size_t member_size);
#ifdef WANT_IP_FROM_PROXY #ifdef WANT_IP_FROM_PROXY
int proxylist_add_network( const ot_net *proxy, const ot_net *net ); int proxylist_add_network(const ot_net *proxy, const ot_net *net);
int proxylist_check_network( const ot_ip6 *proxy, const ot_ip6 address /* can be NULL to only check proxy */ ); int proxylist_check_network(const ot_ip6 *proxy, const ot_ip6 address /* can be NULL to only check proxy */);
#endif #endif
#ifdef WANT_FULLLOG_NETWORKS #ifdef WANT_FULLLOG_NETWORKS
@ -70,9 +71,9 @@ struct ot_log {
}; };
extern ot_log *g_logchain_first, *g_logchain_last; extern ot_log *g_logchain_first, *g_logchain_last;
void loglist_add_network( const ot_net *net ); void loglist_add_network(const ot_net *net);
void loglist_reset( ); void loglist_reset();
int loglist_check_address( const ot_ip6 address ); int loglist_check_address(const ot_ip6 address);
#endif #endif
typedef enum { typedef enum {
@ -82,7 +83,7 @@ typedef enum {
OT_PERMISSION_MAY_PROXY = 0x8 OT_PERMISSION_MAY_PROXY = 0x8
} ot_permissions; } ot_permissions;
int accesslist_bless_net( ot_net *net, ot_permissions permissions ); int accesslist_bless_net(ot_net *net, ot_permissions permissions);
int accesslist_is_blessed( ot_ip6 ip, ot_permissions permissions ); int accesslist_is_blessed(ot_ip6 ip, ot_permissions permissions);
#endif #endif

98
ot_clean.c

@ -5,80 +5,79 @@
/* System */ /* System */
#include <pthread.h> #include <pthread.h>
#include <unistd.h>
#include <string.h> #include <string.h>
#include <unistd.h>
/* Libowfat */ /* Libowfat */
#include "io.h" #include "io.h"
/* Opentracker */ /* Opentracker */
#include "trackerlogic.h" #include "ot_accesslist.h"
#include "ot_mutex.h"
#include "ot_vector.h"
#include "ot_clean.h" #include "ot_clean.h"
#include "ot_mutex.h"
#include "ot_stats.h" #include "ot_stats.h"
#include "ot_accesslist.h" #include "ot_vector.h"
#include "trackerlogic.h"
/* Returns amount of removed peers */ /* Returns amount of removed peers */
static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders ) { static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders) {
ot_peer *last_peer = peers + peer_count * peer_size, *insert_point; ot_peer *last_peer = peers + peer_count * peer_size, *insert_point;
/* Two scan modes: unless there is one peer removed, just increase ot_peertime */ /* Two scan modes: unless there is one peer removed, just increase ot_peertime */
while( peers < last_peer ) { while (peers < last_peer) {
time_t timediff = timedout + OT_PEERTIME( peers, peer_size ); time_t timediff = timedout + OT_PEERTIME(peers, peer_size);
if( timediff >= OT_PEER_TIMEOUT ) if (timediff >= OT_PEER_TIMEOUT)
break; break;
OT_PEERTIME( peers, peer_size ) = timediff; OT_PEERTIME(peers, peer_size) = timediff;
peers += peer_size; peers += peer_size;
} }
/* If we at least remove one peer, we have to copy */ /* If we at least remove one peer, we have to copy */
for( insert_point = peers; peers < last_peer; peers += peer_size ) { for (insert_point = peers; peers < last_peer; peers += peer_size) {
time_t timediff = timedout + OT_PEERTIME( peers, peer_size ); time_t timediff = timedout + OT_PEERTIME(peers, peer_size);
if( timediff < OT_PEER_TIMEOUT ) { if (timediff < OT_PEER_TIMEOUT) {
OT_PEERTIME( peers, peer_size ) = timediff; OT_PEERTIME(peers, peer_size) = timediff;
memcpy( insert_point, peers, peer_size); memcpy(insert_point, peers, peer_size);
insert_point += peer_size; insert_point += peer_size;
} else } else if (OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING)
if( OT_PEERFLAG_D( peers, peer_size ) & PEER_FLAG_SEEDING )
(*removed_seeders)++; (*removed_seeders)++;
} }
return (peers - insert_point) / peer_size; return (peers - insert_point) / peer_size;
} }
int clean_single_peer_list( ot_peerlist *peer_list, size_t peer_size ) { int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) {
ot_vector *peer_vector = &peer_list->peers; ot_vector *peer_vector = &peer_list->peers;
time_t timedout = (time_t)( g_now_minutes - peer_list->base ); time_t timedout = (time_t)(g_now_minutes - peer_list->base);
int num_buckets = 1, removed_seeders = 0; int num_buckets = 1, removed_seeders = 0;
/* No need to clean empty torrent */ /* No need to clean empty torrent */
if( !timedout ) if (!timedout)
return 0; return 0;
/* Torrent has idled out */ /* Torrent has idled out */
if( timedout > OT_TORRENT_TIMEOUT ) if (timedout > OT_TORRENT_TIMEOUT)
return 1; return 1;
/* Nothing to be cleaned here? Test if torrent is worth keeping */ /* Nothing to be cleaned here? Test if torrent is worth keeping */
if( timedout > OT_PEER_TIMEOUT ) { if (timedout > OT_PEER_TIMEOUT) {
if( !peer_list->peer_count ) if (!peer_list->peer_count)
return peer_list->down_count ? 0 : 1; return peer_list->down_count ? 0 : 1;
timedout = OT_PEER_TIMEOUT; timedout = OT_PEER_TIMEOUT;
} }
if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { if (OT_PEERLIST_HASBUCKETS(peer_list)) {
num_buckets = peer_vector->size; num_buckets = peer_vector->size;
peer_vector = (ot_vector *)peer_vector->data; peer_vector = (ot_vector *)peer_vector->data;
} }
while( num_buckets-- ) { while (num_buckets--) {
size_t removed_peers = clean_single_bucket( peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders ); size_t removed_peers = clean_single_bucket(peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders);
peer_list->peer_count -= removed_peers; peer_list->peer_count -= removed_peers;
peer_vector->size -= removed_peers; peer_vector->size -= removed_peers;
if( removed_peers ) if (removed_peers)
vector_fixup_peers( peer_vector, peer_size ); vector_fixup_peers(peer_vector, peer_size);
/* Skip to next bucket, a vector containing peers */ /* Skip to next bucket, a vector containing peers */
++peer_vector; ++peer_vector;
@ -87,10 +86,10 @@ int clean_single_peer_list( ot_peerlist *peer_list, size_t peer_size ) {
peer_list->seed_count -= removed_seeders; peer_list->seed_count -= removed_seeders;
/* See if we need to convert a torrent from simple vector to bucket list */ /* See if we need to convert a torrent from simple vector to bucket list */
if( ( peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT ) || OT_PEERLIST_HASBUCKETS(peer_list) ) if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list))
vector_redistribute_buckets( peer_list, peer_size ); vector_redistribute_buckets(peer_list, peer_size);
if( peer_list->peer_count ) if (peer_list->peer_count)
peer_list->base = g_now_minutes; peer_list->base = g_now_minutes;
else { else {
/* When we got here, the last time that torrent /* When we got here, the last time that torrent
@ -103,34 +102,33 @@ int clean_single_peer_list( ot_peerlist *peer_list, size_t peer_size ) {
/* Clean a single torrent /* Clean a single torrent
return 1 if torrent timed out return 1 if torrent timed out
*/ */
int clean_single_torrent( ot_torrent *torrent ) { int clean_single_torrent(ot_torrent *torrent) {
return clean_single_peer_list( torrent->peer_list6, OT_PEER_SIZE6) * return clean_single_peer_list(torrent->peer_list6, OT_PEER_SIZE6) * clean_single_peer_list(torrent->peer_list4, OT_PEER_SIZE4);
clean_single_peer_list( torrent->peer_list4, OT_PEER_SIZE4);
} }
/* Clean up all peers in current bucket, remove timedout pools and /* Clean up all peers in current bucket, remove timedout pools and
torrents */ torrents */
static void * clean_worker( void * args ) { static void *clean_worker(void *args) {
(void) args; (void)args;
while( 1 ) { while (1) {
int bucket = OT_BUCKET_COUNT; int bucket = OT_BUCKET_COUNT;
while( bucket-- ) { while (bucket--) {
ot_vector *torrents_list = mutex_bucket_lock( bucket ); ot_vector *torrents_list = mutex_bucket_lock(bucket);
size_t toffs; size_t toffs;
int delta_torrentcount = 0; int delta_torrentcount = 0;
for( toffs=0; toffs<torrents_list->size; ++toffs ) { for (toffs = 0; toffs < torrents_list->size; ++toffs) {
ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + toffs; ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + toffs;
if( clean_single_torrent( torrent ) ) { if (clean_single_torrent(torrent)) {
vector_remove_torrent( torrents_list, torrent ); vector_remove_torrent(torrents_list, torrent);
--delta_torrentcount; --delta_torrentcount;
--toffs; --toffs;
} }
} }
mutex_bucket_unlock( bucket, delta_torrentcount ); mutex_bucket_unlock(bucket, delta_torrentcount);
if( !g_opentracker_running ) if (!g_opentracker_running)
return NULL; return NULL;
usleep( OT_CLEAN_SLEEP ); usleep(OT_CLEAN_SLEEP);
} }
stats_cleanup(); stats_cleanup();
#ifdef WANT_ACCESSLIST #ifdef WANT_ACCESSLIST
@ -141,12 +139,8 @@ static void * clean_worker( void * args ) {
} }
static pthread_t thread_id; static pthread_t thread_id;
void clean_init( void ) { void clean_init(void) { pthread_create(&thread_id, NULL, clean_worker, NULL); }
pthread_create( &thread_id, NULL, clean_worker, NULL );
}
void clean_deinit( void ) { void clean_deinit(void) { pthread_cancel(thread_id); }
pthread_cancel( thread_id );
}
const char *g_version_clean_c = "$Source$: $Revision$\n"; const char *g_version_clean_c = "$Source$: $Revision$\n";

8
ot_clean.h

@ -10,10 +10,10 @@
#define OT_CLEAN_INTERVAL_MINUTES 2 #define OT_CLEAN_INTERVAL_MINUTES 2
/* So after each bucket wait 1 / OT_BUCKET_COUNT intervals */ /* So after each bucket wait 1 / OT_BUCKET_COUNT intervals */
#define OT_CLEAN_SLEEP ( ( ( OT_CLEAN_INTERVAL_MINUTES ) * 60 * 1000000 ) / ( OT_BUCKET_COUNT ) ) #define OT_CLEAN_SLEEP (((OT_CLEAN_INTERVAL_MINUTES) * 60 * 1000000) / (OT_BUCKET_COUNT))
void clean_init( void ); void clean_init(void);
void clean_deinit( void ); void clean_deinit(void);
int clean_single_torrent( ot_torrent *torrent ); int clean_single_torrent(ot_torrent *torrent);
#endif #endif

225
ot_fullscrape.c

@ -6,11 +6,11 @@
#ifdef WANT_FULLSCRAPE #ifdef WANT_FULLSCRAPE
/* System */ /* System */
#include <sys/param.h> #include <arpa/inet.h>
#include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <pthread.h> #include <sys/param.h>
#include <arpa/inet.h>
#ifdef WANT_COMPRESSION_GZIP #ifdef WANT_COMPRESSION_GZIP
#include <zlib.h> #include <zlib.h>
#endif #endif
@ -21,46 +21,56 @@
#include "textcode.h" #include "textcode.h"
/* Opentracker */ /* Opentracker */
#include "trackerlogic.h"
#include "ot_mutex.h"
#include "ot_iovec.h"
#include "ot_fullscrape.h" #include "ot_fullscrape.h"
#include "ot_iovec.h"
#include "ot_mutex.h"
#include "trackerlogic.h"
/* Fetch full scrape info for all torrents /* Fetch full scrape info for all torrents
Full scrapes usually are huge and one does not want to Full scrapes usually are huge and one does not want to
allocate more memory. So lets get them in 512k units allocate more memory. So lets get them in 512k units
*/ */
#define OT_SCRAPE_CHUNK_SIZE (1024*1024) #define OT_SCRAPE_CHUNK_SIZE (1024 * 1024)
/* "d8:completei%zde10:downloadedi%zde10:incompletei%zdee" */ /* "d8:completei%zde10:downloadedi%zde10:incompletei%zdee" */
#define OT_SCRAPE_MAXENTRYLEN 256 #define OT_SCRAPE_MAXENTRYLEN 256
/* Forward declaration */ /* Forward declaration */
static void fullscrape_make( int taskid, ot_tasktype mode); static void fullscrape_make(int taskid, ot_tasktype mode);
#ifdef WANT_COMPRESSION_GZIP #ifdef WANT_COMPRESSION_GZIP
static void fullscrape_make_gzip( int taskid, ot_tasktype mode); static void fullscrape_make_gzip(int taskid, ot_tasktype mode);
#endif #endif
/* Converter function from memory to human readable hex strings /* Converter function from memory to human readable hex strings
XXX - Duplicated from ot_stats. Needs fix. */ XXX - Duplicated from ot_stats. Needs fix. */
static char*to_hex(char*d,uint8_t*s){char*m="0123456789ABCDEF";char *t=d;char*e=d+40;while(d<e){*d++=m[*s>>4];*d++=m[*s++&15];}*d=0;return t;} static char *to_hex(char *d, uint8_t *s) {
char *m = "0123456789ABCDEF";
char *t = d;
char *e = d + 40;
while (d < e) {
*d++ = m[*s >> 4];
*d++ = m[*s++ & 15];
}
*d = 0;
return t;
}
/* This is the entry point into this worker thread /* This is the entry point into this worker thread
It grabs tasks from mutex_tasklist and delivers results back It grabs tasks from mutex_tasklist and delivers results back
*/ */
static void * fullscrape_worker( void * args ) { static void *fullscrape_worker(void *args) {
(void) args; (void)args;
while( g_opentracker_running ) { while (g_opentracker_running) {
ot_tasktype tasktype = TASK_FULLSCRAPE; ot_tasktype tasktype = TASK_FULLSCRAPE;
ot_taskid taskid = mutex_workqueue_poptask( &tasktype ); ot_taskid taskid = mutex_workqueue_poptask(&tasktype);
#ifdef WANT_COMPRESSION_GZIP #ifdef WANT_COMPRESSION_GZIP
if (tasktype & TASK_FLAG_GZIP) if (tasktype & TASK_FLAG_GZIP)
fullscrape_make_gzip( taskid, tasktype ); fullscrape_make_gzip(taskid, tasktype);
else else
#endif #endif
fullscrape_make( taskid, tasktype ); fullscrape_make(taskid, tasktype);
mutex_workqueue_pushchunked( taskid, NULL ); mutex_workqueue_pushchunked(taskid, NULL);
} }
return NULL; return NULL;
} }
@ -83,80 +93,87 @@ static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_torrent *torre
size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count; size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count;
switch( mode & TASK_TASK_MASK ) { switch (mode & TASK_TASK_MASK) {
case TASK_FULLSCRAPE: case TASK_FULLSCRAPE:
default: default:
/* push hash as bencoded string */ /* push hash as bencoded string */
*r++='2'; *r++='0'; *r++=':'; *r++ = '2';
memcpy( r, hash, sizeof(ot_hash) ); r += sizeof(ot_hash); *r++ = '0';
*r++ = ':';
memcpy(r, hash, sizeof(ot_hash));
r += sizeof(ot_hash);
/* push rest of the scrape string */ /* push rest of the scrape string */
r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, down_count, peer_count-seed_count ); r += sprintf(r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, down_count, peer_count - seed_count);
break; break;
case TASK_FULLSCRAPE_TPB_ASCII: case TASK_FULLSCRAPE_TPB_ASCII:
to_hex( r, *hash ); r+= 2 * sizeof(ot_hash); to_hex(r, *hash);
r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count ); r += 2 * sizeof(ot_hash);
r += sprintf(r, ":%zd:%zd\n", seed_count, peer_count - seed_count);
break; break;
case TASK_FULLSCRAPE_TPB_ASCII_PLUS: case TASK_FULLSCRAPE_TPB_ASCII_PLUS:
to_hex( r, *hash ); r+= 2 * sizeof(ot_hash); to_hex(r, *hash);
r += sprintf( r, ":%zd:%zd:%zd\n", seed_count, peer_count-seed_count, down_count ); r += 2 * sizeof(ot_hash);
r += sprintf(r, ":%zd:%zd:%zd\n", seed_count, peer_count - seed_count, down_count);
break; break;
case TASK_FULLSCRAPE_TPB_BINARY: case TASK_FULLSCRAPE_TPB_BINARY:
memcpy( r, *hash, sizeof(ot_hash) ); r += sizeof(ot_hash); memcpy(r, *hash, sizeof(ot_hash));
*(uint32_t*)(r+0) = htonl( (uint32_t) seed_count ); r += sizeof(ot_hash);
*(uint32_t*)(r+4) = htonl( (uint32_t)( peer_count-seed_count) ); *(uint32_t *)(r + 0) = htonl((uint32_t)seed_count);
r+=8; *(uint32_t *)(r + 4) = htonl((uint32_t)(peer_count - seed_count));
r += 8;
break; break;
case TASK_FULLSCRAPE_TPB_URLENCODED: case TASK_FULLSCRAPE_TPB_URLENCODED:
r += fmt_urlencoded( r, (char *)*hash, 20 ); r += fmt_urlencoded(r, (char *)*hash, 20);
r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count ); r += sprintf(r, ":%zd:%zd\n", seed_count, peer_count - seed_count);
break; break;
case TASK_FULLSCRAPE_TRACKERSTATE: case TASK_FULLSCRAPE_TRACKERSTATE:
to_hex( r, *hash ); r+= 2 * sizeof(ot_hash); to_hex(r, *hash);
r += sprintf( r, ":%zd:%zd\n", torrent->peer_list6->base, down_count ); r += 2 * sizeof(ot_hash);
r += sprintf(r, ":%zd:%zd\n", torrent->peer_list6->base, down_count);
break; break;
} }
return r; return r;
} }
static void fullscrape_make( int taskid, ot_tasktype mode ) { static void fullscrape_make(int taskid, ot_tasktype mode) {
int bucket; int bucket;
char *r, *re; char *r, *re;
struct iovec iovector = { NULL, 0 }; struct iovec iovector = {NULL, 0};
/* Setup return vector... */ /* Setup return vector... */
r = iovector.iov_base = malloc( OT_SCRAPE_CHUNK_SIZE ); r = iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
if( !r ) if (!r)
return; return;
/* re points to low watermark */ /* re points to low watermark */
re = r + OT_SCRAPE_CHUNK_SIZE - OT_SCRAPE_MAXENTRYLEN; re = r + OT_SCRAPE_CHUNK_SIZE - OT_SCRAPE_MAXENTRYLEN;
if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE ) if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE)
r += sprintf( r, "d5:filesd" ); r += sprintf(r, "d5:filesd");
/* For each bucket... */ /* For each bucket... */
for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
/* Get exclusive access to that bucket */ /* Get exclusive access to that bucket */
ot_vector *torrents_list = mutex_bucket_lock( bucket ); ot_vector *torrents_list = mutex_bucket_lock(bucket);
ot_torrent *torrents = (ot_torrent*)(torrents_list->data); ot_torrent *torrents = (ot_torrent *)(torrents_list->data);
size_t i; size_t i;
/* For each torrent in this bucket.. */ /* For each torrent in this bucket.. */
for( i=0; i<torrents_list->size; ++i ) { for (i = 0; i < torrents_list->size; ++i) {
r = fullscrape_write_one( mode, r, torrents+i, &torrents[i].hash ); r = fullscrape_write_one(mode, r, torrents + i, &torrents[i].hash);
if( r > re) { if (r > re) {
iovector.iov_len = r - (char *)iovector.iov_base; iovector.iov_len = r - (char *)iovector.iov_base;
if (mutex_workqueue_pushchunked(taskid, &iovector) ) { if (mutex_workqueue_pushchunked(taskid, &iovector)) {
free(iovector.iov_base); free(iovector.iov_base);
return mutex_bucket_unlock( bucket, 0 ); return mutex_bucket_unlock(bucket, 0);
} }
/* Allocate a fresh output buffer */ /* Allocate a fresh output buffer */
r = iovector.iov_base = malloc( OT_SCRAPE_CHUNK_SIZE ); r = iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
if( !r ) if (!r)
return mutex_bucket_unlock( bucket, 0 ); return mutex_bucket_unlock(bucket, 0);
/* re points to low watermark */ /* re points to low watermark */
re = r + OT_SCRAPE_CHUNK_SIZE - OT_SCRAPE_MAXENTRYLEN; re = r + OT_SCRAPE_CHUNK_SIZE - OT_SCRAPE_MAXENTRYLEN;
@ -164,132 +181,132 @@ static void fullscrape_make( int taskid, ot_tasktype mode ) {
} }
/* All torrents done: release lock on current bucket */ /* All torrents done: release lock on current bucket */
mutex_bucket_unlock( bucket, 0 ); mutex_bucket_unlock(bucket, 0);
/* Parent thread died? */ /* Parent thread died? */
if( !g_opentracker_running ) if (!g_opentracker_running)
return; return;
} }
if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE ) if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE)
r += sprintf( r, "ee" ); r += sprintf(r, "ee");
/* Send rest of data */ /* Send rest of data */
iovector.iov_len = r - (char *)iovector.iov_base; iovector.iov_len = r - (char *)iovector.iov_base;
if( mutex_workqueue_pushchunked(taskid, &iovector) ) if (mutex_workqueue_pushchunked(taskid, &iovector))
free(iovector.iov_base); free(iovector.iov_base);
} }
#ifdef WANT_COMPRESSION_GZIP #ifdef WANT_COMPRESSION_GZIP
static void fullscrape_make_gzip( int taskid, ot_tasktype mode) { static void fullscrape_make_gzip(int taskid, ot_tasktype mode) {
int bucket; int bucket;
char *r; char *r;
struct iovec iovector = { NULL, 0 }; struct iovec iovector = {NULL, 0};
int zres; int zres;
z_stream strm; z_stream strm;
fprintf(stderr, "GZIP path\n"); fprintf(stderr, "GZIP path\n");
/* Setup return vector... */ /* Setup return vector... */
iovector.iov_base = malloc( OT_SCRAPE_CHUNK_SIZE ); iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
if( !iovector.iov_base ) if (!iovector.iov_base)
return; return;
byte_zero( &strm, sizeof(strm) ); byte_zero(&strm, sizeof(strm));
strm.next_out = (uint8_t*)iovector.iov_base; strm.next_out = (uint8_t *)iovector.iov_base;
strm.avail_out = OT_SCRAPE_CHUNK_SIZE; strm.avail_out = OT_SCRAPE_CHUNK_SIZE;
if( deflateInit2(&strm,7,Z_DEFLATED,31,9,Z_DEFAULT_STRATEGY) != Z_OK ) if (deflateInit2(&strm, 7, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY) != Z_OK)
fprintf( stderr, "not ok.\n" ); fprintf(stderr, "not ok.\n");
if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE ) { if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) {
strm.next_in = (uint8_t*)"d5:filesd"; strm.next_in = (uint8_t *)"d5:filesd";
strm.avail_in = strlen("d5:filesd"); strm.avail_in = strlen("d5:filesd");
zres = deflate( &strm, Z_NO_FLUSH ); zres = deflate(&strm, Z_NO_FLUSH);
} }
/* For each bucket... */ /* For each bucket... */
for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
/* Get exclusive access to that bucket */ /* Get exclusive access to that bucket */
ot_vector *torrents_list = mutex_bucket_lock( bucket ); ot_vector *torrents_list = mutex_bucket_lock(bucket);
ot_torrent *torrents = (ot_torrent*)(torrents_list->data); ot_torrent *torrents = (ot_torrent *)(torrents_list->data);
size_t i; size_t i;
/* For each torrent in this bucket.. */ /* For each torrent in this bucket.. */
for( i=0; i<torrents_list->size; ++i ) { for (i = 0; i < torrents_list->size; ++i) {
char compress_buffer[OT_SCRAPE_MAXENTRYLEN]; char compress_buffer[OT_SCRAPE_MAXENTRYLEN];
r = fullscrape_write_one( mode, compress_buffer, torrents+i, &torrents[i].hash ); r = fullscrape_write_one(mode, compress_buffer, torrents + i, &torrents[i].hash);
strm.next_in = (uint8_t*)compress_buffer; strm.next_in = (uint8_t *)compress_buffer;
strm.avail_in = r - compress_buffer; strm.avail_in = r - compress_buffer;
zres = deflate( &strm, Z_NO_FLUSH ); zres = deflate(&strm, Z_NO_FLUSH);
if( ( zres < Z_OK ) && ( zres != Z_BUF_ERROR ) ) if ((zres < Z_OK) && (zres != Z_BUF_ERROR))
fprintf( stderr, "deflate() failed while in fullscrape_make().\n" ); fprintf(stderr, "deflate() failed while in fullscrape_make().\n");
/* Check if there still is enough buffer left */ /* Check if there still is enough buffer left */
while( !strm.avail_out ) { while (!strm.avail_out) {
iovector.iov_len = (char *)strm.next_out - (char *)iovector.iov_base; iovector.iov_len = (char *)strm.next_out - (char *)iovector.iov_base;
if (mutex_workqueue_pushchunked(taskid, &iovector) ) { if (mutex_workqueue_pushchunked(taskid, &iovector)) {
free(iovector.iov_base); free(iovector.iov_base);
return mutex_bucket_unlock( bucket, 0 ); return mutex_bucket_unlock(bucket, 0);
} }
/* Allocate a fresh output buffer */ /* Allocate a fresh output buffer */
iovector.iov_base = malloc( OT_SCRAPE_CHUNK_SIZE ); iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
if( !iovector.iov_base ) { if (!iovector.iov_base) {
fprintf( stderr, "Out of memory trying to claim ouput buffer\n" ); fprintf(stderr, "Out of memory trying to claim ouput buffer\n");
deflateEnd(&strm); deflateEnd(&strm);
return mutex_bucket_unlock( bucket, 0 ); return mutex_bucket_unlock(bucket, 0);
} }
strm.next_out = (uint8_t*)iovector.iov_base; strm.next_out = (uint8_t *)iovector.iov_base;
strm.avail_out = OT_SCRAPE_CHUNK_SIZE; strm.avail_out = OT_SCRAPE_CHUNK_SIZE;
zres = deflate( &strm, Z_NO_FLUSH ); zres = deflate(&strm, Z_NO_FLUSH);
if( ( zres < Z_OK ) && ( zres != Z_BUF_ERROR ) ) if ((zres < Z_OK) && (zres != Z_BUF_ERROR))
fprintf( stderr, "deflate() failed while in fullscrape_make().\n" ); fprintf(stderr, "deflate() failed while in fullscrape_make().\n");
} }
} }
/* All torrents done: release lock on current bucket */ /* All torrents done: release lock on current bucket */
mutex_bucket_unlock( bucket, 0 ); mutex_bucket_unlock(bucket, 0);
/* Parent thread died? */ /* Parent thread died? */
if( !g_opentracker_running ) if (!g_opentracker_running)
return; return;
} }
if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE ) { if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) {
strm.next_in = (uint8_t*)"ee"; strm.next_in = (uint8_t *)"ee";
strm.avail_in = strlen("ee"); strm.avail_in = strlen("ee");
} }
if( deflate( &strm, Z_FINISH ) < Z_OK ) if (deflate(&strm, Z_FINISH) < Z_OK)
fprintf( stderr, "deflate() failed while in fullscrape_make()'s endgame.\n" ); fprintf(stderr, "deflate() failed while in fullscrape_make()'s endgame.\n");
iovector.iov_len = (char *)strm.next_out - (char *)iovector.iov_base; iovector.iov_len = (char *)strm.next_out - (char *)iovector.iov_base;
if (mutex_workqueue_pushchunked(taskid, &iovector) ) { if (mutex_workqueue_pushchunked(taskid, &iovector)) {
free(iovector.iov_base); free(iovector.iov_base);
return mutex_bucket_unlock( bucket, 0 ); return mutex_bucket_unlock(bucket, 0);
} }
{ {
unsigned int pending; unsigned int pending;
int bits; int bits;
deflatePending( &strm, &pending, &bits); deflatePending(&strm, &pending, &bits);
pending += ( bits ? 1 : 0 ); pending += (bits ? 1 : 0);
if (pending) { if (pending) {
/* Allocate a fresh output buffer */ /* Allocate a fresh output buffer */
iovector.iov_base = malloc( pending ); iovector.iov_base = malloc(pending);
iovector.iov_len = pending; iovector.iov_len = pending;
if( !iovector.iov_base ) { if (!iovector.iov_base) {
fprintf( stderr, "Problem with iovec_fix_increase_or_free\n" ); fprintf(stderr, "Problem with iovec_fix_increase_or_free\n");
deflateEnd(&strm); deflateEnd(&strm);
return mutex_bucket_unlock( bucket, 0 ); return mutex_bucket_unlock(bucket, 0);
} }
strm.next_out = iovector.iov_base; strm.next_out = iovector.iov_base;
strm.avail_out = pending; strm.avail_out = pending;
if( deflate( &strm, Z_FINISH ) < Z_OK ) if (deflate(&strm, Z_FINISH) < Z_OK)
fprintf( stderr, "deflate() failed while in fullscrape_make()'s endgame.\n" ); fprintf(stderr, "deflate() failed while in fullscrape_make()'s endgame.\n");
if( mutex_workqueue_pushchunked(taskid, &iovector) ) if (mutex_workqueue_pushchunked(taskid, &iovector))
free(iovector.iov_base); free(iovector.iov_base);
} }
} }

8
ot_fullscrape.h

@ -8,9 +8,11 @@
#ifdef WANT_FULLSCRAPE #ifdef WANT_FULLSCRAPE
void fullscrape_init( ); #include "ot_mutex.h"
void fullscrape_deinit( );
void fullscrape_deliver( int64 sock, ot_tasktype tasktype ); void fullscrape_init();
void fullscrape_deinit();
void fullscrape_deliver(int64 sock, ot_tasktype tasktype);
#else #else

628
ot_http.c

File diff suppressed because it is too large Load Diff

6
ot_http.h

@ -22,9 +22,9 @@ struct http_data {
STRUCT_HTTP_FLAG flag; STRUCT_HTTP_FLAG flag;
}; };
ssize_t http_handle_request( const int64 s, struct ot_workstruct *ws ); ssize_t http_handle_request(const int64 s, struct ot_workstruct *ws);
ssize_t http_sendiovecdata( const int64 s, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector, int is_partial ); ssize_t http_sendiovecdata(const int64 s, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector, int is_partial);
ssize_t http_issue_error( const int64 s, struct ot_workstruct *ws, int code ); ssize_t http_issue_error(const int64 s, struct ot_workstruct *ws, int code);
extern char *g_stats_path; extern char *g_stats_path;
extern ssize_t g_stats_path_len; extern ssize_t g_stats_path_len;

51
ot_iovec.c

@ -4,27 +4,27 @@
$id$ */ $id$ */
/* System */ /* System */
#include <sys/types.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <sys/types.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <unistd.h>
/* Libowfat */ /* Libowfat */
/* Opentracker */ /* Opentracker */
#include "ot_iovec.h" #include "ot_iovec.h"
void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc ) { void *iovec_increase(int *iovec_entries, struct iovec **iovector, size_t new_alloc) {
void *new_data; void *new_data;
int new_entries = 1 + *iovec_entries; int new_entries = 1 + *iovec_entries;
struct iovec *new_vec = realloc( *iovector, new_entries * sizeof( struct iovec ) ); struct iovec *new_vec = realloc(*iovector, new_entries * sizeof(struct iovec));
if( !new_vec ) if (!new_vec)
return NULL; return NULL;
/* Only allocate after we have a place to store the pointer */ /* Only allocate after we have a place to store the pointer */
new_data = malloc( new_alloc ); new_data = malloc(new_alloc);
if( !new_data ) if (!new_data)
return NULL; return NULL;
new_vec[new_entries - 1].iov_base = new_data; new_vec[new_entries - 1].iov_base = new_data;
@ -35,10 +35,10 @@ void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_al
return new_data; return new_data;
} }
void *iovec_append( int *iovec_entries, struct iovec **iovector, struct iovec *append_iovector) { void *iovec_append(int *iovec_entries, struct iovec **iovector, struct iovec *append_iovector) {
int new_entries = *iovec_entries + 1; int new_entries = *iovec_entries + 1;
struct iovec *new_vec = realloc( *iovector, new_entries * sizeof( struct iovec ) ); struct iovec *new_vec = realloc(*iovector, new_entries * sizeof(struct iovec));
if( !new_vec ) if (!new_vec)
return NULL; return NULL;
/* Take over data from appended iovec */ /* Take over data from appended iovec */
@ -54,40 +54,39 @@ void *iovec_append( int *iovec_entries, struct iovec **iovector, struct iovec *a
return new_vec; return new_vec;
} }
void iovec_free(int *iovec_entries, struct iovec **iovector) {
void iovec_free( int *iovec_entries, struct iovec **iovector ) {
int i; int i;
for( i=0; i<*iovec_entries; ++i ) for (i = 0; i < *iovec_entries; ++i)
free( ((*iovector)[i]).iov_base ); free(((*iovector)[i]).iov_base);
*iovector = NULL; *iovector = NULL;
*iovec_entries = 0; *iovec_entries = 0;
} }
void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr ) { void iovec_fixlast(int *iovec_entries, struct iovec **iovector, void *last_ptr) {
if( *iovec_entries ) { if (*iovec_entries) {
char * base = (char*)((*iovector)[ *iovec_entries - 1 ]).iov_base; char *base = (char *)((*iovector)[*iovec_entries - 1]).iov_base;
size_t new_alloc = ((char*)last_ptr) - base; size_t new_alloc = ((char *)last_ptr) - base;
((*iovector)[*iovec_entries - 1 ]).iov_base = realloc( base, new_alloc ); ((*iovector)[*iovec_entries - 1]).iov_base = realloc(base, new_alloc);
((*iovector)[*iovec_entries - 1 ]).iov_len = new_alloc; ((*iovector)[*iovec_entries - 1]).iov_len = new_alloc;
} }
} }
void *iovec_fix_increase_or_free( int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc ) { void *iovec_fix_increase_or_free(int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc) {
void *new_data; void *new_data;
iovec_fixlast( iovec_entries, iovector, last_ptr ); iovec_fixlast(iovec_entries, iovector, last_ptr);
if( !( new_data = iovec_increase( iovec_entries, iovector, new_alloc ) ) ) if (!(new_data = iovec_increase(iovec_entries, iovector, new_alloc)))
iovec_free( iovec_entries, iovector ); iovec_free(iovec_entries, iovector);
return new_data; return new_data;
} }
size_t iovec_length( const int *iovec_entries, const struct iovec **iovector ) { size_t iovec_length(const int *iovec_entries, const struct iovec **iovector) {
size_t length = 0; size_t length = 0;
int i; int i;
for( i=0; i<*iovec_entries; ++i ) for (i = 0; i < *iovec_entries; ++i)
length += ((*iovector)[i]).iov_len; length += ((*iovector)[i]).iov_len;
return length; return length;
} }

12
ot_iovec.h

@ -8,13 +8,13 @@
#include <sys/uio.h> #include <sys/uio.h>
void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc ); void *iovec_increase(int *iovec_entries, struct iovec **iovector, size_t new_alloc);
void *iovec_append( int *iovec_entries, struct iovec **iovector, struct iovec *append_iovector ); void *iovec_append(int *iovec_entries, struct iovec **iovector, struct iovec *append_iovector);
void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr ); void iovec_fixlast(int *iovec_entries, struct iovec **iovector, void *last_ptr);
void iovec_free( int *iovec_entries, struct iovec **iovector ); void iovec_free(int *iovec_entries, struct iovec **iovector);
size_t iovec_length( const int *iovec_entries, const struct iovec **iovector ); size_t iovec_length(const int *iovec_entries, const struct iovec **iovector);
void *iovec_fix_increase_or_free( int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc ); void *iovec_fix_increase_or_free(int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc);
#endif #endif

154
ot_livesync.c

@ -4,41 +4,41 @@
$id$ */ $id$ */
/* System */ /* System */
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h>
/* Libowfat */ /* Libowfat */
#include "socket.h"
#include "ndelay.h"
#include "byte.h" #include "byte.h"
#include "ip6.h" #include "ip6.h"
#include "ndelay.h"
#include "socket.h"
/* Opentracker */ /* Opentracker */
#include "trackerlogic.h"
#include "ot_livesync.h"
#include "ot_accesslist.h" #include "ot_accesslist.h"
#include "ot_stats.h" #include "ot_livesync.h"
#include "ot_mutex.h" #include "ot_mutex.h"
#include "ot_stats.h"
#include "trackerlogic.h"
#ifdef WANT_SYNC_LIVE #ifdef WANT_SYNC_LIVE
char groupip_1[4] = { 224,0,23,5 }; char groupip_1[4] = {224, 0, 23, 5};
#define LIVESYNC_INCOMING_BUFFSIZE (256*256) #define LIVESYNC_INCOMING_BUFFSIZE (256 * 256)
#define LIVESYNC_OUTGOING_BUFFSIZE_PEERS 1480 #define LIVESYNC_OUTGOING_BUFFSIZE_PEERS 1480
#define LIVESYNC_OUTGOING_WATERMARK_PEERS (sizeof(ot_peer)+sizeof(ot_hash)) #define LIVESYNC_OUTGOING_WATERMARK_PEERS (sizeof(ot_peer) + sizeof(ot_hash))
#define LIVESYNC_MAXDELAY 15 /* seconds */ #define LIVESYNC_MAXDELAY 15 /* seconds */
enum { OT_SYNC_PEER4, OT_SYNC_PEER6 }; enum { OT_SYNC_PEER4, OT_SYNC_PEER6 };
/* Forward declaration */ /* Forward declaration */
static void * livesync_worker( void * args ); static void *livesync_worker(void *args);
/* For outgoing packets */ /* For outgoing packets */
static int64 g_socket_in = -1; static int64 g_socket_in = -1;
@ -57,73 +57,73 @@ static sync_buffer g_v6_buf;
static sync_buffer g_v4_buf; static sync_buffer g_v4_buf;
static pthread_t thread_id; static pthread_t thread_id;
void livesync_init( ) { void livesync_init() {
if( g_socket_in == -1 ) if (g_socket_in == -1)
exerr( "No socket address for live sync specified." ); exerr("No socket address for live sync specified.");
/* Prepare outgoing peers buffer */ /* Prepare outgoing peers buffer */
memcpy( g_v6_buf.data, &g_tracker_id, sizeof( g_tracker_id ) ); memcpy(g_v6_buf.data, &g_tracker_id, sizeof(g_tracker_id));
memcpy( g_v4_buf.data, &g_tracker_id, sizeof( g_tracker_id ) ); memcpy(g_v4_buf.data, &g_tracker_id, sizeof(g_tracker_id));
uint32_pack_big( (char*)g_v6_buf.data + sizeof( g_tracker_id ), OT_SYNC_PEER6); uint32_pack_big((char *)g_v6_buf.data + sizeof(g_tracker_id), OT_SYNC_PEER6);
uint32_pack_big( (char*)g_v4_buf.data + sizeof( g_tracker_id ), OT_SYNC_PEER4); uint32_pack_big((char *)g_v4_buf.data + sizeof(g_tracker_id), OT_SYNC_PEER4);
g_v6_buf.fill = sizeof( g_tracker_id ) + sizeof( uint32_t ); g_v6_buf.fill = sizeof(g_tracker_id) + sizeof(uint32_t);
g_v4_buf.fill = sizeof( g_tracker_id ) + sizeof( uint32_t ); g_v4_buf.fill = sizeof(g_tracker_id) + sizeof(uint32_t);
g_v6_buf.next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY; g_v6_buf.next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY;
g_v4_buf.next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY; g_v4_buf.next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY;
pthread_create( &thread_id, NULL, livesync_worker, NULL ); pthread_create(&thread_id, NULL, livesync_worker, NULL);
} }
void livesync_deinit() { void livesync_deinit() {
if( g_socket_in != -1 ) if (g_socket_in != -1)
close( g_socket_in ); close(g_socket_in);
if( g_socket_out != -1 ) if (g_socket_out != -1)
close( g_socket_out ); close(g_socket_out);
pthread_cancel( thread_id ); pthread_cancel(thread_id);
} }
void livesync_bind_mcast( ot_ip6 ip, uint16_t port) { void livesync_bind_mcast(ot_ip6 ip, uint16_t port) {
char tmpip[4] = {0,0,0,0}; char tmpip[4] = {0, 0, 0, 0};
char *v4ip; char *v4ip;
if( !ip6_isv4mapped(ip)) if (!ip6_isv4mapped(ip))
exerr("v6 mcast support not yet available."); exerr("v6 mcast support not yet available.");
v4ip = ip+12; v4ip = ip + 12;
if( g_socket_in != -1 ) if (g_socket_in != -1)
exerr("Error: Livesync listen ip specified twice."); exerr("Error: Livesync listen ip specified twice.");
if( ( g_socket_in = socket_udp4( )) < 0) if ((g_socket_in = socket_udp4()) < 0)
exerr("Error: Cant create live sync incoming socket." ); exerr("Error: Cant create live sync incoming socket.");
ndelay_off(g_socket_in); ndelay_off(g_socket_in);
if( socket_bind4_reuse( g_socket_in, tmpip, port ) == -1 ) if (socket_bind4_reuse(g_socket_in, tmpip, port) == -1)
exerr("Error: Cant bind live sync incoming socket." ); exerr("Error: Cant bind live sync incoming socket.");
if( socket_mcjoin4( g_socket_in, groupip_1, v4ip ) ) if (socket_mcjoin4(g_socket_in, groupip_1, v4ip))
exerr("Error: Cant make live sync incoming socket join mcast group."); exerr("Error: Cant make live sync incoming socket join mcast group.");
if( ( g_socket_out = socket_udp4()) < 0) if ((g_socket_out = socket_udp4()) < 0)
exerr("Error: Cant create live sync outgoing socket." ); exerr("Error: Cant create live sync outgoing socket.");
if( socket_bind4_reuse( g_socket_out, v4ip, port ) == -1 ) if (socket_bind4_reuse(g_socket_out, v4ip, port) == -1)
exerr("Error: Cant bind live sync outgoing socket." ); exerr("Error: Cant bind live sync outgoing socket.");
socket_mcttl4(g_socket_out, 1); socket_mcttl4(g_socket_out, 1);
socket_mcloop4(g_socket_out, 0); socket_mcloop4(g_socket_out, 0);
} }
/* Caller MUST hold g_outbuf_mutex. Returns with g_outbuf_mutex unlocked */ /* Caller MUST hold g_outbuf_mutex. Returns with g_outbuf_mutex unlocked */
static void livesync_issue_peersync( sync_buffer *buf ) { static void livesync_issue_peersync(sync_buffer *buf) {
char mycopy[LIVESYNC_OUTGOING_BUFFSIZE_PEERS]; char mycopy[LIVESYNC_OUTGOING_BUFFSIZE_PEERS];
size_t fill = buf->fill; size_t fill = buf->fill;
memcpy( mycopy, buf->data, fill ); memcpy(mycopy, buf->data, fill);
buf->fill = sizeof( g_tracker_id ) + sizeof( uint32_t ); buf->fill = sizeof(g_tracker_id) + sizeof(uint32_t);
buf->next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY; buf->next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY;
/* From now this thread has a local copy of the buffer and /* From now this thread has a local copy of the buffer and
@ -133,101 +133,99 @@ static void livesync_issue_peersync( sync_buffer *buf ) {
socket_send4(g_socket_out, mycopy, fill, groupip_1, LIVESYNC_PORT); socket_send4(g_socket_out, mycopy, fill, groupip_1, LIVESYNC_PORT);
} }
static void livesync_handle_peersync( struct ot_workstruct *ws, size_t peer_size ) { static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) {
size_t off = sizeof( g_tracker_id ) + sizeof( uint32_t ); size_t off = sizeof(g_tracker_id) + sizeof(uint32_t);
/* Now basic sanity checks have been done on the live sync packet /* Now basic sanity checks have been done on the live sync packet
We might add more testing and logging. */ We might add more testing and logging. */
while( (ssize_t)(off + sizeof( ot_hash ) + peer_size) <= ws->request_size ) { while ((ssize_t)(off + sizeof(ot_hash) + peer_size) <= ws->request_size) {
memcpy( &ws->peer, ws->request + off + sizeof(ot_hash), peer_size ); memcpy(&ws->peer, ws->request + off + sizeof(ot_hash), peer_size);
ws->hash = (ot_hash*)(ws->request + off); ws->hash = (ot_hash *)(ws->request + off);
if( !g_opentracker_running ) return; if (!g_opentracker_running)
return;
if( OT_PEERFLAG(ws->peer) & PEER_FLAG_STOPPED ) if (OT_PEERFLAG(ws->peer) & PEER_FLAG_STOPPED)
remove_peer_from_torrent( FLAG_MCA, ws ); remove_peer_from_torrent(FLAG_MCA, ws);
else else
add_peer_to_torrent_and_return_peers( FLAG_MCA, ws, /* amount = */ 0 ); add_peer_to_torrent_and_return_peers(FLAG_MCA, ws, /* amount = */ 0);
off += sizeof( ot_hash ) + peer_size; off += sizeof(ot_hash) + peer_size;
} }
stats_issue_event(EVENT_SYNC, 0, stats_issue_event(EVENT_SYNC, 0, (ws->request_size - sizeof(g_tracker_id) - sizeof(uint32_t)) / ((ssize_t)sizeof(ot_hash) + peer_size));
(ws->request_size - sizeof( g_tracker_id ) - sizeof( uint32_t ) ) /
((ssize_t)sizeof( ot_hash ) + peer_size));
} }
/* Tickle the live sync module from time to time, so no events get /* Tickle the live sync module from time to time, so no events get
stuck when there's not enough traffic to fill udp packets fast stuck when there's not enough traffic to fill udp packets fast
enough */ enough */
void livesync_ticker( ) { void livesync_ticker() {
/* livesync_issue_peersync sets g_next_packet_time */ /* livesync_issue_peersync sets g_next_packet_time */
pthread_mutex_lock(&g_outbuf_mutex); pthread_mutex_lock(&g_outbuf_mutex);
if( g_now_seconds > g_v6_buf.next_packet_time && if (g_now_seconds > g_v6_buf.next_packet_time && g_v6_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t))
g_v6_buf.fill > sizeof( g_tracker_id ) + sizeof( uint32_t ) )
livesync_issue_peersync(&g_v6_buf); livesync_issue_peersync(&g_v6_buf);
else else
pthread_mutex_unlock(&g_outbuf_mutex); pthread_mutex_unlock(&g_outbuf_mutex);
pthread_mutex_lock(&g_outbuf_mutex); pthread_mutex_lock(&g_outbuf_mutex);
if( g_now_seconds > g_v4_buf.next_packet_time && if (g_now_seconds > g_v4_buf.next_packet_time && g_v4_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t))
g_v4_buf.fill > sizeof( g_tracker_id ) + sizeof( uint32_t ) )
livesync_issue_peersync(&g_v4_buf); livesync_issue_peersync(&g_v4_buf);
else else
pthread_mutex_unlock(&g_outbuf_mutex); pthread_mutex_unlock(&g_outbuf_mutex);
} }
/* Inform live sync about whats going on. */ /* Inform live sync about whats going on. */
void livesync_tell( struct ot_workstruct *ws ) { void livesync_tell(struct ot_workstruct *ws) {
size_t peer_size; /* initialized in next line */ size_t peer_size; /* initialized in next line */
ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size); ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size);
sync_buffer *dest_buf = peer_size == OT_PEER_SIZE6 ? &g_v6_buf : &g_v4_buf; sync_buffer *dest_buf = peer_size == OT_PEER_SIZE6 ? &g_v6_buf : &g_v4_buf;
pthread_mutex_lock(&g_outbuf_mutex); pthread_mutex_lock(&g_outbuf_mutex);
memcpy( dest_buf->data + dest_buf->fill, ws->hash, sizeof(ot_hash) ); memcpy(dest_buf->data + dest_buf->fill, ws->hash, sizeof(ot_hash));
dest_buf->fill += sizeof(ot_hash); dest_buf->fill += sizeof(ot_hash);
memcpy( dest_buf->data + dest_buf->fill, peer_src, peer_size ); memcpy(dest_buf->data + dest_buf->fill, peer_src, peer_size);
dest_buf->fill += peer_size; dest_buf->fill += peer_size;
if( dest_buf->fill >= LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS ) if (dest_buf->fill >= LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS)
livesync_issue_peersync(dest_buf); livesync_issue_peersync(dest_buf);
else else
pthread_mutex_unlock(&g_outbuf_mutex); pthread_mutex_unlock(&g_outbuf_mutex);
} }
static void * livesync_worker( void * args ) { static void *livesync_worker(void *args) {
struct ot_workstruct ws; struct ot_workstruct ws;
ot_ip6 in_ip; uint16_t in_port; ot_ip6 in_ip;
uint16_t in_port;
(void)args; (void)args;
/* Initialize our "thread local storage" */ /* Initialize our "thread local storage" */
ws.inbuf = ws.request = malloc( LIVESYNC_INCOMING_BUFFSIZE ); ws.inbuf = ws.request = malloc(LIVESYNC_INCOMING_BUFFSIZE);
ws.outbuf = ws.reply = 0; ws.outbuf = ws.reply = 0;
memcpy( in_ip, V4mappedprefix, sizeof( V4mappedprefix ) ); memcpy(in_ip, V4mappedprefix, sizeof(V4mappedprefix));
while( 1 ) { while (1) {
ws.request_size = socket_recv4(g_socket_in, (char*)ws.inbuf, LIVESYNC_INCOMING_BUFFSIZE, 12+(char*)in_ip, &in_port); ws.request_size = socket_recv4(g_socket_in, (char *)ws.inbuf, LIVESYNC_INCOMING_BUFFSIZE, 12 + (char *)in_ip, &in_port);
/* Expect at least tracker id and packet type */ /* Expect at least tracker id and packet type */
if( ws.request_size <= (ssize_t)(sizeof( g_tracker_id ) + sizeof( uint32_t )) ) if (ws.request_size <= (ssize_t)(sizeof(g_tracker_id) + sizeof(uint32_t)))
continue; continue;
if( !accesslist_is_blessed(in_ip, OT_PERMISSION_MAY_LIVESYNC)) if (!accesslist_is_blessed(in_ip, OT_PERMISSION_MAY_LIVESYNC))
continue; continue;
if( !memcmp( ws.inbuf, &g_tracker_id, sizeof( g_tracker_id ) ) ) { if (!memcmp(ws.inbuf, &g_tracker_id, sizeof(g_tracker_id))) {
/* TODO: log packet coming from ourselves */ /* TODO: log packet coming from ourselves */
continue; continue;
} }
switch( uint32_read_big( sizeof( g_tracker_id ) + (char *)ws.inbuf ) ) { switch (uint32_read_big(sizeof(g_tracker_id) + (char *)ws.inbuf)) {
case OT_SYNC_PEER6: case OT_SYNC_PEER6:
livesync_handle_peersync( &ws, OT_PEER_SIZE6 ); livesync_handle_peersync(&ws, OT_PEER_SIZE6);
break; break;
case OT_SYNC_PEER4: case OT_SYNC_PEER4:
livesync_handle_peersync( &ws, OT_PEER_SIZE4 ); livesync_handle_peersync(&ws, OT_PEER_SIZE4);
break; break;
default: default:
break; break;

8
ot_livesync.h

@ -51,18 +51,18 @@ void livesync_init();
void livesync_deinit(); void livesync_deinit();
/* Join multicast group for listening and create sending socket */ /* Join multicast group for listening and create sending socket */
void livesync_bind_mcast( char *ip, uint16_t port ); void livesync_bind_mcast(char *ip, uint16_t port);
/* Inform live sync about whats going on. */ /* Inform live sync about whats going on. */
void livesync_tell( struct ot_workstruct *ws ); void livesync_tell(struct ot_workstruct *ws);
/* Tickle the live sync module from time to time, so no events get /* Tickle the live sync module from time to time, so no events get
stuck when there's not enough traffic to fill udp packets fast stuck when there's not enough traffic to fill udp packets fast
enough */ enough */
void livesync_ticker( ); void livesync_ticker();
/* Handle an incoming live sync packet */ /* Handle an incoming live sync packet */
void handle_livesync( const int64 sock ); void handle_livesync(const int64 sock);
#else #else

125
ot_mutex.c

@ -16,13 +16,13 @@
#include "uint32.h" #include "uint32.h"
/* Opentracker */ /* Opentracker */
#include "trackerlogic.h"
#include "ot_iovec.h" #include "ot_iovec.h"
#include "ot_mutex.h" #include "ot_mutex.h"
#include "ot_stats.h" #include "ot_stats.h"
#include "trackerlogic.h"
/* #define MTX_DBG( STRING ) fprintf( stderr, STRING ) */ /* #define MTX_DBG( STRING ) fprintf( stderr, STRING ) */
#define MTX_DBG( STRING ) #define MTX_DBG(STRING)
/* Our global all torrents list */ /* Our global all torrents list */
static ot_vector all_torrents[OT_BUCKET_COUNT]; static ot_vector all_torrents[OT_BUCKET_COUNT];
@ -32,27 +32,23 @@ static size_t g_torrent_count;
/* Self pipe from opentracker.c */ /* Self pipe from opentracker.c */
extern int g_self_pipe[2]; extern int g_self_pipe[2];
ot_vector *mutex_bucket_lock( int bucket ) { ot_vector *mutex_bucket_lock(int bucket) {
pthread_mutex_lock(bucket_mutex + bucket ); pthread_mutex_lock(bucket_mutex + bucket);
return all_torrents + bucket; return all_torrents + bucket;
} }
ot_vector *mutex_bucket_lock_by_hash( ot_hash const hash ) { ot_vector *mutex_bucket_lock_by_hash(ot_hash const hash) { return mutex_bucket_lock(uint32_read_big((const char *)hash) >> OT_BUCKET_COUNT_SHIFT); }
return mutex_bucket_lock( uint32_read_big( (const char*)hash ) >> OT_BUCKET_COUNT_SHIFT );
}
void mutex_bucket_unlock( int bucket, int delta_torrentcount ) { void mutex_bucket_unlock(int bucket, int delta_torrentcount) {
pthread_mutex_unlock(bucket_mutex + bucket); pthread_mutex_unlock(bucket_mutex + bucket);
g_torrent_count += delta_torrentcount; g_torrent_count += delta_torrentcount;
} }
void mutex_bucket_unlock_by_hash( ot_hash const hash, int delta_torrentcount ) { void mutex_bucket_unlock_by_hash(ot_hash const hash, int delta_torrentcount) {
mutex_bucket_unlock( uint32_read_big( (char*)hash ) >> OT_BUCKET_COUNT_SHIFT, delta_torrentcount ); mutex_bucket_unlock(uint32_read_big((char *)hash) >> OT_BUCKET_COUNT_SHIFT, delta_torrentcount);
} }
size_t mutex_get_torrent_count( ) { size_t mutex_get_torrent_count() { return g_torrent_count; }
return g_torrent_count;
}
/* TaskQueue Magic */ /* TaskQueue Magic */
@ -70,11 +66,11 @@ static struct ot_task *tasklist;
static pthread_mutex_t tasklist_mutex; static pthread_mutex_t tasklist_mutex;
static pthread_cond_t tasklist_being_filled; static pthread_cond_t tasklist_being_filled;
int mutex_workqueue_pushtask( int64 sock, ot_tasktype tasktype ) { int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype) {
struct ot_task ** tmptask, * task; struct ot_task **tmptask, *task;
task = malloc(sizeof( struct ot_task)); task = malloc(sizeof(struct ot_task));
if( !task ) if (!task)
return -1; return -1;
task->taskid = 0; task->taskid = 0;
@ -85,25 +81,25 @@ int mutex_workqueue_pushtask( int64 sock, ot_tasktype tasktype ) {
task->next = 0; task->next = 0;
/* Want exclusive access to tasklist */ /* Want exclusive access to tasklist */
pthread_mutex_lock( &tasklist_mutex ); pthread_mutex_lock(&tasklist_mutex);
/* Skip to end of list */ /* Skip to end of list */
tmptask = &tasklist; tmptask = &tasklist;
while( *tmptask ) while (*tmptask)
tmptask = &(*tmptask)->next; tmptask = &(*tmptask)->next;
*tmptask = task; *tmptask = task;
/* Inform waiting workers and release lock */ /* Inform waiting workers and release lock */
pthread_cond_broadcast( &tasklist_being_filled ); pthread_cond_broadcast(&tasklist_being_filled);
pthread_mutex_unlock( &tasklist_mutex ); pthread_mutex_unlock(&tasklist_mutex);
return 0; return 0;
} }
void mutex_workqueue_canceltask( int64 sock ) { void mutex_workqueue_canceltask(int64 sock) {
struct ot_task ** task; struct ot_task **task;
/* Want exclusive access to tasklist */ /* Want exclusive access to tasklist */
pthread_mutex_lock( &tasklist_mutex ); pthread_mutex_lock(&tasklist_mutex);
for (task = &tasklist; *task; task = &((*task)->next)) for (task = &tasklist; *task; task = &((*task)->next))
if ((*task)->sock == sock) { if ((*task)->sock == sock) {
@ -112,29 +108,29 @@ void mutex_workqueue_canceltask( int64 sock ) {
int i; int i;
/* Free task's iovec */ /* Free task's iovec */
for( i=0; i<(*task)->iovec_entries; ++i ) for (i = 0; i < (*task)->iovec_entries; ++i)
free( iovec[i].iov_base ); free(iovec[i].iov_base);
*task = (*task)->next; *task = (*task)->next;
free( ptask ); free(ptask);
break; break;
} }
/* Release lock */ /* Release lock */
pthread_mutex_unlock( &tasklist_mutex ); pthread_mutex_unlock(&tasklist_mutex);
} }
ot_taskid mutex_workqueue_poptask( ot_tasktype *tasktype ) { ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype) {
struct ot_task * task; struct ot_task *task;
ot_taskid taskid = 0; ot_taskid taskid = 0;
/* Want exclusive access to tasklist */ /* Want exclusive access to tasklist */
pthread_mutex_lock( &tasklist_mutex ); pthread_mutex_lock(&tasklist_mutex);
while( !taskid ) { while (!taskid) {
/* Skip to the first unassigned task this worker wants to do */ /* Skip to the first unassigned task this worker wants to do */
for (task = tasklist; task; task = task->next) for (task = tasklist; task; task = task->next)
if (!task->taskid && ( TASK_CLASS_MASK & task->tasktype ) == *tasktype) { if (!task->taskid && (TASK_CLASS_MASK & task->tasktype) == *tasktype) {
/* If we found an outstanding task, assign a taskid to it /* If we found an outstanding task, assign a taskid to it
and leave the loop */ and leave the loop */
task->taskid = taskid = ++next_free_taskid; task->taskid = taskid = ++next_free_taskid;
@ -144,39 +140,39 @@ ot_taskid mutex_workqueue_poptask( ot_tasktype *tasktype ) {
/* Wait until the next task is being fed */ /* Wait until the next task is being fed */
if (!taskid) if (!taskid)
pthread_cond_wait( &tasklist_being_filled, &tasklist_mutex ); pthread_cond_wait(&tasklist_being_filled, &tasklist_mutex);
} }
/* Release lock */ /* Release lock */
pthread_mutex_unlock( &tasklist_mutex ); pthread_mutex_unlock(&tasklist_mutex);
return taskid; return taskid;
} }
void mutex_workqueue_pushsuccess( ot_taskid taskid ) { void mutex_workqueue_pushsuccess(ot_taskid taskid) {
struct ot_task ** task; struct ot_task **task;
/* Want exclusive access to tasklist */ /* Want exclusive access to tasklist */
pthread_mutex_lock( &tasklist_mutex ); pthread_mutex_lock(&tasklist_mutex);
for (task = &tasklist; *task; task = &((*task)->next)) for (task = &tasklist; *task; task = &((*task)->next))
if ((*task)->taskid == taskid) { if ((*task)->taskid == taskid) {
struct ot_task *ptask = *task; struct ot_task *ptask = *task;
*task = (*task)->next; *task = (*task)->next;
free( ptask ); free(ptask);
break; break;
} }
/* Release lock */ /* Release lock */
pthread_mutex_unlock( &tasklist_mutex ); pthread_mutex_unlock(&tasklist_mutex);
} }
int mutex_workqueue_pushresult( ot_taskid taskid, int iovec_entries, struct iovec *iovec ) { int mutex_workqueue_pushresult(ot_taskid taskid, int iovec_entries, struct iovec *iovec) {
struct ot_task * task; struct ot_task *task;
const char byte = 'o'; const char byte = 'o';
/* Want exclusive access to tasklist */ /* Want exclusive access to tasklist */
pthread_mutex_lock( &tasklist_mutex ); pthread_mutex_lock(&tasklist_mutex);
for (task = tasklist; task; task = task->next) for (task = tasklist; task; task = task->next)
if (task->taskid == taskid) { if (task->taskid == taskid) {
@ -187,25 +183,25 @@ int mutex_workqueue_pushresult( ot_taskid taskid, int iovec_entries, struct iove
} }
/* Release lock */ /* Release lock */
pthread_mutex_unlock( &tasklist_mutex ); pthread_mutex_unlock(&tasklist_mutex);
io_trywrite( g_self_pipe[1], &byte, 1 ); io_trywrite(g_self_pipe[1], &byte, 1);
/* Indicate whether the worker has to throw away results */ /* Indicate whether the worker has to throw away results */
return task ? 0 : -1; return task ? 0 : -1;
} }
int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec) { int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec) {
struct ot_task * task; struct ot_task *task;
const char byte = 'o'; const char byte = 'o';
/* Want exclusive access to tasklist */ /* Want exclusive access to tasklist */
pthread_mutex_lock( &tasklist_mutex ); pthread_mutex_lock(&tasklist_mutex);
for (task = tasklist; task; task = task->next) for (task = tasklist; task; task = task->next)
if (task->taskid == taskid) { if (task->taskid == taskid) {
if( iovec ) { if (iovec) {
if (iovec_append(&task->iovec_entries, &task->iovec, iovec) ) if (iovec_append(&task->iovec_entries, &task->iovec, iovec))
task->tasktype = TASK_DONE_PARTIAL; task->tasktype = TASK_DONE_PARTIAL;
else else
task = NULL; task = NULL;
@ -215,26 +211,25 @@ int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec) {
} }
/* Release lock */ /* Release lock */
pthread_mutex_unlock( &tasklist_mutex ); pthread_mutex_unlock(&tasklist_mutex);
io_trywrite( g_self_pipe[1], &byte, 1 ); io_trywrite(g_self_pipe[1], &byte, 1);
/* Indicate whether the worker has to throw away results */ /* Indicate whether the worker has to throw away results */
return task ? 0 : -1; return task ? 0 : -1;
} }
int64 mutex_workqueue_popresult(int *iovec_entries, struct iovec **iovec, int *is_partial) {
int64 mutex_workqueue_popresult( int *iovec_entries, struct iovec ** iovec, int *is_partial ) { struct ot_task **task;
struct ot_task ** task;
int64 sock = -1; int64 sock = -1;
*is_partial = 0; *is_partial = 0;
/* Want exclusive access to tasklist */ /* Want exclusive access to tasklist */
pthread_mutex_lock( &tasklist_mutex ); pthread_mutex_lock(&tasklist_mutex);
for (task = &tasklist; *task; task = &((*task)->next)) for (task = &tasklist; *task; task = &((*task)->next))
if (((*task)->tasktype & TASK_CLASS_MASK ) == TASK_DONE) { if (((*task)->tasktype & TASK_CLASS_MASK) == TASK_DONE) {
struct ot_task *ptask = *task; struct ot_task *ptask = *task;
*iovec_entries = ptask->iovec_entries; *iovec_entries = ptask->iovec_entries;
*iovec = ptask->iovec; *iovec = ptask->iovec;
@ -242,7 +237,7 @@ int64 mutex_workqueue_popresult( int *iovec_entries, struct iovec ** iovec, int
if ((*task)->tasktype == TASK_DONE) { if ((*task)->tasktype == TASK_DONE) {
*task = ptask->next; *task = ptask->next;
free( ptask ); free(ptask);
} else { } else {
ptask->iovec_entries = 0; ptask->iovec_entries = 0;
ptask->iovec = NULL; ptask->iovec = NULL;
@ -254,26 +249,26 @@ int64 mutex_workqueue_popresult( int *iovec_entries, struct iovec ** iovec, int
} }
/* Release lock */ /* Release lock */
pthread_mutex_unlock( &tasklist_mutex ); pthread_mutex_unlock(&tasklist_mutex);
return sock; return sock;
} }
void mutex_init( ) { void mutex_init() {
int i; int i;
pthread_mutex_init(&tasklist_mutex, NULL); pthread_mutex_init(&tasklist_mutex, NULL);
pthread_cond_init (&tasklist_being_filled, NULL); pthread_cond_init(&tasklist_being_filled, NULL);
for (i=0; i < OT_BUCKET_COUNT; ++i) for (i = 0; i < OT_BUCKET_COUNT; ++i)
pthread_mutex_init(bucket_mutex + i, NULL); pthread_mutex_init(bucket_mutex + i, NULL);
byte_zero( all_torrents, sizeof( all_torrents ) ); byte_zero(all_torrents, sizeof(all_torrents));
} }
void mutex_deinit( ) { void mutex_deinit() {
int i; int i;
for (i=0; i < OT_BUCKET_COUNT; ++i) for (i = 0; i < OT_BUCKET_COUNT; ++i)
pthread_mutex_destroy(bucket_mutex + i); pthread_mutex_destroy(bucket_mutex + i);
pthread_mutex_destroy(&tasklist_mutex); pthread_mutex_destroy(&tasklist_mutex);
pthread_cond_destroy(&tasklist_being_filled); pthread_cond_destroy(&tasklist_being_filled);
byte_zero( all_torrents, sizeof( all_torrents ) ); byte_zero(all_torrents, sizeof(all_torrents));
} }
const char *g_version_mutex_c = "$Source$: $Revision$\n"; const char *g_version_mutex_c = "$Source$: $Revision$\n";

25
ot_mutex.h

@ -7,15 +7,16 @@
#define OT_MUTEX_H__ #define OT_MUTEX_H__
#include <sys/uio.h> #include <sys/uio.h>
#include "trackerlogic.h"
void mutex_init( void ); void mutex_init(void);
void mutex_deinit( void ); void mutex_deinit(void);
ot_vector *mutex_bucket_lock( int bucket ); ot_vector *mutex_bucket_lock(int bucket);
ot_vector *mutex_bucket_lock_by_hash( ot_hash const hash ); ot_vector *mutex_bucket_lock_by_hash(ot_hash const hash);
void mutex_bucket_unlock( int bucket, int delta_torrentcount ); void mutex_bucket_unlock(int bucket, int delta_torrentcount);
void mutex_bucket_unlock_by_hash( ot_hash const hash, int delta_torrentcount ); void mutex_bucket_unlock_by_hash(ot_hash const hash, int delta_torrentcount);
size_t mutex_get_torrent_count(void); size_t mutex_get_torrent_count(void);
@ -67,12 +68,12 @@ typedef enum {
typedef unsigned long ot_taskid; typedef unsigned long ot_taskid;
int mutex_workqueue_pushtask( int64 sock, ot_tasktype tasktype ); int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype);
void mutex_workqueue_canceltask( int64 sock ); void mutex_workqueue_canceltask(int64 sock);
void mutex_workqueue_pushsuccess( ot_taskid taskid ); void mutex_workqueue_pushsuccess(ot_taskid taskid);
ot_taskid mutex_workqueue_poptask( ot_tasktype *tasktype ); ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype);
int mutex_workqueue_pushresult( ot_taskid taskid, int iovec_entries, struct iovec *iovector ); int mutex_workqueue_pushresult(ot_taskid taskid, int iovec_entries, struct iovec *iovector);
int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec); int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec);
int64 mutex_workqueue_popresult( int *iovec_entries, struct iovec ** iovector, int *is_partial ); int64 mutex_workqueue_popresult(int *iovec_entries, struct iovec **iovector, int *is_partial);
#endif #endif

777
ot_stats.c

File diff suppressed because it is too large Load Diff

16
ot_stats.h

@ -6,6 +6,8 @@
#ifndef OT_STATS_H__ #ifndef OT_STATS_H__
#define OT_STATS_H__ #define OT_STATS_H__
#include "trackerlogic.h"
typedef enum { typedef enum {
EVENT_ACCEPT, EVENT_ACCEPT,
EVENT_READ, EVENT_READ,
@ -38,13 +40,13 @@ enum {
CODE_HTTPERROR_COUNT CODE_HTTPERROR_COUNT
}; };
void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event_data ); void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data);
void stats_deliver( int64 sock, int tasktype ); void stats_deliver(int64 sock, int tasktype);
void stats_cleanup( void ); void stats_cleanup(void);
size_t return_stats_for_tracker( char *reply, int mode, int format ); size_t return_stats_for_tracker(char *reply, int mode, int format);
size_t stats_return_tracker_version( char *reply ); size_t stats_return_tracker_version(char *reply);
void stats_init( void ); void stats_init(void);
void stats_deinit( void ); void stats_deinit(void);
extern const char *g_version_rijndael_c; extern const char *g_version_rijndael_c;
extern const char *g_version_livesync_c; extern const char *g_version_livesync_c;

169
ot_udp.c

@ -4,22 +4,22 @@
$id$ */ $id$ */
/* System */ /* System */
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Libowfat */ /* Libowfat */
#include "socket.h"
#include "io.h" #include "io.h"
#include "ip6.h" #include "ip6.h"
#include "socket.h"
/* Opentracker */ /* Opentracker */
#include "trackerlogic.h"
#include "ot_udp.h"
#include "ot_stats.h"
#include "ot_rijndael.h" #include "ot_rijndael.h"
#include "ot_stats.h"
#include "ot_udp.h"
#include "trackerlogic.h"
#if 0 #if 0
static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff }; static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff };
@ -38,7 +38,7 @@ static void udp_generate_rijndael_round_key() {
key[2] = random(); key[2] = random();
key[3] = random(); key[3] = random();
#endif #endif
rijndaelKeySetupEnc128( g_rijndael_round_key, (uint8_t*)key ); rijndaelKeySetupEnc128(g_rijndael_round_key, (uint8_t *)key);
#ifdef WANT_ARC4RANDOM #ifdef WANT_ARC4RANDOM
g_key_of_the_hour[0] = arc4random(); g_key_of_the_hour[0] = arc4random();
@ -49,10 +49,10 @@ static void udp_generate_rijndael_round_key() {
} }
/* Generate current and previous connection id for ip */ /* Generate current and previous connection id for ip */
static void udp_make_connectionid( uint32_t connid[2], const ot_ip6 remoteip, int age ) { static void udp_make_connectionid(uint32_t connid[2], const ot_ip6 remoteip, int age) {
uint32_t plain[4], crypt[4]; uint32_t plain[4], crypt[4];
int i; int i;
if( g_now_minutes + 60 > g_hour_of_the_key ) { if (g_now_minutes + 60 > g_hour_of_the_key) {
g_hour_of_the_key = g_now_minutes; g_hour_of_the_key = g_now_minutes;
g_key_of_the_hour[1] = g_key_of_the_hour[0]; g_key_of_the_hour[1] = g_key_of_the_hour[0];
#ifdef WANT_ARC4RANDOM #ifdef WANT_ARC4RANDOM
@ -62,42 +62,44 @@ static void udp_make_connectionid( uint32_t connid[2], const ot_ip6 remoteip, in
#endif #endif
} }
memcpy( plain, remoteip, sizeof( plain ) ); memcpy(plain, remoteip, sizeof(plain));
for( i=0; i<4; ++i ) plain[i] ^= g_key_of_the_hour[age]; for (i = 0; i < 4; ++i)
rijndaelEncrypt128( g_rijndael_round_key, (uint8_t*)remoteip, (uint8_t*)crypt ); plain[i] ^= g_key_of_the_hour[age];
rijndaelEncrypt128(g_rijndael_round_key, (uint8_t *)remoteip, (uint8_t *)crypt);
connid[0] = crypt[0] ^ crypt[1]; connid[0] = crypt[0] ^ crypt[1];
connid[1] = crypt[2] ^ crypt[3]; connid[1] = crypt[2] ^ crypt[3];
} }
/* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */ /* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */
int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) { int handle_udp6(int64 serversocket, struct ot_workstruct *ws) {
ot_ip6 remoteip; ot_ip6 remoteip;
uint32_t *inpacket = (uint32_t*)ws->inbuf; uint32_t *inpacket = (uint32_t *)ws->inbuf;
uint32_t *outpacket = (uint32_t*)ws->outbuf; uint32_t *outpacket = (uint32_t *)ws->outbuf;
uint32_t left, event, scopeid; uint32_t left, event, scopeid;
uint32_t connid[2]; uint32_t connid[2];
uint32_t action; uint32_t action;
uint16_t port, remoteport; uint16_t port, remoteport;
size_t byte_count, scrape_count; size_t byte_count, scrape_count;
byte_count = socket_recv6( serversocket, ws->inbuf, G_INBUF_SIZE, remoteip, &remoteport, &scopeid ); byte_count = socket_recv6(serversocket, ws->inbuf, G_INBUF_SIZE, remoteip, &remoteport, &scopeid);
if( !byte_count ) return 0; if (!byte_count)
return 0;
stats_issue_event( EVENT_ACCEPT, FLAG_UDP, (uintptr_t)remoteip ); stats_issue_event(EVENT_ACCEPT, FLAG_UDP, (uintptr_t)remoteip);
stats_issue_event( EVENT_READ, FLAG_UDP, byte_count ); stats_issue_event(EVENT_READ, FLAG_UDP, byte_count);
/* Minimum udp tracker packet size, also catches error */ /* Minimum udp tracker packet size, also catches error */
if( byte_count < 16 ) if (byte_count < 16)
return 1; return 1;
/* Get action to take. Ignore error messages and broken packets */ /* Get action to take. Ignore error messages and broken packets */
action = ntohl( inpacket[2] ); action = ntohl(inpacket[2]);
if( action > 2 ) if (action > 2)
return 1; return 1;
/* Generate the connection id we give out and expect to and from /* Generate the connection id we give out and expect to and from
the requesting ip address, this prevents udp spoofing */ the requesting ip address, this prevents udp spoofing */
udp_make_connectionid( connid, remoteip, 0 ); udp_make_connectionid(connid, remoteip, 0);
/* Initialise hash pointer */ /* Initialise hash pointer */
ws->hash = NULL; ws->hash = NULL;
@ -105,25 +107,26 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) {
/* If action is not 0 (connect), then we expect the derived /* If action is not 0 (connect), then we expect the derived
connection id in first 64 bit */ connection id in first 64 bit */
if( ( action > 0 ) && ( inpacket[0] != connid[0] || inpacket[1] != connid[1] ) ) { if ((action > 0) && (inpacket[0] != connid[0] || inpacket[1] != connid[1])) {
/* If connection id does not match, try the one that was /* If connection id does not match, try the one that was
valid in the previous hour. Only if this also does not valid in the previous hour. Only if this also does not
match, return an error packet */ match, return an error packet */
udp_make_connectionid( connid, remoteip, 1 ); udp_make_connectionid(connid, remoteip, 1);
if( inpacket[0] != connid[0] || inpacket[1] != connid[1] ) { if (inpacket[0] != connid[0] || inpacket[1] != connid[1]) {
const size_t s = sizeof( "Connection ID missmatch." ); const size_t s = sizeof("Connection ID missmatch.");
outpacket[0] = htonl( 3 ); outpacket[1] = inpacket[3]; outpacket[0] = htonl(3);
memcpy( &outpacket[2], "Connection ID missmatch.", s ); outpacket[1] = inpacket[3];
socket_send6( serversocket, ws->outbuf, 8 + s, remoteip, remoteport, 0 ); memcpy(&outpacket[2], "Connection ID missmatch.", s);
stats_issue_event( EVENT_CONNID_MISSMATCH, FLAG_UDP, 8 + s ); socket_send6(serversocket, ws->outbuf, 8 + s, remoteip, remoteport, 0);
stats_issue_event(EVENT_CONNID_MISSMATCH, FLAG_UDP, 8 + s);
return 1; return 1;
} }
} }
switch( action ) { switch (action) {
case 0: /* This is a connect action */ case 0: /* This is a connect action */
/* look for udp bittorrent magic id */ /* look for udp bittorrent magic id */
if( (ntohl(inpacket[0]) != 0x00000417) || (ntohl(inpacket[1]) != 0x27101980) ) if ((ntohl(inpacket[0]) != 0x00000417) || (ntohl(inpacket[1]) != 0x27101980))
return 1; return 1;
outpacket[0] = 0; outpacket[0] = 0;
@ -131,99 +134,105 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) {
outpacket[2] = connid[0]; outpacket[2] = connid[0];
outpacket[3] = connid[1]; outpacket[3] = connid[1];
socket_send6( serversocket, ws->outbuf, 16, remoteip, remoteport, 0 ); socket_send6(serversocket, ws->outbuf, 16, remoteip, remoteport, 0);
stats_issue_event( EVENT_CONNECT, FLAG_UDP, 16 ); stats_issue_event(EVENT_CONNECT, FLAG_UDP, 16);
break; break;
case 1: /* This is an announce action */ case 1: /* This is an announce action */
/* Minimum udp announce packet size */ /* Minimum udp announce packet size */
if( byte_count < 98 ) if (byte_count < 98)
return 1; return 1;
/* We do only want to know, if it is zero */ /* We do only want to know, if it is zero */
left = inpacket[64/4] | inpacket[68/4]; left = inpacket[64 / 4] | inpacket[68 / 4];
event = ntohl( inpacket[80/4] ); event = ntohl(inpacket[80 / 4]);
port = *(uint16_t*)( ((char*)inpacket) + 96 ); port = *(uint16_t *)(((char *)inpacket) + 96);
ws->hash = (ot_hash*)( ((char*)inpacket) + 16 ); ws->hash = (ot_hash *)(((char *)inpacket) + 16);
OT_SETIP( ws->peer, remoteip ); OT_SETIP(ws->peer, remoteip);
OT_SETPORT( ws->peer, &port ); OT_SETPORT(ws->peer, &port);
OT_PEERFLAG( ws->peer ) = 0; OT_PEERFLAG(ws->peer) = 0;
switch( event ) { switch (event) {
case 1: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED; break; case 1:
case 3: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED; break; OT_PEERFLAG(ws->peer) |= PEER_FLAG_COMPLETED;
default: break; break;
case 3:
OT_PEERFLAG(ws->peer) |= PEER_FLAG_STOPPED;
break;
default:
break;
} }
if( !left ) if (!left)
OT_PEERFLAG( ws->peer ) |= PEER_FLAG_SEEDING; OT_PEERFLAG(ws->peer) |= PEER_FLAG_SEEDING;
outpacket[0] = htonl( 1 ); /* announce action */ outpacket[0] = htonl(1); /* announce action */
outpacket[1] = inpacket[12/4]; outpacket[1] = inpacket[12 / 4];
if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_STOPPED ) { /* Peer is gone. */ if (OT_PEERFLAG(ws->peer) & PEER_FLAG_STOPPED) { /* Peer is gone. */
ws->reply = ws->outbuf; ws->reply = ws->outbuf;
ws->reply_size = remove_peer_from_torrent( FLAG_UDP, ws ); ws->reply_size = remove_peer_from_torrent(FLAG_UDP, ws);
} else { } else {
/* Limit amount of peers to OT_MAX_PEERS_UDP */ /* Limit amount of peers to OT_MAX_PEERS_UDP */
uint32_t numwant = ntohl( inpacket[92/4] ); uint32_t numwant = ntohl(inpacket[92 / 4]);
size_t max_peers = ip6_isv4mapped(remoteip) ? OT_MAX_PEERS_UDP4 : OT_MAX_PEERS_UDP6; size_t max_peers = ip6_isv4mapped(remoteip) ? OT_MAX_PEERS_UDP4 : OT_MAX_PEERS_UDP6;
if (numwant > max_peers) numwant = max_peers; if (numwant > max_peers)
numwant = max_peers;
ws->reply = ws->outbuf + 8; ws->reply = ws->outbuf + 8;
ws->reply_size = 8 + add_peer_to_torrent_and_return_peers( FLAG_UDP, ws, numwant ); ws->reply_size = 8 + add_peer_to_torrent_and_return_peers(FLAG_UDP, ws, numwant);
} }
socket_send6( serversocket, ws->outbuf, ws->reply_size, remoteip, remoteport, 0 ); socket_send6(serversocket, ws->outbuf, ws->reply_size, remoteip, remoteport, 0);
stats_issue_event( EVENT_ANNOUNCE, FLAG_UDP, ws->reply_size ); stats_issue_event(EVENT_ANNOUNCE, FLAG_UDP, ws->reply_size);
break; break;
case 2: /* This is a scrape action */ case 2: /* This is a scrape action */
outpacket[0] = htonl( 2 ); /* scrape action */ outpacket[0] = htonl(2); /* scrape action */
outpacket[1] = inpacket[12/4]; outpacket[1] = inpacket[12 / 4];
for( scrape_count = 0; ( scrape_count * 20 < byte_count - 16) && ( scrape_count <= 74 ); scrape_count++ ) for (scrape_count = 0; (scrape_count * 20 < byte_count - 16) && (scrape_count <= 74); scrape_count++)
return_udp_scrape_for_torrent( *(ot_hash*)( ((char*)inpacket) + 16 + 20 * scrape_count ), ((char*)outpacket) + 8 + 12 * scrape_count ); return_udp_scrape_for_torrent(*(ot_hash *)(((char *)inpacket) + 16 + 20 * scrape_count), ((char *)outpacket) + 8 + 12 * scrape_count);
socket_send6( serversocket, ws->outbuf, 8 + 12 * scrape_count, remoteip, remoteport, 0 ); socket_send6(serversocket, ws->outbuf, 8 + 12 * scrape_count, remoteip, remoteport, 0);
stats_issue_event( EVENT_SCRAPE, FLAG_UDP, scrape_count ); stats_issue_event(EVENT_SCRAPE, FLAG_UDP, scrape_count);
break; break;
} }
return 1; return 1;
} }
static void* udp_worker( void * args ) { static void *udp_worker(void *args) {
int64 sock = (int64)args; int64 sock = (int64)args;
struct ot_workstruct ws; struct ot_workstruct ws;
memset( &ws, 0, sizeof(ws) ); memset(&ws, 0, sizeof(ws));
ws.inbuf=malloc(G_INBUF_SIZE); ws.inbuf = malloc(G_INBUF_SIZE);
ws.outbuf=malloc(G_OUTBUF_SIZE); ws.outbuf = malloc(G_OUTBUF_SIZE);
#ifdef _DEBUG_HTTPERROR #ifdef _DEBUG_HTTPERROR
ws.debugbuf=malloc(G_DEBUGBUF_SIZE); ws.debugbuf = malloc(G_DEBUGBUF_SIZE);
#endif #endif
while( g_opentracker_running ) while (g_opentracker_running)
handle_udp6( sock, &ws ); handle_udp6(sock, &ws);
free( ws.inbuf ); free(ws.inbuf);
free( ws.outbuf ); free(ws.outbuf);
#ifdef _DEBUG_HTTPERROR #ifdef _DEBUG_HTTPERROR
free( ws.debugbuf ); free(ws.debugbuf);
#endif #endif
return NULL; return NULL;
} }
void udp_init( int64 sock, unsigned int worker_count ) { void udp_init(int64 sock, unsigned int worker_count) {
pthread_t thread_id; pthread_t thread_id;
if( !g_rijndael_round_key[0] ) if (!g_rijndael_round_key[0])
udp_generate_rijndael_round_key(); udp_generate_rijndael_round_key();
#ifdef _DEBUG #ifdef _DEBUG
fprintf( stderr, " installing %d workers on udp socket %ld\n", worker_count, (unsigned long)sock ); fprintf(stderr, " installing %d workers on udp socket %ld\n", worker_count, (unsigned long)sock);
#endif #endif
while( worker_count-- ) while (worker_count--)
pthread_create( &thread_id, NULL, udp_worker, (void *)sock ); pthread_create(&thread_id, NULL, udp_worker, (void *)sock);
} }
const char *g_version_udp_c = "$Source$: $Revision$\n"; const char *g_version_udp_c = "$Source$: $Revision$\n";

4
ot_udp.h

@ -6,7 +6,7 @@
#ifndef OT_UDP_H__ #ifndef OT_UDP_H__
#define OT_UDP_H__ #define OT_UDP_H__
void udp_init( int64 sock, unsigned int worker_count ); void udp_init(int64 sock, unsigned int worker_count);
int handle_udp6( int64 serversocket, struct ot_workstruct *ws ); int handle_udp6(int64 serversocket, struct ot_workstruct *ws);
#endif #endif

212
ot_vector.c

@ -4,43 +4,37 @@
$id$ */ $id$ */
/* System */ /* System */
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <stdint.h>
#include <stddef.h>
/* Opentracker */ /* Opentracker */
#include "trackerlogic.h" #include "trackerlogic.h"
#include "ot_vector.h"
/* Libowfat */ /* Libowfat */
#include "uint32.h"
#include "uint16.h" #include "uint16.h"
#include "uint32.h"
static int vector_compare_peer6(const void *peer1, const void *peer2 ) { static int vector_compare_peer6(const void *peer1, const void *peer2) { return memcmp(peer1, peer2, OT_PEER_COMPARE_SIZE6); }
return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE6 ); static int vector_compare_peer4(const void *peer1, const void *peer2) { return memcmp(peer1, peer2, OT_PEER_COMPARE_SIZE4); }
}
static int vector_compare_peer4(const void *peer1, const void *peer2 ) {
return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE4 );
}
/* 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
*/ */
void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, 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 compare_size, int *exactmatch ) {
size_t interval = member_count; size_t interval = member_count;
while( interval ) { while (interval) {
uint8_t *lookat = ((uint8_t*)base) + member_size * ( interval / 2 ); uint8_t *lookat = ((uint8_t *)base) + member_size * (interval / 2);
int cmp = memcmp( lookat, key, compare_size ); int cmp = memcmp(lookat, key, compare_size);
if(cmp == 0 ) { if (cmp == 0) {
base = lookat; base = lookat;
break; break;
} }
if(cmp < 0) { if (cmp < 0) {
base = lookat + member_size; base = lookat + member_size;
interval--; interval--;
} }
@ -48,13 +42,14 @@ void *binary_search( const void * const key, const void * base, const size_t mem
} }
*exactmatch = interval; *exactmatch = interval;
return (void*)base; return (void *)base;
} }
static uint8_t vector_hash_peer( ot_peer const *peer, size_t compare_size, int bucket_count ) { static uint8_t vector_hash_peer(ot_peer const *peer, size_t compare_size, int bucket_count) {
unsigned int hash = 5381; unsigned int hash = 5381;
uint8_t *p = (uint8_t*)peer; uint8_t *p = (uint8_t *)peer;
while( compare_size-- ) hash += (hash<<5) + *(p++); while (compare_size--)
hash += (hash << 5) + *(p++);
return hash % bucket_count; return hash % bucket_count;
} }
@ -65,49 +60,53 @@ static uint8_t vector_hash_peer( ot_peer const *peer, size_t compare_size, int b
if it wasn't found in vector. Caller needs to check the passed "exactmatch" variable to see, whether an insert if it wasn't found in vector. Caller needs to check the passed "exactmatch" variable to see, whether an insert
took place. If resizing the vector failed, NULL is returned, else the pointer to the object in vector. took place. If resizing the vector failed, NULL is returned, else the pointer to the object in vector.
*/ */
void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch) {
uint8_t *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); uint8_t *match = binary_search(key, vector->data, vector->size, member_size, compare_size, exactmatch);
if( *exactmatch ) return match; if (*exactmatch)
return match;
if( vector->size + 1 > vector->space ) { if (vector->size + 1 > vector->space) {
size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
uint8_t *new_data = realloc( vector->data, new_space * member_size ); uint8_t *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 - (uint8_t*)vector->data); match = new_data + (match - (uint8_t *)vector->data);
vector->data = new_data; vector->data = new_data;
vector->space = new_space; vector->space = new_space;
} }
memmove( match + member_size, match, ((uint8_t*)vector->data) + member_size * vector->size - match ); memmove(match + member_size, match, ((uint8_t *)vector->data) + member_size * vector->size - match);
vector->size++; vector->size++;
return match; return match;
} }
ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch ) { ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch) {
ot_peer *match, *end; ot_peer *match, *end;
const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
size_t match_to_end; size_t match_to_end;
/* If space is zero but size is set, we're dealing with a list of vector->size buckets */ /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
if( vector->space < vector->size ) if (vector->space < vector->size)
vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, compare_size, vector->size ); vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size);
match = binary_search( peer, vector->data, vector->size, peer_size, compare_size, exactmatch ); match = binary_search(peer, vector->data, vector->size, peer_size, compare_size, exactmatch);
if( *exactmatch ) return match; if (*exactmatch)
return match;
/* This is the amount of bytes that needs to be pushed backwards by peer_size bytes to make room for new peer */ /* This is the amount of bytes that needs to be pushed backwards by peer_size bytes to make room for new peer */
end = (ot_peer*)vector->data + vector->size * peer_size; end = (ot_peer *)vector->data + vector->size * peer_size;
match_to_end = end - match; match_to_end = end - match;
if( vector->size + 1 > vector->space ) { if (vector->size + 1 > vector->space) {
ptrdiff_t offset = match - (ot_peer*)vector->data; ptrdiff_t offset = match - (ot_peer *)vector->data;
size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
ot_peer *new_data = realloc( vector->data, new_space * peer_size ); ot_peer *new_data = realloc(vector->data, new_space * peer_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 + offset; match = new_data + offset;
@ -116,7 +115,7 @@ ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, siz
} }
/* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */ /* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */
memmove( match + peer_size, match, match_to_end); memmove(match + peer_size, match, match_to_end);
vector->size++; vector->size++;
return match; return match;
@ -127,130 +126,134 @@ ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, siz
1 if a non-seeding peer was removed 1 if a non-seeding peer was removed
2 if a seeding peer was removed 2 if a seeding peer was removed
*/ */
int vector_remove_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size) { int vector_remove_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size) {
int exactmatch, was_seeder; int exactmatch, was_seeder;
ot_peer *match, *end; ot_peer *match, *end;
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
if( !vector->size ) return 0; if (!vector->size)
return 0;
/* If space is zero but size is set, we're dealing with a list of vector->size buckets */ /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
if( vector->space < vector->size ) if (vector->space < vector->size)
vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, compare_size, vector->size ); vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size);
end = ((ot_peer*)vector->data) + peer_size * vector->size; end = ((ot_peer *)vector->data) + peer_size * vector->size;
match = (ot_peer*)binary_search( peer, vector->data, vector->size, peer_size, compare_size, &exactmatch ); match = (ot_peer *)binary_search(peer, vector->data, vector->size, peer_size, compare_size, &exactmatch);
if( !exactmatch ) return 0; if (!exactmatch)
return 0;
was_seeder = ( OT_PEERFLAG_D( match, peer_size ) & PEER_FLAG_SEEDING ) ? 2 : 1; was_seeder = (OT_PEERFLAG_D(match, peer_size) & PEER_FLAG_SEEDING) ? 2 : 1;
memmove( match, match + peer_size, end - match - peer_size ); memmove(match, match + peer_size, end - match - peer_size);
vector->size--; vector->size--;
vector_fixup_peers( vector, peer_size ); vector_fixup_peers(vector, peer_size);
return was_seeder; return was_seeder;
} }
void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { void vector_remove_torrent(ot_vector *vector, ot_torrent *match) {
ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; ot_torrent *end = ((ot_torrent *)vector->data) + vector->size;
if( !vector->size ) return; if (!vector->size)
return;
/* 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 */
free_peerlist( match->peer_list6 ); free_peerlist(match->peer_list6);
free_peerlist( match->peer_list4 ); free_peerlist(match->peer_list4);
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_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) { if ((--vector->size * OT_VECTOR_SHRINK_THRESH < vector->space) && (vector->space >= OT_VECTOR_SHRINK_RATIO * 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));
} }
} }
void vector_clean_list( ot_vector * vector, int num_buckets ) { void vector_clean_list(ot_vector *vector, int num_buckets) {
while( num_buckets-- ) while (num_buckets--)
free( vector[num_buckets].data ); free(vector[num_buckets].data);
free( vector ); free(vector);
return; return;
} }
void vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size ) { void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) {
int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1; int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1;
ot_vector * bucket_list_new, * bucket_list_old = &peer_list->peers; ot_vector *bucket_list_new, *bucket_list_old = &peer_list->peers;
int (*sort_func)(const void *, const void *) = int (*sort_func)(const void *, const void *) = peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4;
peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4;
if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { if (OT_PEERLIST_HASBUCKETS(peer_list)) {
num_buckets_old = peer_list->peers.size; num_buckets_old = peer_list->peers.size;
bucket_list_old = peer_list->peers.data; bucket_list_old = peer_list->peers.data;
} }
if( peer_list->peer_count < 255 ) if (peer_list->peer_count < 255)
num_buckets_new = 1; num_buckets_new = 1;
else if( peer_list->peer_count > 8192 ) else if (peer_list->peer_count > 8192)
num_buckets_new = 64; num_buckets_new = 64;
else if( peer_list->peer_count >= 512 && peer_list->peer_count < 4096 ) else if (peer_list->peer_count >= 512 && peer_list->peer_count < 4096)
num_buckets_new = 16; num_buckets_new = 16;
else if( peer_list->peer_count < 512 && num_buckets_old <= 16 ) else if (peer_list->peer_count < 512 && num_buckets_old <= 16)
num_buckets_new = num_buckets_old; num_buckets_new = num_buckets_old;
else if( peer_list->peer_count < 512 ) else if (peer_list->peer_count < 512)
num_buckets_new = 1; num_buckets_new = 1;
else if( peer_list->peer_count < 8192 && num_buckets_old > 1 ) else if (peer_list->peer_count < 8192 && num_buckets_old > 1)
num_buckets_new = num_buckets_old; num_buckets_new = num_buckets_old;
else else
num_buckets_new = 16; num_buckets_new = 16;
if( num_buckets_new == num_buckets_old ) if (num_buckets_new == num_buckets_old)
return; return;
/* Assume near perfect distribution */ /* Assume near perfect distribution */
bucket_list_new = malloc( num_buckets_new * sizeof( ot_vector ) ); bucket_list_new = malloc(num_buckets_new * sizeof(ot_vector));
if( !bucket_list_new) return; if (!bucket_list_new)
bzero( bucket_list_new, num_buckets_new * sizeof( ot_vector ) ); return;
bzero(bucket_list_new, num_buckets_new * sizeof(ot_vector));
tmp = peer_list->peer_count / num_buckets_new; tmp = peer_list->peer_count / num_buckets_new;
bucket_size_new = OT_VECTOR_MIN_MEMBERS; bucket_size_new = OT_VECTOR_MIN_MEMBERS;
while( bucket_size_new < tmp) while (bucket_size_new < tmp)
bucket_size_new *= OT_VECTOR_GROW_RATIO; bucket_size_new *= OT_VECTOR_GROW_RATIO;
/* preallocate vectors to hold all peers */ /* preallocate vectors to hold all peers */
for( bucket=0; bucket<num_buckets_new; ++bucket ) { for (bucket = 0; bucket < num_buckets_new; ++bucket) {
bucket_list_new[bucket].space = bucket_size_new; bucket_list_new[bucket].space = bucket_size_new;
bucket_list_new[bucket].data = malloc( bucket_size_new * peer_size ); bucket_list_new[bucket].data = malloc(bucket_size_new * peer_size);
if( !bucket_list_new[bucket].data ) if (!bucket_list_new[bucket].data)
return vector_clean_list( bucket_list_new, num_buckets_new ); return vector_clean_list(bucket_list_new, num_buckets_new);
} }
/* Now sort them into the correct bucket */ /* Now sort them into the correct bucket */
for( bucket=0; bucket<num_buckets_old; ++bucket ) { for (bucket = 0; bucket < num_buckets_old; ++bucket) {
ot_peer * peers_old = bucket_list_old[bucket].data; ot_peer *peers_old = bucket_list_old[bucket].data;
int peer_count_old = bucket_list_old[bucket].size; int peer_count_old = bucket_list_old[bucket].size;
while( peer_count_old-- ) { while (peer_count_old--) {
ot_vector * bucket_dest = bucket_list_new; ot_vector *bucket_dest = bucket_list_new;
if( num_buckets_new > 1 ) if (num_buckets_new > 1)
bucket_dest += vector_hash_peer(peers_old, OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size), num_buckets_new); bucket_dest += vector_hash_peer(peers_old, OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size), num_buckets_new);
if( bucket_dest->size + 1 > bucket_dest->space ) { if (bucket_dest->size + 1 > bucket_dest->space) {
void * tmp = realloc( bucket_dest->data, peer_size * OT_VECTOR_GROW_RATIO * bucket_dest->space ); void *tmp = realloc(bucket_dest->data, peer_size * OT_VECTOR_GROW_RATIO * bucket_dest->space);
if( !tmp ) return vector_clean_list( bucket_list_new, num_buckets_new ); if (!tmp)
return vector_clean_list(bucket_list_new, num_buckets_new);
bucket_dest->data = tmp; bucket_dest->data = tmp;
bucket_dest->space *= OT_VECTOR_GROW_RATIO; bucket_dest->space *= OT_VECTOR_GROW_RATIO;
} }
memcpy((ot_peer*)bucket_dest->data + peer_size * bucket_dest->size++, peers_old, peer_size); memcpy((ot_peer *)bucket_dest->data + peer_size * bucket_dest->size++, peers_old, peer_size);
peers_old += peer_size; peers_old += peer_size;
} }
} }
/* Now sort each bucket to later allow bsearch */ /* Now sort each bucket to later allow bsearch */
for( bucket=0; bucket<num_buckets_new; ++bucket ) for (bucket = 0; bucket < num_buckets_new; ++bucket)
qsort( bucket_list_new[bucket].data, bucket_list_new[bucket].size, peer_size, sort_func ); qsort(bucket_list_new[bucket].data, bucket_list_new[bucket].size, peer_size, sort_func);
/* Everything worked fine. Now link new bucket_list to peer_list */ /* Everything worked fine. Now link new bucket_list to peer_list */
if( OT_PEERLIST_HASBUCKETS( peer_list) ) if (OT_PEERLIST_HASBUCKETS(peer_list))
vector_clean_list( (ot_vector*)peer_list->peers.data, peer_list->peers.size ); vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size);
else else
free( peer_list->peers.data ); free(peer_list->peers.data);
if( num_buckets_new > 1 ) { if (num_buckets_new > 1) {
peer_list->peers.data = bucket_list_new; peer_list->peers.data = bucket_list_new;
peer_list->peers.size = num_buckets_new; peer_list->peers.size = num_buckets_new;
peer_list->peers.space = 0; /* Magic marker for "is list of buckets" */ peer_list->peers.space = 0; /* Magic marker for "is list of buckets" */
@ -258,27 +261,26 @@ void vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size ) {
peer_list->peers.data = bucket_list_new->data; peer_list->peers.data = bucket_list_new->data;
peer_list->peers.size = bucket_list_new->size; peer_list->peers.size = bucket_list_new->size;
peer_list->peers.space = bucket_list_new->space; peer_list->peers.space = bucket_list_new->space;
free( bucket_list_new ); free(bucket_list_new);
} }
} }
void vector_fixup_peers( ot_vector * vector, size_t peer_size ) { void vector_fixup_peers(ot_vector *vector, size_t peer_size) {
int need_fix = 0; int need_fix = 0;
if( !vector->size ) { if (!vector->size) {
free( vector->data ); free(vector->data);
vector->data = NULL; vector->data = NULL;
vector->space = 0; vector->space = 0;
return; return;
} }
while( ( vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && while ((vector->size * OT_VECTOR_SHRINK_THRESH < vector->space) && (vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS)) {
( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) {
vector->space /= OT_VECTOR_SHRINK_RATIO; vector->space /= OT_VECTOR_SHRINK_RATIO;
need_fix++; need_fix++;
} }
if( need_fix ) if (need_fix)
vector->data = realloc( vector->data, vector->space * peer_size ); vector->data = realloc(vector->data, vector->space * peer_size);
} }
const char *g_version_vector_c = "$Source$: $Revision$\n"; const char *g_version_vector_c = "$Source$: $Revision$\n";

17
ot_vector.h

@ -21,17 +21,16 @@ typedef struct {
size_t space; size_t space;
} ot_vector; } ot_vector;
void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, 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 compare_size, int *exactmatch ); void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch);
void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ); ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch);
ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch );
int vector_remove_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size); int vector_remove_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size);
void vector_remove_torrent( ot_vector *vector, ot_torrent *match ); void vector_remove_torrent(ot_vector *vector, ot_torrent *match);
/* For ot_clean.c */ /* For ot_clean.c */
void vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size ); void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size);
void vector_fixup_peers( ot_vector * vector, size_t peer_size ); void vector_fixup_peers(ot_vector *vector, size_t peer_size);
void vector_clean_list( ot_vector * vector, int num_buckets); void vector_clean_list(ot_vector *vector, int num_buckets);
#endif #endif

89
scan_urlencoded_query.c

@ -45,37 +45,45 @@ static const unsigned char is_unreserved[256] = {
/* Do a fast nibble to hex representation conversion */ /* Do a fast nibble to hex representation conversion */
static unsigned char fromhex(unsigned char x) { static unsigned char fromhex(unsigned char x) {
x-='0'; if( x<=9) return x; x -= '0';
x&=~0x20; x-='A'-'0'; if (x <= 9)
if( x<6 ) return x+10; return x;
x &= ~0x20;
x -= 'A' - '0';
if (x < 6)
return x + 10;
return 0xff; return 0xff;
} }
/* Skip the value of a param=value pair */ /* Skip the value of a param=value pair */
void scan_urlencoded_skipvalue( char **string ) { void scan_urlencoded_skipvalue(char **string) {
const unsigned char* s=*(const unsigned char**) string; const unsigned char *s = *(const unsigned char **)string;
unsigned char f; unsigned char f;
/* Since we are asked to skip the 'value', we assume to stop at /* Since we are asked to skip the 'value', we assume to stop at
terminators for a 'value' string position */ terminators for a 'value' string position */
while( ( f = is_unreserved[ *s++ ] ) & SCAN_SEARCHPATH_VALUE ); while ((f = is_unreserved[*s++]) & SCAN_SEARCHPATH_VALUE)
;
/* If we stopped at a hard terminator like \0 or \n, make the /* If we stopped at a hard terminator like \0 or \n, make the
next scan_urlencoded_query encounter it again */ next scan_urlencoded_query encounter it again */
if( f & SCAN_SEARCHPATH_TERMINATOR ) --s; if (f & SCAN_SEARCHPATH_TERMINATOR)
--s;
*string = (char*)s; *string = (char *)s;
} }
int scan_find_keywords( const ot_keywords * keywords, char **string, SCAN_SEARCHPATH_FLAG flags) { int scan_find_keywords(const ot_keywords *keywords, char **string, SCAN_SEARCHPATH_FLAG flags) {
char *deststring = *string; char *deststring = *string;
ssize_t match_length = scan_urlencoded_query(string, deststring, flags ); ssize_t match_length = scan_urlencoded_query(string, deststring, flags);
if( match_length < 0 ) return match_length; if (match_length < 0)
if( match_length == 0 ) return -3; return match_length;
if (match_length == 0)
return -3;
while( keywords->key ) { while (keywords->key) {
if( !strncmp( keywords->key, deststring, match_length ) && !keywords->key[match_length] ) if (!strncmp(keywords->key, deststring, match_length) && !keywords->key[match_length])
return keywords->value; return keywords->value;
keywords++; keywords++;
} }
@ -84,59 +92,74 @@ int scan_find_keywords( const ot_keywords * keywords, char **string, SCAN_SEARCH
} }
ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags) { ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags) {
const unsigned char* s=*(const unsigned char**) string; const unsigned char *s = *(const unsigned char **)string;
unsigned char *d = (unsigned char*)deststring; unsigned char *d = (unsigned char *)deststring;
unsigned char b, c; unsigned char b, c;
/* This is the main decoding loop. /* This is the main decoding loop.
'flag' determines, which characters are non-terminating in current context '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 ) (ie. stop at '=' and '&' if scanning for a 'param'; stop at '?' if scanning for the path )
*/ */
while( is_unreserved[ c = *s++ ] & flags ) { while (is_unreserved[c = *s++] & flags) {
/* When encountering an url escaped character, try to decode */ /* When encountering an url escaped character, try to decode */
if( c=='%') { if (c == '%') {
if( ( b = fromhex(*s++) ) == 0xff ) return -1; if ((b = fromhex(*s++)) == 0xff)
if( ( c = fromhex(*s++) ) == 0xff ) return -1; return -1;
c|=(b<<4); if ((c = fromhex(*s++)) == 0xff)
return -1;
c |= (b << 4);
} }
/* Write (possibly decoded) character to output */ /* Write (possibly decoded) character to output */
*d++ = c; *d++ = c;
} }
switch( c ) { switch (c) {
case 0: case '\r': case '\n': case ' ': case 0:
case '\r':
case '\n':
case ' ':
/* If we started scanning on a hard terminator, indicate we've finished */ /* If we started scanning on a hard terminator, indicate we've finished */
if( d == (unsigned char*)deststring ) return -2; if (d == (unsigned char *)deststring)
return -2;
/* Else make the next call to scan_urlencoded_param encounter it again */ /* Else make the next call to scan_urlencoded_param encounter it again */
--s; --s;
break; break;
case '?': case '?':
if( flags != SCAN_PATH ) return -1; if (flags != SCAN_PATH)
return -1;
break; break;
case '=': case '=':
if( flags != SCAN_SEARCHPATH_PARAM ) return -1; if (flags != SCAN_SEARCHPATH_PARAM)
return -1;
break; break;
case '&': case '&':
if( flags == SCAN_PATH ) return -1; if (flags == SCAN_PATH)
if( flags == SCAN_SEARCHPATH_PARAM ) --s; return -1;
if (flags == SCAN_SEARCHPATH_PARAM)
--s;
break; break;
default: default:
return -1; return -1;
} }
*string = (char *)s; *string = (char *)s;
return d - (unsigned char*)deststring; return d - (unsigned char *)deststring;
} }
ssize_t scan_fixed_int( char *data, size_t len, int *tmp ) { ssize_t scan_fixed_int(char *data, size_t len, int *tmp) {
int minus = 0; int minus = 0;
*tmp = 0; *tmp = 0;
if( *data == '-' ) --len, ++data, ++minus; if (*data == '-')
while( (len > 0) && (*data >= '0') && (*data <= '9') ) { --len; *tmp = 10**tmp + *data++-'0'; } --len, ++data, ++minus;
if( minus ) *tmp = -*tmp; while ((len > 0) && (*data >= '0') && (*data <= '9')) {
--len;
*tmp = 10 * *tmp + *data++ - '0';
}
if (minus)
*tmp = -*tmp;
return len; return len;
} }

6
scan_urlencoded_query.h

@ -38,18 +38,18 @@ ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_F
or -2 for terminator found or -2 for terminator found
or -3 for no keyword matched or -3 for no keyword matched
*/ */
int scan_find_keywords( const ot_keywords * keywords, char **string, SCAN_SEARCHPATH_FLAG flags); int scan_find_keywords(const ot_keywords *keywords, char **string, SCAN_SEARCHPATH_FLAG flags);
/* string in: pointer to value of a param=value pair to skip /* string in: pointer to value of a param=value pair to skip
out: pointer to next scan position on return out: pointer to next scan position on return
*/ */
void scan_urlencoded_skipvalue( char **string ); void scan_urlencoded_skipvalue(char **string);
/* 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
*/ */
ssize_t scan_fixed_int( char *data, size_t len, int *number ); ssize_t scan_fixed_int(char *data, size_t len, int *number);
#endif #endif

476
trackerlogic.c

@ -4,119 +4,117 @@
$id$ */ $id$ */
/* System */ /* System */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <unistd.h>
#include <errno.h> #include <errno.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* Libowfat */ /* Libowfat */
#include "array.h"
#include "byte.h" #include "byte.h"
#include "io.h" #include "io.h"
#include "iob.h" #include "iob.h"
#include "ip6.h" #include "ip6.h"
#include "array.h"
/* Opentracker */ /* Opentracker */
#include "trackerlogic.h"
#include "ot_vector.h"
#include "ot_mutex.h"
#include "ot_stats.h"
#include "ot_clean.h"
#include "ot_http.h"
#include "ot_accesslist.h" #include "ot_accesslist.h"
#include "ot_clean.h"
#include "ot_fullscrape.h" #include "ot_fullscrape.h"
#include "ot_http.h"
#include "ot_livesync.h" #include "ot_livesync.h"
#include "ot_mutex.h"
#include "ot_stats.h"
#include "ot_vector.h"
#include "trackerlogic.h"
/* Forward declaration */ /* Forward declaration */
size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ); size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto);
void free_peerlist( ot_peerlist *peer_list ) { void free_peerlist(ot_peerlist *peer_list) {
if( peer_list->peers.data ) { if (peer_list->peers.data) {
if( OT_PEERLIST_HASBUCKETS( peer_list ) ) if (OT_PEERLIST_HASBUCKETS(peer_list))
vector_clean_list( (ot_vector*)peer_list->peers.data, peer_list->peers.size ); vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size);
else else
free( peer_list->peers.data ); free(peer_list->peers.data);
} }
free( peer_list ); free(peer_list);
} }
void add_torrent_from_saved_state( ot_hash const hash, ot_time base, size_t down_count ) { void add_torrent_from_saved_state(ot_hash const hash, ot_time base, size_t down_count) {
int exactmatch; int exactmatch;
ot_torrent *torrent; ot_torrent *torrent;
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); ot_vector *torrents_list = mutex_bucket_lock_by_hash(hash);
if( !accesslist_hashisvalid( hash ) ) if (!accesslist_hashisvalid(hash))
return mutex_bucket_unlock_by_hash( hash, 0 ); return mutex_bucket_unlock_by_hash(hash, 0);
torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); torrent = vector_find_or_insert(torrents_list, (void *)hash, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
if( !torrent || exactmatch ) if (!torrent || exactmatch)
return mutex_bucket_unlock_by_hash( hash, 0 ); return mutex_bucket_unlock_by_hash(hash, 0);
/* Create a new torrent entry, then */ /* Create a new torrent entry, then */
byte_zero( torrent, sizeof( ot_torrent ) ); byte_zero(torrent, sizeof(ot_torrent));
memcpy( torrent->hash, hash, sizeof(ot_hash) ); memcpy(torrent->hash, hash, sizeof(ot_hash));
if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) || if (!(torrent->peer_list6 = malloc(sizeof(ot_peerlist))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) {
!( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) { vector_remove_torrent(torrents_list, torrent);
vector_remove_torrent( torrents_list, torrent ); return mutex_bucket_unlock_by_hash(hash, 0);
return mutex_bucket_unlock_by_hash( hash, 0 );
} }
byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) ); byte_zero(torrent->peer_list6, sizeof(ot_peerlist));
byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) ); byte_zero(torrent->peer_list4, sizeof(ot_peerlist));
torrent->peer_list6->base = base; torrent->peer_list6->base = base;
torrent->peer_list4->base = base; torrent->peer_list4->base = base;
torrent->peer_list6->down_count = down_count; torrent->peer_list6->down_count = down_count;
torrent->peer_list4->down_count = down_count; torrent->peer_list4->down_count = down_count;
return mutex_bucket_unlock_by_hash( hash, 1 ); return mutex_bucket_unlock_by_hash(hash, 1);
} }
size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ) { size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount) {
int exactmatch, delta_torrentcount = 0; int exactmatch, delta_torrentcount = 0;
ot_torrent *torrent; ot_torrent *torrent;
ot_peer *peer_dest; ot_peer *peer_dest;
ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash);
ot_peerlist *peer_list; ot_peerlist *peer_list;
size_t peer_size; /* initialized in next line */ size_t peer_size; /* initialized in next line */
ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size); ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size);
if( !accesslist_hashisvalid( *ws->hash ) ) { if (!accesslist_hashisvalid(*ws->hash)) {
mutex_bucket_unlock_by_hash( *ws->hash, 0 ); mutex_bucket_unlock_by_hash(*ws->hash, 0);
if( proto == FLAG_TCP ) { if (proto == FLAG_TCP) {
const char invalid_hash[] = "d14:failure reason63:Requested download is not authorized for use with this tracker.e"; const char invalid_hash[] = "d14:failure reason63:Requested download is not authorized for use with this tracker.e";
memcpy( ws->reply, invalid_hash, strlen( invalid_hash ) ); memcpy(ws->reply, invalid_hash, strlen(invalid_hash));
return strlen( invalid_hash ); return strlen(invalid_hash);
} }
return 0; return 0;
} }
torrent = vector_find_or_insert( torrents_list, (void*)ws->hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); torrent = vector_find_or_insert(torrents_list, (void *)ws->hash, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
if( !torrent ) { if (!torrent) {
mutex_bucket_unlock_by_hash( *ws->hash, 0 ); mutex_bucket_unlock_by_hash(*ws->hash, 0);
return 0; return 0;
} }
if( !exactmatch ) { if (!exactmatch) {
/* Create a new torrent entry, then */ /* Create a new torrent entry, then */
byte_zero( torrent, sizeof(ot_torrent)); byte_zero(torrent, sizeof(ot_torrent));
memcpy( torrent->hash, *ws->hash, sizeof(ot_hash) ); memcpy(torrent->hash, *ws->hash, sizeof(ot_hash));
if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) || if (!(torrent->peer_list6 = malloc(sizeof(ot_peerlist))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) {
!( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) { vector_remove_torrent(torrents_list, torrent);
vector_remove_torrent( torrents_list, torrent ); mutex_bucket_unlock_by_hash(*ws->hash, 0);
mutex_bucket_unlock_by_hash( *ws->hash, 0 );
return 0; return 0;
} }
byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) ); byte_zero(torrent->peer_list6, sizeof(ot_peerlist));
byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) ); byte_zero(torrent->peer_list4, sizeof(ot_peerlist));
delta_torrentcount = 1; delta_torrentcount = 1;
} else } else
clean_single_torrent( torrent ); clean_single_torrent(torrent);
torrent->peer_list6->base = g_now_minutes; torrent->peer_list6->base = g_now_minutes;
torrent->peer_list4->base = g_now_minutes; torrent->peer_list4->base = g_now_minutes;
@ -124,99 +122,99 @@ size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstr
peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
/* Check for peer in torrent */ /* Check for peer in torrent */
peer_dest = vector_find_or_insert_peer( &(peer_list->peers), peer_src, peer_size, &exactmatch ); peer_dest = vector_find_or_insert_peer(&(peer_list->peers), peer_src, peer_size, &exactmatch);
if( !peer_dest ) { if (!peer_dest) {
mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
return 0; return 0;
} }
/* Tell peer that it's fresh */ /* Tell peer that it's fresh */
OT_PEERTIME( ws->peer, OT_PEER_SIZE6 ) = 0; OT_PEERTIME(ws->peer, OT_PEER_SIZE6) = 0;
/* Sanitize flags: Whoever claims to have completed download, must be a seeder */ /* Sanitize flags: Whoever claims to have completed download, must be a seeder */
if( ( OT_PEERFLAG( ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) if ((OT_PEERFLAG(ws->peer) & (PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING)) == PEER_FLAG_COMPLETED)
OT_PEERFLAG( ws->peer ) ^= PEER_FLAG_COMPLETED; OT_PEERFLAG(ws->peer) ^= PEER_FLAG_COMPLETED;
/* If we hadn't had a match create peer there */ /* If we hadn't had a match create peer there */
if( !exactmatch ) { if (!exactmatch) {
#ifdef WANT_SYNC_LIVE #ifdef WANT_SYNC_LIVE
if( proto == FLAG_MCA ) if (proto == FLAG_MCA)
OT_PEERFLAG( ws->peer ) |= PEER_FLAG_FROM_SYNC; OT_PEERFLAG(ws->peer) |= PEER_FLAG_FROM_SYNC;
else else
livesync_tell( ws ); livesync_tell(ws);
#endif #endif
peer_list->peer_count++; peer_list->peer_count++;
if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_COMPLETED ) { if (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED) {
peer_list->down_count++; peer_list->down_count++;
stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws ); stats_issue_event(EVENT_COMPLETED, 0, (uintptr_t)ws);
} }
if( OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) if (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING)
peer_list->seed_count++; peer_list->seed_count++;
} else { } else {
stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest, peer_size ) ); stats_issue_event(EVENT_RENEW, 0, OT_PEERTIME(peer_dest, peer_size));
#ifdef WANT_SPOT_WOODPECKER #ifdef WANT_SPOT_WOODPECKER
if( ( OT_PEERTIME(peer_dest, peer_size) > 0 ) && ( OT_PEERTIME(peer_dest, peer_size) < 20 ) ) if ((OT_PEERTIME(peer_dest, peer_size) > 0) && (OT_PEERTIME(peer_dest, peer_size) < 20))
stats_issue_event( EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer ); stats_issue_event(EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer);
#endif #endif
#ifdef WANT_SYNC_LIVE #ifdef WANT_SYNC_LIVE
/* Won't live sync peers that come back too fast. Only exception: /* Won't live sync peers that come back too fast. Only exception:
fresh "completed" reports */ fresh "completed" reports */
if( proto != FLAG_MCA ) { if (proto != FLAG_MCA) {
if( OT_PEERTIME( peer_dest, peer_size ) > OT_CLIENT_SYNC_RENEW_BOUNDARY || if (OT_PEERTIME(peer_dest, peer_size) > OT_CLIENT_SYNC_RENEW_BOUNDARY ||
( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) ) (!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED)))
livesync_tell( ws ); livesync_tell(ws);
} }
#endif #endif
if( (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) ) if ((OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING) && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING))
peer_list->seed_count--; peer_list->seed_count--;
if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) ) if (!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING))
peer_list->seed_count++; peer_list->seed_count++;
if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) { if (!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED)) {
peer_list->down_count++; peer_list->down_count++;
stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws ); stats_issue_event(EVENT_COMPLETED, 0, (uintptr_t)ws);
} }
if( OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) if (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED)
OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED; OT_PEERFLAG(ws->peer) |= PEER_FLAG_COMPLETED;
} }
memcpy( peer_dest, peer_src, peer_size ); memcpy(peer_dest, peer_src, peer_size);
#ifdef WANT_SYNC #ifdef WANT_SYNC
if( proto == FLAG_MCA ) { if (proto == FLAG_MCA) {
mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
return 0; return 0;
} }
#endif #endif
ws->reply_size = return_peers_for_torrent( ws, torrent, amount, ws->reply, proto ); ws->reply_size = return_peers_for_torrent(ws, torrent, amount, ws->reply, proto);
mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
return ws->reply_size; return ws->reply_size;
} }
static size_t return_peers_all( ot_peerlist *peer_list, size_t peer_size, char *reply ) { static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *reply) {
unsigned int bucket, num_buckets = 1; unsigned int bucket, num_buckets = 1;
ot_vector * bucket_list = &peer_list->peers; ot_vector *bucket_list = &peer_list->peers;
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
size_t result = compare_size * peer_list->peer_count; size_t result = compare_size * peer_list->peer_count;
char * r_end = reply + result; char *r_end = reply + result;
if( OT_PEERLIST_HASBUCKETS(peer_list) ) { if (OT_PEERLIST_HASBUCKETS(peer_list)) {
num_buckets = bucket_list->size; num_buckets = bucket_list->size;
bucket_list = (ot_vector *)bucket_list->data; bucket_list = (ot_vector *)bucket_list->data;
} }
for( bucket = 0; bucket<num_buckets; ++bucket ) { for (bucket = 0; bucket < num_buckets; ++bucket) {
ot_peer *peers = bucket_list[bucket].data; ot_peer *peers = bucket_list[bucket].data;
size_t peer_count = bucket_list[bucket].size; size_t peer_count = bucket_list[bucket].size;
while( peer_count-- ) { while (peer_count--) {
if( OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING ) { if (OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING) {
r_end -= compare_size; r_end -= compare_size;
memcpy( r_end, peers, compare_size); memcpy(r_end, peers, compare_size);
} else { } else {
memcpy( reply, peers, compare_size ); memcpy(reply, peers, compare_size);
reply += compare_size; reply += compare_size;
} }
peers += peer_size; peers += peer_size;
@ -225,45 +223,47 @@ static size_t return_peers_all( ot_peerlist *peer_list, size_t peer_size, char *
return result; return result;
} }
static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply ) { static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply) {
unsigned int bucket_offset, bucket_index = 0, num_buckets = 1; unsigned int bucket_offset, bucket_index = 0, num_buckets = 1;
ot_vector * bucket_list = &peer_list->peers; ot_vector *bucket_list = &peer_list->peers;
unsigned int shifted_pc = peer_list->peer_count; unsigned int shifted_pc = peer_list->peer_count;
unsigned int shifted_step = 0; unsigned int shifted_step = 0;
unsigned int shift = 0; unsigned int shift = 0;
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
size_t result = compare_size * amount; size_t result = compare_size * amount;
char * r_end = reply + result; char *r_end = reply + result;
if( OT_PEERLIST_HASBUCKETS(peer_list) ) { if (OT_PEERLIST_HASBUCKETS(peer_list)) {
num_buckets = bucket_list->size; num_buckets = bucket_list->size;
bucket_list = (ot_vector *)bucket_list->data; bucket_list = (ot_vector *)bucket_list->data;
} }
/* Make fixpoint arithmetic as exact as possible */ /* Make fixpoint arithmetic as exact as possible */
#define MAXPRECBIT (1<<(8*sizeof(int)-3)) #define MAXPRECBIT (1 << (8 * sizeof(int) - 3))
while( !(shifted_pc & MAXPRECBIT ) ) { shifted_pc <<= 1; shift++; } while (!(shifted_pc & MAXPRECBIT)) {
shifted_step = shifted_pc/amount; shifted_pc <<= 1;
shift++;
}
shifted_step = shifted_pc / amount;
#undef MAXPRECBIT #undef MAXPRECBIT
/* Initialize somewhere in the middle of peers so that /* Initialize somewhere in the middle of peers so that
fixpoint's aliasing doesn't alway miss the same peers */ fixpoint's aliasing doesn't alway miss the same peers */
bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count; bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count;
while( amount-- ) { while (amount--) {
ot_peer *peer; ot_peer *peer;
/* This is the aliased, non shifted range, next value may fall into */ /* This is the aliased, non shifted range, next value may fall into */
unsigned int diff = ( ( ( amount + 1 ) * shifted_step ) >> shift ) - unsigned int diff = (((amount + 1) * shifted_step) >> shift) - ((amount * shifted_step) >> shift);
( ( amount * shifted_step ) >> shift );
bucket_offset += 1 + nrand48(ws->rand48_state) % diff; bucket_offset += 1 + nrand48(ws->rand48_state) % diff;
while( bucket_offset >= bucket_list[bucket_index].size ) { while (bucket_offset >= bucket_list[bucket_index].size) {
bucket_offset -= bucket_list[bucket_index].size; bucket_offset -= bucket_list[bucket_index].size;
bucket_index = ( bucket_index + 1 ) % num_buckets; bucket_index = (bucket_index + 1) % num_buckets;
} }
peer = bucket_list[bucket_index].data + peer_size * bucket_offset; peer = bucket_list[bucket_index].data + peer_size * bucket_offset;
if( OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING ) { if (OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING) {
r_end -= compare_size; r_end -= compare_size;
memcpy(r_end, peer, compare_size); memcpy(r_end, peer, compare_size);
} else { } else {
@ -274,31 +274,31 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee
return result; return result;
} }
static size_t return_peers_for_torrent_udp( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply ) { static size_t return_peers_for_torrent_udp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) {
char *r = reply; char *r = reply;
size_t peer_size = peer_size_from_peer6(&ws->peer); size_t peer_size = peer_size_from_peer6(&ws->peer);
ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
if( amount > peer_list->peer_count ) if (amount > peer_list->peer_count)
amount = peer_list->peer_count; amount = peer_list->peer_count;
*(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); *(uint32_t *)(r + 0) = htonl(OT_CLIENT_REQUEST_INTERVAL_RANDOM);
*(uint32_t*)(r+4) = htonl( peer_count - seed_count ); *(uint32_t *)(r + 4) = htonl(peer_count - seed_count);
*(uint32_t*)(r+8) = htonl( seed_count ); *(uint32_t *)(r + 8) = htonl(seed_count);
r += 12; r += 12;
if( amount ) { if (amount) {
if( amount == peer_list->peer_count ) if (amount == peer_list->peer_count)
r += return_peers_all( peer_list, peer_size, r ); r += return_peers_all(peer_list, peer_size, r);
else else
r += return_peers_selection( ws, peer_list, peer_size, amount, r ); r += return_peers_selection(ws, peer_list, peer_size, amount, r);
} }
return r - reply; return r - reply;
} }
static size_t return_peers_for_torrent_tcp( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply ) { static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) {
char *r = reply; char *r = reply;
int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
@ -310,14 +310,14 @@ static size_t return_peers_for_torrent_tcp( struct ot_workstruct * ws, ot_torren
size_t amount_v6 = torrent->peer_list6->peer_count; size_t amount_v6 = torrent->peer_list6->peer_count;
/* Complex case: both lists have more than enough entries and we need to split between v4 and v6 clients */ /* Complex case: both lists have more than enough entries and we need to split between v4 and v6 clients */
if( amount_v4 + amount_v6 > amount ) { if (amount_v4 + amount_v6 > amount) {
size_t amount_left, percent_v6 = 0, percent_v4 = 0, left_v6, left_v4; size_t amount_left, percent_v6 = 0, percent_v4 = 0, left_v6, left_v4;
const size_t SCALE = 1024; const size_t SCALE = 1024;
/* If possible, fill at least a quarter of peer from each family */ /* If possible, fill at least a quarter of peer from each family */
if( amount / 4 <= amount_v4 ) if (amount / 4 <= amount_v4)
amount_v4 = amount / 4; amount_v4 = amount / 4;
if( amount / 4 <= amount_v6 ) if (amount / 4 <= amount_v6)
amount_v6 = amount / 4; amount_v6 = amount / 4;
/* Fill the rest according to which family's pool provides more peers */ /* Fill the rest according to which family's pool provides more peers */
@ -326,7 +326,7 @@ static size_t return_peers_for_torrent_tcp( struct ot_workstruct * ws, ot_torren
left_v4 = torrent->peer_list4->peer_count - amount_v4; left_v4 = torrent->peer_list4->peer_count - amount_v4;
left_v6 = torrent->peer_list6->peer_count - amount_v6; left_v6 = torrent->peer_list6->peer_count - amount_v6;
if( left_v4 + left_v6 ) { if (left_v4 + left_v6) {
percent_v4 = (SCALE * left_v4) / (left_v4 + left_v6); percent_v4 = (SCALE * left_v4) / (left_v4 + left_v6);
percent_v6 = (SCALE * left_v6) / (left_v4 + left_v6); percent_v6 = (SCALE * left_v6) / (left_v4 + left_v6);
} }
@ -335,28 +335,29 @@ static size_t return_peers_for_torrent_tcp( struct ot_workstruct * ws, ot_torren
amount_v6 += (amount_left * percent_v6) / SCALE; amount_v6 += (amount_left * percent_v6) / SCALE;
/* Integer division rounding can leave out a peer */ /* Integer division rounding can leave out a peer */
if( amount_v4 + amount_v6 < amount && amount_v6 < torrent->peer_list6->peer_count ) if (amount_v4 + amount_v6 < amount && amount_v6 < torrent->peer_list6->peer_count)
++amount_v6; ++amount_v6;
if( amount_v4 + amount_v6 < amount && amount_v4 < torrent->peer_list4->peer_count ) if (amount_v4 + amount_v6 < amount && amount_v4 < torrent->peer_list4->peer_count)
++amount_v4; ++amount_v4;
} }
r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie", seed_count, down_count, peer_count, erval, erval/2 ); r +=
sprintf(r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie", seed_count, down_count, peer_count, erval, erval / 2);
if( amount_v4 ) { if (amount_v4) {
r += sprintf( r, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4); r += sprintf(r, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4);
if( amount_v4 == torrent->peer_list4->peer_count ) if (amount_v4 == torrent->peer_list4->peer_count)
r += return_peers_all( torrent->peer_list4, OT_PEER_SIZE4, r ); r += return_peers_all(torrent->peer_list4, OT_PEER_SIZE4, r);
else else
r += return_peers_selection( ws, torrent->peer_list4, OT_PEER_SIZE4, amount_v4, r ); r += return_peers_selection(ws, torrent->peer_list4, OT_PEER_SIZE4, amount_v4, r);
} }
if( amount_v6 ) { if (amount_v6) {
r += sprintf( r, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6); r += sprintf(r, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6);
if( amount_v6 == torrent->peer_list6->peer_count ) if (amount_v6 == torrent->peer_list6->peer_count)
r += return_peers_all( torrent->peer_list6, OT_PEER_SIZE6, r ); r += return_peers_all(torrent->peer_list6, OT_PEER_SIZE6, r);
else else
r += return_peers_selection( ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r ); r += return_peers_selection(ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r);
} }
*r++ = 'e'; *r++ = 'e';
@ -371,148 +372,153 @@ static size_t return_peers_for_torrent_tcp( struct ot_workstruct * ws, ot_torren
* 12 + 6 * amount bytes for UDP/IPv4 * 12 + 6 * amount bytes for UDP/IPv4
* 12 + 18 * amount bytes for UDP/IPv6 * 12 + 18 * amount bytes for UDP/IPv6
* Does not yet check not to return self * Does not yet check not to return self
*/ */
size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) { size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto) {
return proto == FLAG_TCP ? return_peers_for_torrent_tcp(ws, torrent, amount, reply) : return_peers_for_torrent_udp(ws, torrent, amount, reply); return proto == FLAG_TCP ? return_peers_for_torrent_tcp(ws, torrent, amount, reply) : return_peers_for_torrent_udp(ws, torrent, amount, reply);
} }
/* Fetches scrape info for a specific torrent */ /* Fetches scrape info for a specific torrent */
size_t return_udp_scrape_for_torrent( ot_hash const hash, char *reply ) { size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply) {
int exactmatch, delta_torrentcount = 0; int exactmatch, delta_torrentcount = 0;
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); 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_torrent *torrent = binary_search(hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
if( !exactmatch ) { if (!exactmatch) {
memset( reply, 0, 12); memset(reply, 0, 12);
} else { } else {
uint32_t *r = (uint32_t*) reply; uint32_t *r = (uint32_t *)reply;
if( clean_single_torrent( torrent ) ) { if (clean_single_torrent(torrent)) {
vector_remove_torrent( torrents_list, torrent ); vector_remove_torrent(torrents_list, torrent);
memset( reply, 0, 12); memset(reply, 0, 12);
delta_torrentcount = -1; delta_torrentcount = -1;
} else { } else {
r[0] = htonl( torrent->peer_list6->seed_count + torrent->peer_list4->seed_count ); r[0] = htonl(torrent->peer_list6->seed_count + torrent->peer_list4->seed_count);
r[1] = htonl( torrent->peer_list6->down_count + torrent->peer_list4->down_count ); r[1] = htonl(torrent->peer_list6->down_count + torrent->peer_list4->down_count);
r[2] = htonl( torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - r[2] = htonl(torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
} }
} }
mutex_bucket_unlock_by_hash( hash, delta_torrentcount ); mutex_bucket_unlock_by_hash(hash, delta_torrentcount);
return 12; return 12;
} }
/* Fetches scrape info for a specific torrent */ /* Fetches scrape info for a specific torrent */
size_t return_tcp_scrape_for_torrent( ot_hash const *hash_list, int amount, char *reply ) { size_t return_tcp_scrape_for_torrent(ot_hash const *hash_list, int amount, char *reply) {
char *r = reply; char *r = reply;
int exactmatch, i; int exactmatch, i;
r += sprintf( r, "d5:filesd" ); r += sprintf(r, "d5:filesd");
for( i=0; i<amount; ++i ) { for (i = 0; i < amount; ++i) {
int delta_torrentcount = 0; int delta_torrentcount = 0;
ot_hash const *hash = hash_list + i; ot_hash const *hash = hash_list + i;
ot_vector *torrents_list = mutex_bucket_lock_by_hash( *hash ); 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_torrent *torrent = binary_search(hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
if( exactmatch ) { if (exactmatch) {
if( clean_single_torrent( torrent ) ) { if (clean_single_torrent(torrent)) {
vector_remove_torrent( torrents_list, torrent ); vector_remove_torrent(torrents_list, torrent);
delta_torrentcount = -1; delta_torrentcount = -1;
} else { } else {
*r++='2';*r++='0';*r++=':'; *r++ = '2';
memcpy( r, hash, sizeof(ot_hash) ); r+=sizeof(ot_hash); *r++ = '0';
r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", *r++ = ':';
torrent->peer_list6->seed_count + torrent->peer_list4->seed_count, memcpy(r, hash, sizeof(ot_hash));
r += sizeof(ot_hash);
r += sprintf(r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", torrent->peer_list6->seed_count + torrent->peer_list4->seed_count,
torrent->peer_list6->down_count + torrent->peer_list4->down_count, torrent->peer_list6->down_count + torrent->peer_list4->down_count,
torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
} }
} }
mutex_bucket_unlock_by_hash( *hash, delta_torrentcount ); mutex_bucket_unlock_by_hash(*hash, delta_torrentcount);
} }
*r++ = 'e'; *r++ = 'e'; *r++ = 'e';
*r++ = 'e';
return r - reply; return r - reply;
} }
static ot_peerlist dummy_list; static ot_peerlist dummy_list;
size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) { size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) {
int exactmatch; int exactmatch;
ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash);
ot_torrent *torrent = binary_search( ws->hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); ot_torrent *torrent = binary_search(ws->hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
ot_peerlist *peer_list = &dummy_list; ot_peerlist *peer_list = &dummy_list;
size_t peer_size; /* initialized in next line */ size_t peer_size; /* initialized in next line */
ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size); ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size);
size_t peer_count = 0, seed_count = 0; size_t peer_count = 0, seed_count = 0;
#ifdef WANT_SYNC_LIVE #ifdef WANT_SYNC_LIVE
if( proto != FLAG_MCA ) { if (proto != FLAG_MCA) {
OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED; OT_PEERFLAG(ws->peer) |= PEER_FLAG_STOPPED;
livesync_tell( ws ); livesync_tell(ws);
} }
#endif #endif
if( exactmatch ) { if (exactmatch) {
peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
switch( vector_remove_peer( &peer_list->peers, peer_src, peer_size ) ) { switch (vector_remove_peer(&peer_list->peers, peer_src, peer_size)) {
case 2: peer_list->seed_count--; /* Intentional fallthrough */ case 2:
case 1: peer_list->peer_count--; /* Intentional fallthrough */ peer_list->seed_count--; /* Intentional fallthrough */
default: break; case 1:
peer_list->peer_count--; /* Intentional fallthrough */
default:
break;
} }
peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
} }
if (proto == FLAG_TCP) {
if( proto == FLAG_TCP ) {
int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
ws->reply_size = sprintf( ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s0:e", seed_count, peer_count - seed_count, erval, erval / 2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4 ); ws->reply_size = sprintf(ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s0:e", seed_count, peer_count - seed_count, erval,
erval / 2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4);
} }
/* Handle UDP reply */ /* Handle UDP reply */
if( proto == FLAG_UDP ) { if (proto == FLAG_UDP) {
((uint32_t*)ws->reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); ((uint32_t *)ws->reply)[2] = htonl(OT_CLIENT_REQUEST_INTERVAL_RANDOM);
((uint32_t*)ws->reply)[3] = htonl( peer_count - seed_count ); ((uint32_t *)ws->reply)[3] = htonl(peer_count - seed_count);
((uint32_t*)ws->reply)[4] = htonl( seed_count); ((uint32_t *)ws->reply)[4] = htonl(seed_count);
ws->reply_size = 20; ws->reply_size = 20;
} }
mutex_bucket_unlock_by_hash( *ws->hash, 0 ); mutex_bucket_unlock_by_hash(*ws->hash, 0);
return ws->reply_size; return ws->reply_size;
} }
void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data ), uintptr_t data ) { void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), uintptr_t data) {
int bucket; int bucket;
size_t j; size_t j;
for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
ot_vector *torrents_list = mutex_bucket_lock( bucket ); ot_vector *torrents_list = mutex_bucket_lock(bucket);
ot_torrent *torrents = (ot_torrent*)(torrents_list->data); ot_torrent *torrents = (ot_torrent *)(torrents_list->data);
for( j=0; j<torrents_list->size; ++j ) for (j = 0; j < torrents_list->size; ++j)
if( for_each( torrents + j, data ) ) if (for_each(torrents + j, data))
break; break;
mutex_bucket_unlock( bucket, 0 ); mutex_bucket_unlock(bucket, 0);
if( !g_opentracker_running ) return; if (!g_opentracker_running)
return;
} }
} }
ot_peer *peer_from_peer6( ot_peer6 *peer, size_t *peer_size ) { ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size) {
ot_ip6 *ip = (ot_ip6*)peer; ot_ip6 *ip = (ot_ip6 *)peer;
if( !ip6_isv4mapped(ip) ) { if (!ip6_isv4mapped(ip)) {
*peer_size = OT_PEER_SIZE6; *peer_size = OT_PEER_SIZE6;
return (ot_peer*)peer; return (ot_peer *)peer;
} }
*peer_size = OT_PEER_SIZE4; *peer_size = OT_PEER_SIZE4;
return (ot_peer*)(((uint8_t*)peer) + 12); return (ot_peer *)(((uint8_t *)peer) + 12);
} }
size_t peer_size_from_peer6(ot_peer6 *peer) { size_t peer_size_from_peer6(ot_peer6 *peer) {
ot_ip6 *ip = (ot_ip6*)peer; ot_ip6 *ip = (ot_ip6 *)peer;
if( !ip6_isv4mapped(ip)) if (!ip6_isv4mapped(ip))
return OT_PEER_SIZE6; return OT_PEER_SIZE6;
return OT_PEER_SIZE4; return OT_PEER_SIZE4;
} }
@ -520,20 +526,20 @@ size_t peer_size_from_peer6(ot_peer6 *peer) {
#ifdef _DEBUG_RANDOMTORRENTS #ifdef _DEBUG_RANDOMTORRENTS
void trackerlogic_add_random_torrents(size_t amount) { void trackerlogic_add_random_torrents(size_t amount) {
struct ot_workstruct ws; struct ot_workstruct ws;
memset( &ws, 0, sizeof(ws) ); memset(&ws, 0, sizeof(ws));
ws.inbuf=malloc(G_INBUF_SIZE); ws.inbuf = malloc(G_INBUF_SIZE);
ws.outbuf=malloc(G_OUTBUF_SIZE); ws.outbuf = malloc(G_OUTBUF_SIZE);
ws.reply=ws.outbuf; ws.reply = ws.outbuf;
ws.hash=(ot_hash*)ws.inbuf; ws.hash = (ot_hash *)ws.inbuf;
while( amount-- ) { while (amount--) {
arc4random_buf(ws.hash, sizeof(ot_hash)); arc4random_buf(ws.hash, sizeof(ot_hash));
arc4random_buf(&ws.peer, sizeof(ws.peer)); arc4random_buf(&ws.peer, sizeof(ws.peer));
OT_PEERFLAG(ws.peer) &= PEER_FLAG_SEEDING | PEER_FLAG_COMPLETED | PEER_FLAG_STOPPED; OT_PEERFLAG(ws.peer) &= PEER_FLAG_SEEDING | PEER_FLAG_COMPLETED | PEER_FLAG_STOPPED;
add_peer_to_torrent_and_return_peers( FLAG_TCP, &ws, 1 ); add_peer_to_torrent_and_return_peers(FLAG_TCP, &ws, 1);
} }
free(ws.inbuf); free(ws.inbuf);
@ -541,54 +547,54 @@ void trackerlogic_add_random_torrents(size_t amount) {
} }
#endif #endif
void exerr( char * message ) { void exerr(char *message) {
fprintf( stderr, "%s\n", message ); fprintf(stderr, "%s\n", message);
exit( 111 ); exit(111);
} }
void trackerlogic_init( ) { void trackerlogic_init() {
g_tracker_id = random(); g_tracker_id = random();
if( !g_stats_path ) if (!g_stats_path)
g_stats_path = "stats"; g_stats_path = "stats";
g_stats_path_len = strlen( g_stats_path ); g_stats_path_len = strlen(g_stats_path);
/* Initialise background worker threads */ /* Initialise background worker threads */
mutex_init( ); mutex_init();
clean_init( ); clean_init();
fullscrape_init( ); fullscrape_init();
accesslist_init( ); accesslist_init();
livesync_init( ); livesync_init();
stats_init( ); stats_init();
} }
void trackerlogic_deinit( void ) { void trackerlogic_deinit(void) {
int bucket, delta_torrentcount = 0; int bucket, delta_torrentcount = 0;
size_t j; size_t j;
/* Free all torrents... */ /* Free all torrents... */
for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
ot_vector *torrents_list = mutex_bucket_lock( bucket ); ot_vector *torrents_list = mutex_bucket_lock(bucket);
if( torrents_list->size ) { if (torrents_list->size) {
for( j=0; j<torrents_list->size; ++j ) { for (j = 0; j < torrents_list->size; ++j) {
ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j; ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + j;
free_peerlist( torrent->peer_list6 ); free_peerlist(torrent->peer_list6);
free_peerlist( torrent->peer_list4 ); free_peerlist(torrent->peer_list4);
delta_torrentcount -= 1; delta_torrentcount -= 1;
} }
free( torrents_list->data ); free(torrents_list->data);
} }
mutex_bucket_unlock( bucket, delta_torrentcount ); mutex_bucket_unlock(bucket, delta_torrentcount);
} }
/* Deinitialise background worker threads */ /* Deinitialise background worker threads */
stats_deinit( ); stats_deinit();
livesync_deinit( ); livesync_deinit();
accesslist_deinit( ); accesslist_deinit();
fullscrape_deinit( ); fullscrape_deinit();
clean_deinit( ); clean_deinit();
/* Release mutexes */ /* Release mutexes */
mutex_deinit( ); mutex_deinit();
} }
const char *g_version_trackerlogic_c = "$Source$: $Revision$\n"; const char *g_version_trackerlogic_c = "$Source$: $Revision$\n";

81
trackerlogic.h

@ -6,11 +6,11 @@
#ifndef OT_TRACKERLOGIC_H__ #ifndef OT_TRACKERLOGIC_H__
#define OT_TRACKERLOGIC_H__ #define OT_TRACKERLOGIC_H__
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#if defined(__linux__) && defined(WANT_ARC4RANDOM) #if defined(__linux__) && defined(WANT_ARC4RANDOM)
#include <bsd/stdlib.h> #include <bsd/stdlib.h>
@ -22,8 +22,10 @@
typedef uint8_t ot_hash[20]; typedef uint8_t ot_hash[20];
typedef time_t ot_time; typedef time_t ot_time;
typedef char ot_ip6[16]; typedef char ot_ip6[16];
typedef struct { ot_ip6 address; int bits; } typedef struct {
ot_net; ot_ip6 address;
int bits;
} ot_net;
/* List of peers should fit in a single UDP packet (around 1200 bytes) */ /* List of peers should fit in a single UDP packet (around 1200 bytes) */
#define OT_MAX_PEERS_UDP6 66 #define OT_MAX_PEERS_UDP6 66
#define OT_MAX_PEERS_UDP4 200 #define OT_MAX_PEERS_UDP4 200
@ -37,18 +39,19 @@ typedef struct { ot_ip6 address; int bits; }
/* Some tracker behaviour tunable */ /* Some tracker behaviour tunable */
#define OT_CLIENT_TIMEOUT 30 #define OT_CLIENT_TIMEOUT 30
#define OT_CLIENT_TIMEOUT_CHECKINTERVAL 10 #define OT_CLIENT_TIMEOUT_CHECKINTERVAL 10
#define OT_CLIENT_TIMEOUT_SEND (60*15) #define OT_CLIENT_TIMEOUT_SEND (60 * 15)
#define OT_CLIENT_REQUEST_INTERVAL (60*30) #define OT_CLIENT_REQUEST_INTERVAL (60 * 30)
#define OT_CLIENT_REQUEST_VARIATION (60*6) #define OT_CLIENT_REQUEST_VARIATION (60 * 6)
#define OT_TORRENT_TIMEOUT_HOURS 24 #define OT_TORRENT_TIMEOUT_HOURS 24
#define OT_TORRENT_TIMEOUT (60*OT_TORRENT_TIMEOUT_HOURS) #define OT_TORRENT_TIMEOUT (60 * OT_TORRENT_TIMEOUT_HOURS)
#define OT_CLIENT_REQUEST_INTERVAL_RANDOM ( OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION/2 + (int)( nrand48(ws->rand48_state) % OT_CLIENT_REQUEST_VARIATION ) ) #define OT_CLIENT_REQUEST_INTERVAL_RANDOM \
(OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION / 2 + (int)(nrand48(ws->rand48_state) % OT_CLIENT_REQUEST_VARIATION))
/* If WANT_MODEST_FULLSCRAPES is on, ip addresses may not /* If WANT_MODEST_FULLSCRAPES is on, ip addresses may not
fullscrape more frequently than this amount in seconds */ fullscrape more frequently than this amount in seconds */
#define OT_MODEST_PEER_TIMEOUT (60*5) #define OT_MODEST_PEER_TIMEOUT (60 * 5)
/* If peers come back before 10 minutes, don't live sync them */ /* If peers come back before 10 minutes, don't live sync them */
#define OT_CLIENT_SYNC_RENEW_BOUNDARY 10 #define OT_CLIENT_SYNC_RENEW_BOUNDARY 10
@ -64,27 +67,27 @@ typedef struct { ot_ip6 address; int bits; }
Sort key is, of course, its hash */ Sort key is, of course, its hash */
#define OT_BUCKET_COUNT_BITS 10 #define OT_BUCKET_COUNT_BITS 10
#define OT_BUCKET_COUNT (1<<OT_BUCKET_COUNT_BITS) #define OT_BUCKET_COUNT (1 << OT_BUCKET_COUNT_BITS)
#define OT_BUCKET_COUNT_SHIFT (32-OT_BUCKET_COUNT_BITS) #define OT_BUCKET_COUNT_SHIFT (32 - OT_BUCKET_COUNT_BITS)
/* if _DEBUG_RANDOMTORRENTS is set, this is the amount of torrents to create /* if _DEBUG_RANDOMTORRENTS is set, this is the amount of torrents to create
on startup */ on startup */
#define RANDOMTORRENTS (1024*1024*1) #define RANDOMTORRENTS (1024 * 1024 * 1)
/* From opentracker.c */ /* From opentracker.c */
extern time_t g_now_seconds; extern time_t g_now_seconds;
extern volatile int g_opentracker_running; extern volatile int g_opentracker_running;
#define g_now_minutes (g_now_seconds/60) #define g_now_minutes (g_now_seconds / 60)
extern uint32_t g_tracker_id; extern uint32_t g_tracker_id;
typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG; typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG;
#define OT_PEER_COMPARE_SIZE6 ((OT_IP_SIZE6)+(OT_PORT_SIZE)) #define OT_PEER_COMPARE_SIZE6 ((OT_IP_SIZE6) + (OT_PORT_SIZE))
#define OT_PEER_COMPARE_SIZE4 ((OT_IP_SIZE4)+(OT_PORT_SIZE)) #define OT_PEER_COMPARE_SIZE4 ((OT_IP_SIZE4) + (OT_PORT_SIZE))
#define OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(PEER_SIZE) ((PEER_SIZE)-(OT_TIME_SIZE)-(OT_FLAG_SIZE)) #define OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(PEER_SIZE) ((PEER_SIZE) - (OT_TIME_SIZE) - (OT_FLAG_SIZE))
#define OT_PEER_SIZE6 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE6)) #define OT_PEER_SIZE6 ((OT_TIME_SIZE) + (OT_FLAG_SIZE) + (OT_PEER_COMPARE_SIZE6))
#define OT_PEER_SIZE4 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE4)) #define OT_PEER_SIZE4 ((OT_TIME_SIZE) + (OT_FLAG_SIZE) + (OT_PEER_COMPARE_SIZE4))
typedef uint8_t ot_peer; /* Generic pointer to a v6 or v4 peer */ typedef uint8_t ot_peer; /* Generic pointer to a v6 or v4 peer */
typedef uint8_t ot_peer6[OT_PEER_SIZE6]; typedef uint8_t ot_peer6[OT_PEER_SIZE6];
@ -100,11 +103,11 @@ ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size);
size_t peer_size_from_peer6(ot_peer6 *peer); size_t peer_size_from_peer6(ot_peer6 *peer);
/* New style */ /* New style */
#define OT_SETIP(peer,ip) memcpy((uint8_t*)(peer),(ip),OT_IP_SIZE6) #define OT_SETIP(peer, ip) memcpy((uint8_t *)(peer), (ip), OT_IP_SIZE6)
#define OT_SETPORT(peer,port) memcpy(((uint8_t*)(peer))+(OT_IP_SIZE6),(port),2) #define OT_SETPORT(peer, port) memcpy(((uint8_t *)(peer)) + (OT_IP_SIZE6), (port), 2)
#define OT_PEERFLAG(peer) (((uint8_t*)(peer))[(OT_IP_SIZE6)+2]) #define OT_PEERFLAG(peer) (((uint8_t *)(peer))[(OT_IP_SIZE6) + 2])
#define OT_PEERFLAG_D(peer,peersize) (((uint8_t*)(peer))[(peersize)-2]) #define OT_PEERFLAG_D(peer, peersize) (((uint8_t *)(peer))[(peersize) - 2])
#define OT_PEERTIME(peer,peersize) (((uint8_t*)(peer))[(peersize)-1]) #define OT_PEERTIME(peer, peersize) (((uint8_t *)(peer))[(peersize) - 1])
#define PEERS_BENCODED6 "6:peers6" #define PEERS_BENCODED6 "6:peers6"
#define PEERS_BENCODED4 "5:peers" #define PEERS_BENCODED4 "5:peers"
@ -126,9 +129,9 @@ struct ot_peerlist {
size_t seed_count; size_t seed_count;
size_t peer_count; size_t peer_count;
size_t down_count; size_t down_count;
/* normal peers vector or /* normal peers vector or
pointer to ot_vector[32] buckets if data != NULL and space == 0 pointer to ot_vector[32] buckets if data != NULL and space == 0
*/ */
ot_vector peers; ot_vector peers;
}; };
#define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list)->peers.size > (peer_list)->peers.space) #define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list)->peers.size > (peer_list)->peers.space)
@ -174,34 +177,34 @@ struct ot_workstruct {
#endif #endif
#ifdef WANT_SYNC #ifdef WANT_SYNC
#define WANT_SYNC_PARAM( param ) , param #define WANT_SYNC_PARAM(param) , param
#else #else
#define WANT_SYNC_PARAM( param ) #define WANT_SYNC_PARAM(param)
#endif #endif
#ifdef WANT_LOG_NETWORKS #ifdef WANT_LOG_NETWORKS
#error Live logging networks disabled at the moment. #error Live logging networks disabled at the moment.
#endif #endif
void trackerlogic_init( void ); void trackerlogic_init(void);
void trackerlogic_deinit( void ); void trackerlogic_deinit(void);
void exerr( char * message ); void exerr(char *message);
/* add_peer_to_torrent does only release the torrent bucket if from_sync is set, /* add_peer_to_torrent does only release the torrent bucket if from_sync is set,
otherwise it is released in return_peers_for_torrent */ otherwise it is released in return_peers_for_torrent */
size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ); size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount);
size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ); size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws);
size_t return_tcp_scrape_for_torrent( ot_hash const *hash_list, int amount, char *reply ); size_t return_tcp_scrape_for_torrent(ot_hash const *hash_list, int amount, char *reply);
size_t return_udp_scrape_for_torrent( ot_hash const hash, char *reply ); size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply);
void add_torrent_from_saved_state( ot_hash const hash, ot_time base, size_t down_count ); void add_torrent_from_saved_state(ot_hash const hash, ot_time base, size_t down_count);
#ifdef _DEBUG_RANDOMTORRENTS #ifdef _DEBUG_RANDOMTORRENTS
void trackerlogic_add_random_torrents(size_t amount); void trackerlogic_add_random_torrents(size_t amount);
#endif #endif
/* torrent iterator */ /* torrent iterator */
void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data ), uintptr_t data ); void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), uintptr_t data);
/* Helper, before it moves to its own object */ /* Helper, before it moves to its own object */
void free_peerlist( ot_peerlist *peer_list ); void free_peerlist(ot_peerlist *peer_list);
#endif #endif

Loading…
Cancel
Save