]> git.ipfire.org Git - thirdparty/opentracker.git/commitdiff
Prepare opentracker for dual stack capabilities
authorDirk Engling <erdgeist@erdgeist.org>
Wed, 3 Apr 2024 20:25:30 +0000 (22:25 +0200)
committerDirk Engling <erdgeist@erdgeist.org>
Wed, 3 Apr 2024 20:25:30 +0000 (22:25 +0200)
ot_clean.c
ot_fullscrape.c
ot_http.c
ot_livesync.c
ot_mutex.h
ot_stats.c
ot_udp.c
ot_vector.c
ot_vector.h
trackerlogic.c
trackerlogic.h

index 139bedb50494081ac5fb5bcc1204a74832e894b1..3b494f4e6afd00ef30e25f3f9df5fbc63b25c7c2 100644 (file)
 #include "ot_accesslist.h"
 
 /* Returns amount of removed peers */
-static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, time_t timedout, int *removed_seeders ) {
-  ot_peer *last_peer = peers + peer_count, *insert_point;
-  time_t timediff;
+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;
 
   /* Two scan modes: unless there is one peer removed, just increase ot_peertime */
   while( peers < last_peer ) {
-    if( ( timediff = timedout + OT_PEERTIME( peers ) ) >= OT_PEER_TIMEOUT )
+    time_t timediff = timedout + OT_PEERTIME( peers, peer_size );
+    if( timediff >= OT_PEER_TIMEOUT )
       break;
-    OT_PEERTIME( peers++ ) = timediff;
+    OT_PEERTIME( peers, peer_size ) = timediff;
+    peers += peer_size;
   }
 
-  /* If we at least remove one peer, we have to copy  */
-  insert_point = peers;
-  while( peers < last_peer )
-    if( ( timediff = timedout + OT_PEERTIME( peers ) ) < OT_PEER_TIMEOUT ) {
-      OT_PEERTIME( peers ) = timediff;
-      memcpy( insert_point++, peers++, sizeof(ot_peer));
+  /* If we at least remove one peer, we have to copy */
+  for( insert_point = peers; peers < last_peer; peers += peer_size ) {
+    time_t timediff = timedout + OT_PEERTIME( peers, peer_size );
+
+    if( timediff < OT_PEER_TIMEOUT ) {
+      OT_PEERTIME( peers, peer_size ) = timediff;
+      memcpy( insert_point, peers, peer_size);
+      insert_point += peer_size;
     } else
-      if( OT_PEERFLAG( peers++ ) & PEER_FLAG_SEEDING )
+      if( OT_PEERFLAG_D( peers, peer_size ) & PEER_FLAG_SEEDING )
         (*removed_seeders)++;
+  }
 
   return peers - insert_point;
 }
 
-/* Clean a single torrent
-   return 1 if torrent timed out
-*/
-int clean_single_torrent( ot_torrent *torrent ) {
-  ot_peerlist *peer_list = torrent->peer_list;
-  ot_vector *bucket_list = &peer_list->peers;
+int clean_single_peer_list( ot_peerlist *peer_list, size_t peer_size ) {
+  ot_vector *peer_vector = &peer_list->peers;
   time_t timedout = (time_t)( g_now_minutes - peer_list->base );
   int num_buckets = 1, removed_seeders = 0;
 
@@ -69,24 +69,26 @@ int clean_single_torrent( ot_torrent *torrent ) {
   }
 
   if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
-    num_buckets = bucket_list->size;
-    bucket_list = (ot_vector *)bucket_list->data;
+    num_buckets = peer_vector->size;
+    peer_vector = (ot_vector *)peer_vector->data;
   }
 
   while( num_buckets-- ) {
-    size_t removed_peers = clean_single_bucket( bucket_list->data, bucket_list->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;
-    bucket_list->size     -= removed_peers;
-    if( bucket_list->size < removed_peers )
-      vector_fixup_peers( bucket_list );
-    ++bucket_list;
+    peer_vector->size     -= removed_peers;
+    if( removed_peers )
+      vector_fixup_peers( peer_vector, peer_size );
+
+    /* Skip to next bucket, a vector containing peers */
+    ++peer_vector;
   }
 
   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) )
-    vector_redistribute_buckets( peer_list );
+    vector_redistribute_buckets( peer_list, peer_size );
 
   if( peer_list->peer_count )
     peer_list->base = g_now_minutes;
@@ -96,7 +98,14 @@ int clean_single_torrent( ot_torrent *torrent ) {
     peer_list->base = g_now_minutes - OT_PEER_TIMEOUT;
   }
   return 0;
+}
 
+/* Clean a single torrent
+   return 1 if torrent timed out
+*/
+int clean_single_torrent( ot_torrent *torrent ) {
+  return clean_single_peer_list( torrent->peer_list6, OT_PEER_SIZE6) *
+         clean_single_peer_list( torrent->peer_list4, OT_PEER_SIZE4);
 }
 
 /* Clean up all peers in current bucket, remove timedout pools and
index 5d115dc0bffb6c78c01845aaa2a7f5b720ea5fef..d7d3518d4889ecd1311a45fb657b3f390a7d8970 100644 (file)
@@ -82,7 +82,11 @@ void fullscrape_deliver( int64 sock, ot_tasktype tasktype ) {
   mutex_workqueue_pushtask( sock, tasktype );
 }
 
-static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_peerlist *peer_list, ot_hash *hash ) {
+static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_torrent *torrent, ot_hash *hash ) {
+  size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_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;
+
   switch( mode & TASK_TASK_MASK ) {
     case TASK_FULLSCRAPE:
     default:
@@ -90,30 +94,30 @@ static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_peerlist *peer
       *r++='2'; *r++='0'; *r++=':';
       memcpy( r, hash, sizeof(ot_hash) ); r += sizeof(ot_hash);
       /* push rest of the scrape string */
-      r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count );
+      r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, down_count, peer_count-seed_count );
 
       break;
     case TASK_FULLSCRAPE_TPB_ASCII:
       to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
-      r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count );
+      r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count );
       break;
     case TASK_FULLSCRAPE_TPB_ASCII_PLUS:
       to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
-      r += sprintf( r, ":%zd:%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count, peer_list->down_count );
+      r += sprintf( r, ":%zd:%zd:%zd\n", seed_count, peer_count-seed_count, down_count );
       break;
     case TASK_FULLSCRAPE_TPB_BINARY:
       memcpy( r, *hash, sizeof(ot_hash) ); r += sizeof(ot_hash);
-      *(uint32_t*)(r+0) = htonl( (uint32_t)  peer_list->seed_count );
-      *(uint32_t*)(r+4) = htonl( (uint32_t)( peer_list->peer_count-peer_list->seed_count) );
+      *(uint32_t*)(r+0) = htonl( (uint32_t)  seed_count );
+      *(uint32_t*)(r+4) = htonl( (uint32_t)( peer_count-seed_count) );
       r+=8;
       break;
     case TASK_FULLSCRAPE_TPB_URLENCODED:
       r += fmt_urlencoded( r, (char *)*hash, 20 );
-      r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count );
+      r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count );
       break;
     case TASK_FULLSCRAPE_TRACKERSTATE:
       to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
-      r += sprintf( r, ":%zd:%zd\n", peer_list->base, peer_list->down_count );
+      r += sprintf( r, ":%zd:%zd\n", torrent->peer_list6->base, down_count );
       break;
     }
     return r;
@@ -145,7 +149,7 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas
 
     /* For each torrent in this bucket.. */
     for( i=0; i<torrents_list->size; ++i ) {
-      r = fullscrape_write_one( mode, r, torrents[i].peer_list, &torrents[i].hash );
+      r = fullscrape_write_one( mode, r, torrents+i, &torrents[i].hash );
 
       if( r > re) {
         /* Allocate a fresh output buffer at the end of our buffers list */
@@ -210,7 +214,7 @@ static void fullscrape_make_gzip( int *iovec_entries, struct iovec **iovector, o
     /* For each torrent in this bucket.. */
     for( i=0; i<torrents_list->size; ++i ) {
       char compress_buffer[OT_SCRAPE_MAXENTRYLEN];
-      r = fullscrape_write_one( mode, compress_buffer, torrents[i].peer_list, &torrents[i].hash );
+      r = fullscrape_write_one( mode, compress_buffer, torrents+i, &torrents[i].hash );
       strm.next_in   = (uint8_t*)compress_buffer;
       strm.avail_in  = r - compress_buffer;
       zres = deflate( &strm, Z_NO_FLUSH );
index 88b4261d1c3547f359ae093888ca160c6038d5a7..374d6d8eeb28cb1405fbb9d82240a70708e5c111 100644 (file)
--- a/ot_http.c
+++ b/ot_http.c
@@ -421,26 +421,18 @@ static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws,
     ot_ip6 proxied_ip;
     char *fwd = http_header( ws->request, ws->header_size, "x-forwarded-for" );
     if( fwd && scan_ip6( fwd, proxied_ip ) ) {
-      /* If proxy reports an ipv6 address but we can only handle v4 (or vice versa), bail out */
-#ifndef WANT_V6
-      if( !ip6_isv4mapped(proxied_ip) )
-#else
-      if( ip6_isv4mapped(proxied_ip) )
-#endif
-        HTTPERROR_400_PARAM;
-
-      OT_SETIP( &ws->peer, proxied_ip );
+      OT_SETIP( ws->peer, proxied_ip );
     } else
-      OT_SETIP( &ws->peer, cookie->ip );
+      OT_SETIP( ws->peer, cookie->ip );
   } else
 #endif
-  OT_SETIP( &ws->peer, cookie->ip );
+  OT_SETIP( ws->peer, cookie->ip );
 
   ws->peer_id = NULL;
   ws->hash = NULL;
 
-  OT_SETPORT( &ws->peer, &port );
-  OT_PEERFLAG( &ws->peer ) = 0;
+  OT_SETPORT( ws->peer, &port );
+  OT_PEERFLAG( ws->peer ) = 0;
   numwant = 50;
   scanon = 1;
 
index 75a5f9fdb4f26ce34e319f0efa8150d02b088cb5..b87fa6ddd67f267d4b70ed27873f2cb4a5797b4d 100644 (file)
@@ -127,13 +127,13 @@ static void livesync_handle_peersync( struct ot_workstruct *ws ) {
 
   /* Now basic sanity checks have been done on the live sync packet
      We might add more testing and logging. */
-  while( off + (ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ) <= ws->request_size ) {
-    memcpy( &ws->peer, ws->request + off + sizeof(ot_hash), sizeof( ot_peer ) );
+  while( off + (ssize_t)sizeof( ot_hash ) + OT_PEER_SIZE4 <= ws->request_size ) {
+    memcpy( &ws->peer, ws->request + off + sizeof(ot_hash), OT_PEER_SIZE4 );
     ws->hash = (ot_hash*)(ws->request + off);
 
     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 );
     else
       add_peer_to_torrent_and_return_peers( FLAG_MCA, ws, /* amount = */ 0 );
@@ -143,7 +143,7 @@ static void livesync_handle_peersync( struct ot_workstruct *ws ) {
 
   stats_issue_event(EVENT_SYNC, 0,
                     (ws->request_size - sizeof( g_tracker_id ) - sizeof( uint32_t ) ) /
-                    ((ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer )));
+                    ((ssize_t)sizeof( ot_hash ) + OT_PEER_SIZE4));
 }
 
 /* Tickle the live sync module from time to time, so no events get
@@ -164,9 +164,9 @@ void livesync_tell( struct ot_workstruct *ws ) {
   pthread_mutex_lock(&g_outbuf_mutex);
 
   memcpy( g_outbuf + g_outbuf_data, ws->hash, sizeof(ot_hash) );
-  memcpy( g_outbuf + g_outbuf_data + sizeof(ot_hash), &ws->peer, sizeof(ot_peer) );
+  memcpy( g_outbuf + g_outbuf_data + sizeof(ot_hash), &ws->peer, OT_PEER_SIZE4 );
 
-  g_outbuf_data += sizeof(ot_hash) + sizeof(ot_peer);
+  g_outbuf_data += sizeof(ot_hash) + OT_PEER_SIZE4;
 
   if( g_outbuf_data >= LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS )
     livesync_issue_peersync();
index 93c1ecfc393ab160c0f8161d3dd4f5af817bd662..8d64cf6ceada63420161acce7a0c88056e111bfa 100644 (file)
@@ -43,7 +43,7 @@ typedef enum {
   TASK_STATS_EVERYTHING            = 0x0106,
   TASK_STATS_FULLLOG               = 0x0107,
   TASK_STATS_WOODPECKERS           = 0x0108,
-  
+
   TASK_FULLSCRAPE                  = 0x0200, /* Default mode */
   TASK_FULLSCRAPE_TPB_BINARY       = 0x0201,
   TASK_FULLSCRAPE_TPB_ASCII        = 0x0202,
index 7d2749fe2ba793064914b6feb1608c471051e75f..b3cc48a0c0f301304903fb0ecffbce9a84f78748 100644 (file)
@@ -73,13 +73,13 @@ static time_t ot_start_time;
 #define __LDR(P,D)   ((__BYTE((P),(D))>>__SHFT((D)))&__MSK)
 #define __STR(P,D,V)   __BYTE((P),(D))=(__BYTE((P),(D))&~(__MSK<<__SHFT((D))))|((V)<<__SHFT((D)))
 
-#ifdef WANT_V6
-#define STATS_NETWORK_NODE_MAXDEPTH  (68-STATS_NETWORK_NODE_BITWIDTH)
-#define STATS_NETWORK_NODE_LIMIT     (48-STATS_NETWORK_NODE_BITWIDTH)
-#else
+//#ifdef WANT_V6
+//#define STATS_NETWORK_NODE_MAXDEPTH  (68-STATS_NETWORK_NODE_BITWIDTH)
+//#define STATS_NETWORK_NODE_LIMIT     (48-STATS_NETWORK_NODE_BITWIDTH)
+//#else
 #define STATS_NETWORK_NODE_MAXDEPTH  (28-STATS_NETWORK_NODE_BITWIDTH)
 #define STATS_NETWORK_NODE_LIMIT     (24-STATS_NETWORK_NODE_BITWIDTH)
-#endif
+//#endif
 
 typedef union stats_network_node stats_network_node;
 union stats_network_node {
@@ -219,12 +219,12 @@ static size_t stats_slash24s_txt( char *reply, size_t amount ) {
   stats_network_node *slash24s_network_counters_root = NULL;
   char *r=reply;
   int bucket;
-  size_t i;
+  size_t i, peer_size = OT_PEER_SIZE4;
 
   for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
     ot_vector *torrents_list = mutex_bucket_lock( bucket );
     for( i=0; i<torrents_list->size; ++i ) {
-      ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list;
+      ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list4;
       ot_vector   *bucket_list = &peer_list->peers;
       int          num_buckets = 1;
 
@@ -236,9 +236,11 @@ static size_t stats_slash24s_txt( char *reply, size_t amount ) {
       while( num_buckets-- ) {
         ot_peer *peers = (ot_peer*)bucket_list->data;
         size_t   numpeers = bucket_list->size;
-        while( numpeers-- )
-          if( stat_increase_network_count( &slash24s_network_counters_root, 0, (uintptr_t)(peers++) ) )
+        while( numpeers-- ) {
+          if( stat_increase_network_count( &slash24s_network_counters_root, 0, (uintptr_t)(peers) ) )
             goto bailout_unlock;
+          peers += peer_size;
+        }
         ++bucket_list;
       }
     }
@@ -285,8 +287,8 @@ typedef struct {
 static int torrent_statter( ot_torrent *torrent, uintptr_t data ) {
   torrent_stats *stats = (torrent_stats*)data;
   stats->torrent_count++;
-  stats->peer_count += torrent->peer_list->peer_count;
-  stats->seed_count += torrent->peer_list->seed_count;
+  stats->peer_count += torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
+  stats->seed_count += torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
   return 0;
 }
 
@@ -312,21 +314,23 @@ size_t stats_top_txt( char * reply, int amount ) {
     ot_vector *torrents_list = mutex_bucket_lock( bucket );
     for( j=0; j<torrents_list->size; ++j ) {
       ot_torrent *torrent = (ot_torrent*)(torrents_list->data) + j;
+      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;
       idx = amount - 1;
-      while( (idx >= 0) && ( torrent->peer_list->peer_count > top100c[idx].val ) )
+      while( (idx >= 0) && ( peer_count > top100c[idx].val ) )
         --idx;
       if ( idx++ != amount - 1 ) {
         memmove( top100c + idx + 1, top100c + idx, ( amount - 1 - idx ) * sizeof( ot_record ) );
         memcpy( &top100c[idx].hash, &torrent->hash, sizeof(ot_hash));
-        top100c[idx].val = torrent->peer_list->peer_count;
+        top100c[idx].val = peer_count;
       }
       idx = amount - 1;
-      while( (idx >= 0) && ( torrent->peer_list->seed_count > top100s[idx].val ) )
+      while( (idx >= 0) && ( seed_count > top100s[idx].val ) )
         --idx;
       if ( idx++ != amount - 1 ) {
         memmove( top100s + idx + 1, top100s + idx, ( amount - 1 - idx ) * sizeof( ot_record ) );
         memcpy( &top100s[idx].hash, &torrent->hash, sizeof(ot_hash));
-        top100s[idx].val = torrent->peer_list->seed_count;
+        top100s[idx].val = seed_count;
       }
     }
     mutex_bucket_unlock( bucket, 0 );
@@ -718,7 +722,7 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event
       break;
     case EVENT_SYNC:
       ot_overall_sync_count+=event_data;
-           break;
+      break;
     case EVENT_BUCKET_LOCKED:
       ot_overall_stall_count++;
       break;
index 830966077120a3c286435a78382ac6c95ac3a588..c32a7e2f51a3c8ff4c93c0ab3cb7706413f31188 100644 (file)
--- a/ot_udp.c
+++ b/ot_udp.c
@@ -13,6 +13,7 @@
 /* Libowfat */
 #include "socket.h"
 #include "io.h"
+#include "ip6.h"
 
 /* Opentracker */
 #include "trackerlogic.h"
@@ -73,7 +74,7 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) {
   ot_ip6      remoteip;
   uint32_t   *inpacket = (uint32_t*)ws->inbuf;
   uint32_t   *outpacket = (uint32_t*)ws->outbuf;
-  uint32_t    numwant, left, event, scopeid;
+  uint32_t    left, event, scopeid;
   uint32_t    connid[2];
   uint32_t    action;
   uint16_t    port, remoteport;
@@ -141,34 +142,35 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) {
       /* We do only want to know, if it is zero */
       left  = inpacket[64/4] | inpacket[68/4];
 
-      /* Limit amount of peers to OT_MAX_PEERS_UDP */
-      numwant = ntohl( inpacket[92/4] );
-      if (numwant > OT_MAX_PEERS_UDP) numwant = OT_MAX_PEERS_UDP;
-
       event    = ntohl( inpacket[80/4] );
       port     = *(uint16_t*)( ((char*)inpacket) + 96 );
       ws->hash = (ot_hash*)( ((char*)inpacket) + 16 );
 
-      OT_SETIP( &ws->peer, remoteip );
-      OT_SETPORT( &ws->peer, &port );
-      OT_PEERFLAG( &ws->peer ) = 0;
+      OT_SETIP( ws->peer, remoteip );
+      OT_SETPORT( ws->peer, &port );
+      OT_PEERFLAG( ws->peer ) = 0;
 
       switch( event ) {
-        case 1: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; break;
-        case 3: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; break;
+        case 1: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED; break;
+        case 3: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED; break;
         default: break;
       }
 
       if( !left )
-        OT_PEERFLAG( &ws->peer )         |= PEER_FLAG_SEEDING;
+        OT_PEERFLAG( ws->peer )         |= PEER_FLAG_SEEDING;
 
       outpacket[0] = htonl( 1 );    /* announce action */
       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_size = remove_peer_from_torrent( FLAG_UDP, ws );
       } else {
+        /* Limit amount of peers to OT_MAX_PEERS_UDP */
+        uint32_t numwant = ntohl( inpacket[92/4] );
+        size_t max_peers = ip6_isv4mapped(remoteip) ? OT_MAX_PEERS_UDP4 : OT_MAX_PEERS_UDP6;
+        if (numwant > max_peers) numwant = max_peers;
+
         ws->reply      = ws->outbuf + 8;
         ws->reply_size = 8 + add_peer_to_torrent_and_return_peers( FLAG_UDP, ws, numwant );
       }
index 2a632b2782c1a932907a7fb264f4d764cffce847..c38f05d8413c4a8278effa798f66cef8a2c87f3b 100644 (file)
 #include "uint32.h"
 #include "uint16.h"
 
-static int vector_compare_peer(const void *peer1, const void *peer2 ) {
-  return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE );
+static int vector_compare_peer6(const void *peer1, const void *peer2 ) {
+  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 );
 }
 
 /* This function gives us a binary search that returns a pointer, even if
@@ -47,10 +50,10 @@ void *binary_search( const void * const key, const void * base, const size_t mem
   return (void*)base;
 }
 
-static uint8_t vector_hash_peer( ot_peer *peer, int bucket_count ) {
-  unsigned int hash = 5381, i = OT_PEER_COMPARE_SIZE;
+static uint8_t vector_hash_peer( ot_peer const *peer, size_t compare_size, int bucket_count ) {
+  unsigned int hash = 5381;
   uint8_t *p = (uint8_t*)peer;
-  while( i-- ) hash += (hash<<5) + *(p++);
+  while( compare_size-- ) hash += (hash<<5) + *(p++);
   return hash % bucket_count;
 }
 
@@ -82,27 +85,37 @@ void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, s
   return match;
 }
 
-ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ) {
-  ot_peer *match;
+ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch ) {
+  ot_peer *match, *end;
+  const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
+  size_t match_to_end;
 
   /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
   if( vector->space < vector->size )
-    vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size );
-  match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, exactmatch );
+    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 );
 
   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 */
+  end = (ot_peer*)vector->data + vector->size * peer_size;
+  match_to_end = end - match;
+
   if( vector->size + 1 > vector->space ) {
+    ptrdiff_t offset = match - (ot_peer*)vector->data;
     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 * sizeof(ot_peer) );
+    ot_peer *new_data = realloc( vector->data, new_space * peer_size );
+
     if( !new_data ) return NULL;
     /* Adjust pointer if it moved by realloc */
-    match = new_data + (match - (ot_peer*)vector->data);
+    match = new_data + offset;
 
     vector->data = new_data;
     vector->space = new_space;
   }
-  memmove( match + 1, match, sizeof(ot_peer) * ( ((ot_peer*)vector->data) + vector->size - match ) );
+
+  /* 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);
 
   vector->size++;
   return match;
@@ -113,26 +126,27 @@ ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exac
               1 if a non-seeding peer was removed
               2 if a seeding peer was removed
 */
-int vector_remove_peer( ot_vector *vector, ot_peer *peer ) {
-  int      exactmatch;
-  ot_peer *match, *end;
+int vector_remove_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size) {
+  int      exactmatch, was_seeder;
+  ot_peer  *match, *end;
+  size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
 
   if( !vector->size ) return 0;
 
   /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
   if( vector->space < vector->size )
-    vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size );
+    vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, compare_size, vector->size );
 
-  end = ((ot_peer*)vector->data) + vector->size;
-  match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch );
+  end = ((ot_peer*)vector->data) + peer_size * vector->size;
+  match = (ot_peer*)binary_search( peer, vector->data, vector->size, peer_size, compare_size, &exactmatch );
   if( !exactmatch ) return 0;
 
-  exactmatch = ( OT_PEERFLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1;
-  memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) );
+  was_seeder = ( OT_PEERFLAG_D( match, peer_size ) & PEER_FLAG_SEEDING ) ? 2 : 1;
+  memmove( match, match + peer_size, end - match - peer_size );
 
   vector->size--;
-  vector_fixup_peers( vector );
-  return exactmatch;
+  vector_fixup_peers( vector, peer_size );
+  return was_seeder;
 }
 
 void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
@@ -142,7 +156,8 @@ void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
 
   /* If this is being called after a unsuccessful malloc() for peer_list
      in add_peer_to_torrent, match->peer_list actually might be NULL */
-  if( match->peer_list) free_peerlist( match->peer_list );
+  if( match->peer_list6) free_peerlist( match->peer_list6 );
+  if( match->peer_list4) free_peerlist( match->peer_list4 );
 
   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 ) ) {
@@ -158,9 +173,11 @@ void vector_clean_list( ot_vector * vector, int num_buckets ) {
   return;
 }
 
-void vector_redistribute_buckets( ot_peerlist * peer_list ) {
+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;
   ot_vector * bucket_list_new, * bucket_list_old = &peer_list->peers;
+  int (*sort_func)(const void *, const void *) =
+    peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4;
 
   if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
     num_buckets_old = peer_list->peers.size;
@@ -198,33 +215,33 @@ void vector_redistribute_buckets( ot_peerlist * peer_list ) {
   /* preallocate vectors to hold all peers */
   for( bucket=0; bucket<num_buckets_new; ++bucket ) {
     bucket_list_new[bucket].space = bucket_size_new;
-    bucket_list_new[bucket].data  = malloc( bucket_size_new * sizeof(ot_peer) );
+    bucket_list_new[bucket].data  = malloc( bucket_size_new * peer_size );
     if( !bucket_list_new[bucket].data )
       return vector_clean_list( bucket_list_new, num_buckets_new );
   }
 
   /* Now sort them into the correct bucket */
   for( bucket=0; bucket<num_buckets_old; ++bucket ) {
-    ot_peer * peers_old = bucket_list_old[bucket].data, * peers_new;
+    ot_peer * peers_old = bucket_list_old[bucket].data;
     int peer_count_old = bucket_list_old[bucket].size;
     while( peer_count_old-- ) {
       ot_vector * bucket_dest = bucket_list_new;
       if( num_buckets_new > 1 )
-        bucket_dest += vector_hash_peer(peers_old, 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 ) {
-        void * tmp = realloc( bucket_dest->data, sizeof(ot_peer) * 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 );
         bucket_dest->data   = tmp;
         bucket_dest->space *= OT_VECTOR_GROW_RATIO;
       }
-      peers_new = (ot_peer*)bucket_dest->data;
-      memcpy(peers_new + bucket_dest->size++, peers_old++, sizeof(ot_peer));
+      memcpy((ot_peer*)bucket_dest->data + peer_size * bucket_dest->size++, peers_old, peer_size);
+      peers_old += peer_size;
     }
   }
 
   /* Now sort each bucket to later allow bsearch */
   for( bucket=0; bucket<num_buckets_new; ++bucket )
-    qsort( bucket_list_new[bucket].data, bucket_list_new[bucket].size, sizeof( ot_peer ), vector_compare_peer );
+    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 */
   if( OT_PEERLIST_HASBUCKETS( peer_list) )
@@ -244,7 +261,7 @@ void vector_redistribute_buckets( ot_peerlist * peer_list ) {
   }
 }
 
-void vector_fixup_peers( ot_vector * vector ) {
+void vector_fixup_peers( ot_vector * vector, size_t peer_size ) {
   int need_fix = 0;
 
   if( !vector->size ) {
@@ -260,7 +277,7 @@ void vector_fixup_peers( ot_vector * vector ) {
     need_fix++;
   }
   if( need_fix )
-    vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) );
+    vector->data = realloc( vector->data, vector->space * peer_size );
 }
 
 const char *g_version_vector_c = "$Source$: $Revision$\n";
index f7f87aa3c3d73a5f9e7465bd418b93b7fba0ea2d..f60c291496e70bdf5c87b409fbccc607005beab3 100644 (file)
@@ -24,11 +24,13 @@ typedef struct {
 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 );
 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 *peer, 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 *peer );
+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_redistribute_buckets( ot_peerlist * peer_list );
-void     vector_fixup_peers( ot_vector * vector );
+
+/* For ot_clean.c */
+void     vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size );
+void     vector_fixup_peers( ot_vector * vector, size_t peer_size );
 
 #endif
index 47e00855ee5b0d3a0006cae6ffd52a0425ca9910..9d564c1e7b540bfd9500eac1f103c8eb7e660395 100644 (file)
@@ -16,6 +16,7 @@
 #include "byte.h"
 #include "io.h"
 #include "iob.h"
+#include "ip6.h"
 #include "array.h"
 
 /* Opentracker */
@@ -57,25 +58,33 @@ void add_torrent_from_saved_state( ot_hash hash, ot_time base, size_t down_count
     return mutex_bucket_unlock_by_hash( hash, 0 );
 
   /* Create a new torrent entry, then */
+  byte_zero( torrent, sizeof( ot_torrent ) );
   memcpy( torrent->hash, hash, sizeof(ot_hash) );
 
-  if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
+  if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) ||
+      !( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) {
     vector_remove_torrent( torrents_list, torrent );
     return mutex_bucket_unlock_by_hash( hash, 0 );
   }
 
-  byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
-  torrent->peer_list->base = base;
-  torrent->peer_list->down_count = down_count;
+  byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) );
+  byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) );
+  torrent->peer_list6->base = base;
+  torrent->peer_list4->base = base;
+  torrent->peer_list6->down_count = down_count;
+  torrent->peer_list4->down_count = down_count;
 
   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 ) {
-  int         exactmatch, delta_torrentcount = 0;
-  ot_torrent *torrent;
-  ot_peer    *peer_dest;
-  ot_vector  *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
+  int          exactmatch, delta_torrentcount = 0;
+  ot_torrent  *torrent;
+  ot_peer     *peer_dest;
+  ot_vector   *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
+  ot_peerlist *peer_list;
+  size_t       peer_size; /* initialized in next line */
+  ot_peer     *peer_src = peer_from_peer6(&ws->peer, &peer_size);
 
   if( !accesslist_hashisvalid( *ws->hash ) ) {
     mutex_bucket_unlock_by_hash( *ws->hash, 0 );
@@ -95,82 +104,88 @@ size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstr
 
   if( !exactmatch ) {
     /* Create a new torrent entry, then */
+    byte_zero( torrent, sizeof(ot_torrent));
     memcpy( torrent->hash, *ws->hash, sizeof(ot_hash) );
 
-    if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
+    if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) ||
+        !( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) {
       vector_remove_torrent( torrents_list, torrent );
       mutex_bucket_unlock_by_hash( *ws->hash, 0 );
       return 0;
     }
 
-    byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
+    byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) );
+    byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) );
     delta_torrentcount = 1;
   } else
     clean_single_torrent( torrent );
 
-  torrent->peer_list->base = g_now_minutes;
+  torrent->peer_list6->base = g_now_minutes;
+  torrent->peer_list4->base = g_now_minutes;
+
+  peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
 
   /* Check for peer in torrent */
-  peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), &ws->peer, &exactmatch );
+  peer_dest = vector_find_or_insert_peer( &(peer_list->peers), peer_src, peer_size, &exactmatch );
   if( !peer_dest ) {
     mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
     return 0;
   }
 
   /* Tell peer that it's fresh */
-  OT_PEERTIME( &ws->peer ) = 0;
+  OT_PEERTIME( ws->peer, OT_PEER_SIZE6 ) = 0;
 
   /* 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 )
-    OT_PEERFLAG( &ws->peer ) ^= PEER_FLAG_COMPLETED;
+  if( ( OT_PEERFLAG( ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
+    OT_PEERFLAG( ws->peer ) ^= PEER_FLAG_COMPLETED;
 
   /* If we hadn't had a match create peer there */
   if( !exactmatch ) {
 
 #ifdef WANT_SYNC_LIVE
     if( proto == FLAG_MCA )
-      OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_FROM_SYNC;
+      OT_PEERFLAG( ws->peer ) |= PEER_FLAG_FROM_SYNC;
     else
       livesync_tell( ws );
 #endif
 
-    torrent->peer_list->peer_count++;
-    if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) {
-      torrent->peer_list->down_count++;
+    peer_list->peer_count++;
+    if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_COMPLETED ) {
+      peer_list->down_count++;
       stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
     }
-    if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING )
-      torrent->peer_list->seed_count++;
+    if( OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING )
+      peer_list->seed_count++;
 
   } else {
-    stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest ) );
+    stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest, peer_size ) );
 #ifdef WANT_SPOT_WOODPECKER
-    if( ( OT_PEERTIME(peer_dest) > 0 ) && ( OT_PEERTIME(peer_dest) < 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 );
 #endif
 #ifdef WANT_SYNC_LIVE
     /* Won't live sync peers that come back too fast. Only exception:
        fresh "completed" reports */
     if( proto != FLAG_MCA ) {
-      if( OT_PEERTIME( peer_dest ) > OT_CLIENT_SYNC_RENEW_BOUNDARY ||
-         ( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) )
+      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 ) ) )
         livesync_tell( ws );
     }
 #endif
 
-    if(  (OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING )   && !(OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) )
-      torrent->peer_list->seed_count--;
-    if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING )   &&  (OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) )
-      torrent->peer_list->seed_count++;
-    if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) &&  (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) {
-      torrent->peer_list->down_count++;
+    if(  (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING )   && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) )
+      peer_list->seed_count--;
+    if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING )   &&  (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) )
+      peer_list->seed_count++;
+    if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) &&  (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) {
+      peer_list->down_count++;
       stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
     }
-    if(   OT_PEERFLAG(peer_dest) & 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;
   }
 
-  memcpy( peer_dest, &ws->peer, sizeof(ot_peer) );
+  memcpy( peer_dest, peer_src, peer_size );
 #ifdef WANT_SYNC
   if( proto == FLAG_MCA ) {
     mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
@@ -183,10 +198,11 @@ size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstr
   return ws->reply_size;
 }
 
-static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) {
+static size_t return_peers_all( ot_peerlist *peer_list, size_t peer_size, char *reply ) {
   unsigned int bucket, num_buckets = 1;
   ot_vector  * bucket_list = &peer_list->peers;
-  size_t       result = OT_PEER_COMPARE_SIZE * peer_list->peer_count;
+  size_t       compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
+  size_t       result = compare_size * peer_list->peer_count;
   char       * r_end = reply + result;
 
   if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
@@ -195,28 +211,30 @@ static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) {
   }
 
   for( bucket = 0; bucket<num_buckets; ++bucket ) {
-    ot_peer * peers = (ot_peer*)bucket_list[bucket].data;
-    size_t    peer_count = bucket_list[bucket].size;
+    ot_peer *peers = bucket_list[bucket].data;
+    size_t   peer_count = bucket_list[bucket].size;
     while( peer_count-- ) {
-      if( OT_PEERFLAG(peers) & PEER_FLAG_SEEDING ) {
-        r_end-=OT_PEER_COMPARE_SIZE;
-        memcpy(r_end,peers++,OT_PEER_COMPARE_SIZE);
+      if( OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING ) {
+        r_end -= peer_size;
+        memcpy( r_end, peers, compare_size);
       } else {
-        memcpy(reply,peers++,OT_PEER_COMPARE_SIZE);
-        reply+=OT_PEER_COMPARE_SIZE;
+        memcpy( reply, peers, compare_size );
+        reply += compare_size;
       }
+      peers += peer_size;
     }
   }
   return result;
 }
 
-static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *peer_list, 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;
   ot_vector  * bucket_list = &peer_list->peers;
   unsigned int shifted_pc = peer_list->peer_count;
   unsigned int shifted_step = 0;
   unsigned int shift = 0;
-  size_t       result = OT_PEER_COMPARE_SIZE * amount;
+  size_t       compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
+  size_t       result = compare_size * amount;
   char       * r_end = reply + result;
 
   if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
@@ -235,7 +253,7 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee
   bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count;
 
   while( amount-- ) {
-    ot_peer * peer;
+    ot_peer *peer;
 
     /* This is the aliased, non shifted range, next value may fall into */
     unsigned int diff = ( ( ( amount + 1 ) * shifted_step ) >> shift ) -
@@ -246,13 +264,13 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee
       bucket_offset -= bucket_list[bucket_index].size;
       bucket_index = ( bucket_index + 1 ) % num_buckets;
     }
-    peer = ((ot_peer*)bucket_list[bucket_index].data) + bucket_offset;
-    if( OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) {
-      r_end-=OT_PEER_COMPARE_SIZE;
-      memcpy(r_end,peer,OT_PEER_COMPARE_SIZE);
+    peer = bucket_list[bucket_index].data + peer_size * bucket_offset;
+    if( OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING ) {
+      r_end -= compare_size;
+      memcpy(r_end, peer, compare_size);
     } else {
-      memcpy(reply,peer,OT_PEER_COMPARE_SIZE);
-      reply+=OT_PEER_COMPARE_SIZE;
+      memcpy(reply, peer, compare_size);
+      reply += compare_size;
     }
   }
   return result;
@@ -267,15 +285,17 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee
    * 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 ) {
-  ot_peerlist *peer_list = torrent->peer_list;
+  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;
   char        *r = reply;
+  size_t      compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
 
   if( amount > peer_list->peer_count )
     amount = peer_list->peer_count;
 
   if( proto == FLAG_TCP ) {
     int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
-    r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie" PEERS_BENCODED "%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, erval, erval/2, OT_PEER_COMPARE_SIZE*amount );
+    r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, erval, erval/2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4, compare_size * amount );
   } else {
     *(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
     *(uint32_t*)(r+4) = htonl( peer_list->peer_count - peer_list->seed_count );
@@ -285,9 +305,9 @@ size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent,
 
   if( amount ) {
     if( amount == peer_list->peer_count )
-      r += return_peers_all( peer_list, r );
+      r += return_peers_all( peer_list, peer_size, r );
     else
-      r += return_peers_selection( ws, peer_list, amount, r );
+      r += return_peers_selection( ws, peer_list, peer_size, amount, r );
   }
 
   if( proto == FLAG_TCP )
@@ -312,9 +332,10 @@ size_t return_udp_scrape_for_torrent( ot_hash hash, char *reply ) {
       memset( reply, 0, 12);
       delta_torrentcount = -1;
     } else {
-      r[0] = htonl( torrent->peer_list->seed_count );
-      r[1] = htonl( torrent->peer_list->down_count );
-      r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->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[2] = htonl( torrent->peer_list6->peer_count + torrent->peer_list4->peer_count -
+                    torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
     }
   }
   mutex_bucket_unlock_by_hash( hash, delta_torrentcount );
@@ -342,7 +363,10 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl
         *r++='2';*r++='0';*r++=':';
         memcpy( r, hash, sizeof(ot_hash) ); r+=sizeof(ot_hash);
         r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee",
-          torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count );
+          torrent->peer_list6->seed_count + torrent->peer_list4->seed_count,
+          torrent->peer_list6->down_count + torrent->peer_list4->down_count,
+          torrent->peer_list6->peer_count + torrent->peer_list4->peer_count -
+          torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
       }
     }
     mutex_bucket_unlock_by_hash( *hash, delta_torrentcount );
@@ -358,17 +382,19 @@ size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) {
   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_peerlist *peer_list = &dummy_list;
+  size_t       peer_size; /* initialized in next line */
+  ot_peer     *peer_src = peer_from_peer6(&ws->peer, &peer_size);
 
 #ifdef WANT_SYNC_LIVE
   if( proto != FLAG_MCA ) {
-    OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED;
+    OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED;
     livesync_tell( ws );
   }
 #endif
 
   if( exactmatch ) {
-    peer_list = torrent->peer_list;
-    switch( vector_remove_peer( &peer_list->peers, &ws->peer ) ) {
+    peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
+    switch( vector_remove_peer( &peer_list->peers, peer_src, peer_size ) ) {
       case 2:  peer_list->seed_count--; /* Intentional fallthrough */
       case 1:  peer_list->peer_count--; /* Intentional fallthrough */
       default: break;
@@ -377,7 +403,7 @@ size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) {
 
   if( proto == FLAG_TCP ) {
     int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
-    ws->reply_size = sprintf( ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie" PEERS_BENCODED "0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, erval, erval / 2 );
+    ws->reply_size = sprintf( ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, erval, erval / 2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4 );
   }
 
   /* Handle UDP reply */
@@ -409,6 +435,23 @@ void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data
   }
 }
 
+ot_peer *peer_from_peer6( ot_peer6 *peer, size_t *peer_size ) {
+  ot_ip6 *ip = (ot_ip6*)peer;
+  if( !ip6_isv4mapped(ip) ) {
+    *peer_size = OT_PEER_SIZE6;
+    return (ot_peer*)peer;
+  }
+  *peer_size = OT_PEER_SIZE4;
+  return (ot_peer*)(((uint8_t*)peer) + 12);
+}
+
+size_t   peer_size_from_peer6(ot_peer6 *peer) {
+  ot_ip6 *ip = (ot_ip6*)peer;
+  if( !ip6_isv4mapped(ip))
+    return OT_PEER_SIZE6;
+  return OT_PEER_SIZE4;
+}
+
 void exerr( char * message ) {
   fprintf( stderr, "%s\n", message );
   exit( 111 );
@@ -440,7 +483,8 @@ void trackerlogic_deinit( void ) {
     if( torrents_list->size ) {
       for( j=0; j<torrents_list->size; ++j ) {
         ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j;
-        free_peerlist( torrent->peer_list );
+        free_peerlist( torrent->peer_list6 );
+        free_peerlist( torrent->peer_list4 );
         delta_torrentcount -= 1;
       }
       free( torrents_list->data );
index f43b4f18196e8c1a2052c2392cb6ab7d8d9b7854..24ef097f77c02f40d66576cd80a8ea16ecd0277f 100644 (file)
@@ -24,16 +24,12 @@ typedef time_t  ot_time;
 typedef char    ot_ip6[16];
 typedef struct { ot_ip6 address; int bits; }
                 ot_net;
-#ifdef WANT_V6
-#define OT_IP_SIZE 16
-#define PEERS_BENCODED "6:peers6"
 /* List of peers should fit in a single UDP packet (around 1200 bytes) */
-#define OT_MAX_PEERS_UDP 66
-#else
-#define OT_IP_SIZE 4
-#define PEERS_BENCODED "5:peers"
-#define OT_MAX_PEERS_UDP 200
-#endif
+#define OT_MAX_PEERS_UDP6 66
+#define OT_MAX_PEERS_UDP4 200
+
+#define OT_IP_SIZE6 16
+#define OT_IP_SIZE4 4
 #define OT_PORT_SIZE 2
 #define OT_FLAG_SIZE 1
 #define OT_TIME_SIZE 1
@@ -61,6 +57,7 @@ typedef struct { ot_ip6 address; int bits; }
 #define OT_ADMINIP_MAX 64
 #define OT_MAX_THREADS 64
 
+/* Number of minutes after announce before peer is removed */
 #define OT_PEER_TIMEOUT 45
 
 /* We maintain a list of 1024 pointers to sorted list of ot_torrent structs
@@ -78,23 +75,35 @@ extern volatile int g_opentracker_running;
 extern uint32_t g_tracker_id;
 typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG;
 
-#define OT_PEER_COMPARE_SIZE ((OT_IP_SIZE)+(OT_PORT_SIZE))
-#define OT_PEER_SIZE ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE))
-typedef uint8_t ot_peer[OT_PEER_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_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_SIZE4 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE4))
+
+typedef uint8_t ot_peer[1];
+typedef uint8_t ot_peer6[OT_PEER_SIZE6];
+typedef uint8_t ot_peer4[OT_PEER_SIZE4];
 static const uint8_t PEER_FLAG_SEEDING   = 0x80;
 static const uint8_t PEER_FLAG_COMPLETED = 0x40;
 static const uint8_t PEER_FLAG_STOPPED   = 0x20;
 static const uint8_t PEER_FLAG_FROM_SYNC = 0x10;
 static const uint8_t PEER_FLAG_LEECHING  = 0x00;
 
-#ifdef WANT_V6
-#define OT_SETIP(peer,ip)     memcpy((peer),(ip),(OT_IP_SIZE))
-#else
-#define OT_SETIP(peer,ip)     memcpy((peer),(((uint8_t*)ip)+12),(OT_IP_SIZE))
-#endif
-#define OT_SETPORT(peer,port) memcpy(((uint8_t*)(peer))+(OT_IP_SIZE),(port),2)
-#define OT_PEERFLAG(peer)     (((uint8_t*)(peer))[(OT_IP_SIZE)+2])
-#define OT_PEERTIME(peer)     (((uint8_t*)(peer))[(OT_IP_SIZE)+3])
+/* Takes an ot_peer6 and returns the proper pointer to the peer and sets peer_size */
+ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size);
+size_t   peer_size_from_peer6(ot_peer6 *peer);
+
+/* New style */
+#define OT_SETIP(peer,ip)              memcpy((peer),(ip),OT_IP_SIZE6)
+#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_D(peer,peersize)   (((uint8_t*)(peer))[(peersize)-2])
+#define OT_PEERTIME(peer,peersize)     (((uint8_t*)(peer))[(peersize)-1])
+
+#define PEERS_BENCODED6 "6:peers6"
+#define PEERS_BENCODED4 "5:peers"
 
 #define OT_HASH_COMPARE_SIZE (sizeof(ot_hash))
 
@@ -102,7 +111,8 @@ struct ot_peerlist;
 typedef struct ot_peerlist ot_peerlist;
 typedef struct {
   ot_hash      hash;
-  ot_peerlist *peer_list;
+  ot_peerlist *peer_list6;
+  ot_peerlist *peer_list4;
 } ot_torrent;
 
 #include "ot_vector.h"
@@ -131,7 +141,7 @@ struct ot_workstruct {
 #endif
 
   /* The peer currently in the working */
-  ot_peer  peer;
+  ot_peer6 peer; /* Can fit v6 and v4 peers */
 
   /* Pointers into the request buffer */
   ot_hash *hash;