From 70a65f284257a4564cf80acb5b1e7a3b81efe149 Mon Sep 17 00:00:00 2001
From: erdgeist <>
Date: Sun, 4 Feb 2007 03:29:29 +0000
Subject: Add a lot of documentation for static functions in trackerlogic.c.
 Make vector_remove_peer use hysteresis only, if pool is expected to grow
 again. Remove too old torrents.

---
 trackerlogic.c | 78 ++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 52 insertions(+), 26 deletions(-)

diff --git a/trackerlogic.c b/trackerlogic.c
index acd89b6..d112abd 100644
--- a/trackerlogic.c
+++ b/trackerlogic.c
@@ -34,6 +34,11 @@ int g_check_blacklist = 1;
 static ot_torrent* const OT_TORRENT_ON_BLACKLIST = (ot_torrent*)2;
 #endif
 
+/* Converter function from memory to human readable hex strings
+   - definitely not thread safe!!!
+*/
+static char ths[2+2*20]="-";static char*to_hex(ot_byte*s){const char*m="0123456789ABCDEF";char*e=ths+41;char*t=ths+1;while(t<e){*t++=m[*s>>4];*t++=m[*s++&15];}*t=0;return ths+1;}
+
 /* This function gives us a binary search that returns a pointer, even if
    no exact match is found. In that case it sets exactmatch 0 and gives
    calling functions the chance to insert data
@@ -58,11 +63,13 @@ static void *binary_search( const void * const key, const void * base, const siz
   return (void*)lookat;
 }
 
-/* Converter function from memory to human readable hex strings
-   - definitely not thread safe!!!
+/* This is the generic insert operation for our vector type.
+   It tries to locate the object at "key" with size "member_size" by comparing its first "compare_size" bytes with
+   those of objects in vector. Our special "binary_search" function does that and either returns the match or a
+   pointer to where the object is to be inserted. vector_find_or_insert makes space for the object and copies it,
+   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.
 */
-char ths[2+2*20]="-";char*to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+41;char*t=ths+1;while(t<e){*t++=m[*s>>4];*t++=m[*s++&15];}*t=0;return ths+1;}
-
 static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) {
   ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch );
 
@@ -83,9 +90,16 @@ static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_
   vector->size++;
   return match;
 }
-	
-static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) {
-  int exactmatch;
+
+/* This is the non-generic delete from vector-operation specialized for peers in pools.
+   Set hysteresis == 0 if you expect the vector not to ever grow again.
+   It returns 0 if no peer was found (and thus not removed)
+              1 if a non-seeding peer was removed
+              2 if a seeding peer was removed
+*/
+static int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis ) {
+  int      exactmatch;
+  size_t   shrink_thresh = hysteresis ? OT_VECTOR_SHRINK_THRESH : OT_VECTOR_SHRINK_RATIO;
   ot_peer *end = ((ot_peer*)vector->data) + vector->size;
   ot_peer *match;
 
@@ -95,7 +109,7 @@ static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) {
   if( !exactmatch ) return 0;
   exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1;
   memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) );
-  if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) {
+  if( ( --vector->size * shrink_thresh < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) {
     vector->space /= OT_VECTOR_SHRINK_RATIO;
     vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) );
   }
@@ -117,14 +131,18 @@ static void free_peerlist( ot_peerlist *peer_list ) {
   free( peer_list );
 }
 
+/* This is the non-generic delete from vector-operation specialized for torrents in buckets.
+   it returns 0 if the hash wasn't found in vector
+              1 if the torrent was removed from vector
+*/
 static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
   int exactmatch;
   ot_torrent *end = ((ot_torrent*)vector->data) + vector->size;
   ot_torrent *match;
 
   if( !vector->size ) return 0;
-  match = binary_search( hash, vector->data, vector->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
 
+  match = binary_search( hash, vector->data, vector->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
   if( !exactmatch ) return 0;
 
   /* If this is being called after a unsuccessful malloc() for peer_list
@@ -139,8 +157,11 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
   return 1;
 }
 
-/* Returns 1, if torrent is gone, 0 otherwise
-   We expect NOW as a parameter since calling time() may be expensive*/
+/* This function deallocates all timedouted pools and shifts all other pools
+   it Returns 1 if torrent itself has not seen an announce for more than OT_TORRENT_TIMEOUT time units
+              0 if torrent is not yet timed out
+   Note: We expect NOW as a parameter since calling time() may be expensive
+*/
 static int clean_peerlist( time_t time_now, ot_peerlist *peer_list ) {
   int i, timedout = (int)( time_now - peer_list->base );
 
@@ -156,8 +177,11 @@ static int clean_peerlist( time_t time_now, ot_peerlist *peer_list ) {
   memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout) );
   byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout );
 
-  peer_list->base = NOW;
-  return timedout == OT_POOLS_COUNT;
+  if( timedout == OT_POOLS_COUNT )
+    return time_now - peer_list->base > OT_TORRENT_TIMEOUT;
+
+  peer_list->base = time_now;
+  return 0;
 }
 
 ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
@@ -187,13 +211,12 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
     /* Create a new torrent entry, then */
     memmove( &torrent->hash, hash, sizeof( ot_hash ) );
 
-    torrent->peer_list = malloc( sizeof (ot_peerlist) );
-    if( !torrent->peer_list ) {
+    if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
       vector_remove_torrent( torrents_list, hash );
       return NULL;
     }
 
-    byte_zero( torrent->peer_list, sizeof( ot_peerlist ));
+    byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
     torrent->peer_list->base = NOW;
   } else
     clean_peerlist( NOW, torrent->peer_list );
@@ -201,7 +224,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
   peer_pool = &torrent->peer_list->peers[0];
   peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch );
 
-  if( OT_FLAG(peer) & PEER_FLAG_COMPLETED )
+  if( OT_FLAG( peer ) & PEER_FLAG_COMPLETED )
     torrent->peer_list->downloaded++;
 
   /* If we hadn't had a match in current pool, create peer there and
@@ -213,7 +236,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
       torrent->peer_list->seed_count[0]++;
 
     for( i=1; i<OT_POOLS_COUNT; ++i ) {
-      switch( vector_remove_peer( &torrent->peer_list->peers[i], peer ) ) {
+      switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) {
         case 0: continue;
         case 2: torrent->peer_list->seed_count[i]--;
         case 1: default: return torrent;
@@ -231,7 +254,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
 }
 
 /* Compiles a list of random peers for a torrent
-   * reply must have enough space to hold 24+6*amount bytes
+   * reply must have enough space to hold 92+6*amount bytes
    * Selector function can be anything, maybe test for seeds, etc.
    * RANDOM may return huge values
    * does not yet check not to return self
@@ -349,7 +372,7 @@ size_t return_memstat_for_tracker( char **reply ) {
   if( !( r = *reply = malloc( 256*32 + (43+OT_POOLS_COUNT*32)*torrent_count ) ) ) return 0;
 
   for( i=0; i<256; ++i )
-    r += sprintf( r, "%02X: %04X %04X\n", i, (ot_dword)all_torrents[i].size, (ot_dword)all_torrents[i].space );
+    r += sprintf( r, "%02X: %08X %08X\n", i, (unsigned int)all_torrents[i].size, (unsigned int)all_torrents[i].space );
 
   for( i=0; i<256; ++i ) {
     ot_vector *torrents_list = &all_torrents[i];
@@ -359,7 +382,7 @@ size_t return_memstat_for_tracker( char **reply ) {
       r += sprintf( r, "\n%s:\n", to_hex( (ot_byte*)hash ) );
       clean_peerlist( time_now, peer_list );
       for( k=0; k<OT_POOLS_COUNT; ++k )
-        r += sprintf( r, "\t%04X %04X\n", peer_list->peers[k].size, peer_list->peers[k].space );
+        r += sprintf( r, "\t%04X %04X\n", ((unsigned int)peer_list->peers[k].size), (unsigned int)peer_list->peers[k].space );
     }
   }
 
@@ -432,7 +455,13 @@ size_t return_stats_for_tracker( char *reply, int mode ) {
     for( j=0; j<torrents_list->size; ++j ) {
       ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
       size_t local_peers = 0, local_seeds = 0;
-      clean_peerlist( time_now, peer_list );
+
+      if( clean_peerlist( time_now, peer_list ) ) {
+        ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash;
+        vector_remove_torrent( torrents_list->data, hash );
+        --j;
+        continue;
+      }
       for( k=0; k<OT_POOLS_COUNT; ++k ) {
         local_peers += peer_list->peers[k].size;
         local_seeds += peer_list->seed_count[k];
@@ -480,15 +509,12 @@ void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) {
 
   /* Maybe this does the job */
   if( clean_peerlist( NOW, torrent->peer_list ) ) {
-#ifdef WANT_CLOSED_TRACKER
-    if( !g_closedtracker )
-#endif
     vector_remove_torrent( torrents_list, hash );
     return;
   }
 
   for( i=0; i<OT_POOLS_COUNT; ++i )
-    switch( vector_remove_peer( &torrent->peer_list->peers[i], peer ) ) {
+    switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, i == 0 ) ) {
       case 0: continue;
       case 2: torrent->peer_list->seed_count[i]--;
       case 1: default: return;
-- 
cgit v1.2.3