/* Libowfat */
#include "byte.h"
#include "io.h"
+#include "ip4.h"
#include "ip6.h"
/* Opentracker */
static time_t ot_start_time;
-#ifdef WANT_LOG_NETWORKS
-#define STATS_NETWORK_NODE_BITWIDTH 8
-#define STATS_NETWORK_NODE_COUNT (1<<STATS_NETWORK_NODE_BITWIDTH)
+#define STATS_NETWORK_NODE_BITWIDTH 4
+#define STATS_NETWORK_NODE_COUNT (1<<STATS_NETWORK_NODE_BITWIDTH)
+
+#define __BYTE(P,D) (((uint8_t*)P)[D/8])
+#define __MSK (STATS_NETWORK_NODE_COUNT-1)
+#define __SHFT(D) ((D^STATS_NETWORK_NODE_BITWIDTH)&STATS_NETWORK_NODE_BITWIDTH)
+
+#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 (48/8-1)
+#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 (12+24/8-1)
+#define STATS_NETWORK_NODE_MAXDEPTH (28-STATS_NETWORK_NODE_BITWIDTH)
+#define STATS_NETWORK_NODE_LIMIT (24-STATS_NETWORK_NODE_BITWIDTH)
#endif
-
typedef union stats_network_node stats_network_node;
union stats_network_node {
int counters[STATS_NETWORK_NODE_COUNT];
stats_network_node *children[STATS_NETWORK_NODE_COUNT];
};
+#ifdef WANT_LOG_NETWORKS
static stats_network_node *stats_network_counters_root = NULL;
+#endif
static int stat_increase_network_count( stats_network_node **node, int depth, uintptr_t ip ) {
- uint8_t *_ip = (uint8_t*)ip;
- int foo = _ip[depth];
+ int foo = __LDR(ip,depth);
if( !*node ) {
*node = malloc( sizeof( stats_network_node ) );
}
if( depth < STATS_NETWORK_NODE_MAXDEPTH )
- return stat_increase_network_count( &(*node)->children[ foo ], depth+1, ip );
+ return stat_increase_network_count( &(*node)->children[ foo ], depth+STATS_NETWORK_NODE_BITWIDTH, ip );
(*node)->counters[ foo ]++;
return 0;
int i, rest = 0;
if( !*node ) return 0;
- if( ++depth == STATS_NETWORK_NODE_MAXDEPTH )
- for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) {
+ depth += STATS_NETWORK_NODE_BITWIDTH;
+ if( depth == STATS_NETWORK_NODE_MAXDEPTH ) {
+ for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i )
rest += ((*node)->counters[i]>>=shift);
- return rest;
- }
+ return rest;
+ }
for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) {
stats_network_node **childnode = &(*node)->children[i];
return rest;
}
-static void stats_get_highscore_networks( stats_network_node *node, int depth, ot_ip6 node_value, int *scores, ot_ip6 *networks, int network_count ) {
- uint8_t *_node_value = (uint8_t*)node_value;
+static size_t stats_get_highscore_networks( stats_network_node *node, int depth, ot_ip6 node_value, size_t *scores, ot_ip6 *networks, int network_count, int limit ) {
+ size_t score = 0;
int i;
- if( !node ) return;
+ if( !node ) return 0;
- if( depth < STATS_NETWORK_NODE_MAXDEPTH ) {
+ if( depth < limit ) {
for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i )
- if( node->children[i] ) {
- _node_value[depth] = i;
- stats_get_highscore_networks( node->children[i], depth+1, node_value, scores, networks, network_count );
- }
- } else
- for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) {
- int j=1;
- if( node->counters[i] <= scores[0] ) continue;
-
- _node_value[depth] = i;
- while( (j<network_count) && (node->counters[i]>scores[j] ) ) ++j;
- --j;
-
- memcpy( scores, scores + 1, j * sizeof( *scores ) );
- memcpy( networks, networks + 1, j * sizeof( *networks ) );
- scores[ j ] = node->counters[ i ];
- memcpy( networks + j, _node_value, sizeof( *networks ) );
+ if( node->children[i] ) {
+ __STR(node_value,depth,i);
+ score += stats_get_highscore_networks( node->children[i], depth+STATS_NETWORK_NODE_BITWIDTH, node_value, scores, networks, network_count, limit );
}
+ return score;
+ }
+
+ if( depth > limit && depth < STATS_NETWORK_NODE_MAXDEPTH ) {
+ for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i )
+ if( node->children[i] )
+ score += stats_get_highscore_networks( node->children[i], depth+STATS_NETWORK_NODE_BITWIDTH, node_value, scores, networks, network_count, limit );
+ return score;
+ }
+
+ if( depth > limit && depth == STATS_NETWORK_NODE_MAXDEPTH ) {
+ for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i )
+ score += node->counters[i];
+ return score;
+ }
+
+ /* if( depth == limit ) */
+ for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) {
+ int j=1;
+ size_t node_score;
+
+ if( depth == STATS_NETWORK_NODE_MAXDEPTH )
+ node_score = node->counters[i];
+ else
+ node_score = stats_get_highscore_networks( node->children[i], depth+STATS_NETWORK_NODE_BITWIDTH, node_value, scores, networks, network_count, limit );
+
+ score += node_score;
+
+ if( node_score <= scores[0] ) continue;
+
+ __STR(node_value,depth,i);
+ while( j < network_count && node_score > scores[j] ) ++j;
+ --j;
+
+ memcpy( scores, scores + 1, j * sizeof( *scores ) );
+ memcpy( networks, networks + 1, j * sizeof( *networks ) );
+ scores[ j ] = node_score;
+ memcpy( networks + j, node_value, sizeof( *networks ) );
+ }
+
+ return score;
}
-static size_t stats_return_busy_networks( char * reply ) {
- ot_ip6 networks[256];
+static size_t stats_return_busy_networks( char * reply, stats_network_node *tree, int amount ) {
+ ot_ip6 networks[amount];
ot_ip6 node_value;
- int scores[256];
+ size_t scores[amount];
int i;
char * r = reply;
- memset( scores, 0, sizeof( *scores ) * 256 );
- memset( networks, 0, sizeof( *networks ) * 256 );
+ memset( scores, 0, sizeof( scores ) );
+ memset( networks, 0, sizeof( networks ) );
+ memset( node_value, 0, sizeof( node_value ) );
- stats_get_highscore_networks( stats_network_counters_root, 0, node_value, scores, networks, 256 );
+ stats_get_highscore_networks( tree, 0, node_value, scores, networks, amount, STATS_NETWORK_NODE_MAXDEPTH );
- for( i=255; i>=0; --i) {
- r += sprintf( r, "%08i: ", scores[i] );
- r += fmt_ip6c( r, networks[i] );
- *r++ = '\n';
+ r += sprintf( r, "Networks, limit /%d:\n", STATS_NETWORK_NODE_MAXDEPTH+STATS_NETWORK_NODE_BITWIDTH );
+ for( i=amount-1; i>=0; --i) {
+ if( scores[i] ) {
+ r += sprintf( r, "%08zd: ", scores[i] );
+#ifdef WANT_V6
+ r += fmt_ip6c( r, networks[i] );
+#else
+ r += fmt_ip4( r, networks[i]);
+#endif
+ *r++ = '\n';
+ }
}
+ memset( scores, 0, sizeof( scores ) );
+ memset( networks, 0, sizeof( networks ) );
+ memset( node_value, 0, sizeof( node_value ) );
+
+ stats_get_highscore_networks( tree, 0, node_value, scores, networks, amount, STATS_NETWORK_NODE_LIMIT );
+
+ r += sprintf( r, "\nNetworks, limit /%d:\n", STATS_NETWORK_NODE_LIMIT+STATS_NETWORK_NODE_BITWIDTH );
+ for( i=amount-1; i>=0; --i) {
+ if( scores[i] ) {
+ r += sprintf( r, "%08zd: ", scores[i] );
+#ifdef WANT_V6
+ r += fmt_ip6c( r, networks[i] );
+#else
+ r += fmt_ip4( r, networks[i] );
+#endif
+ *r++ = '\n';
+ }
+ }
+
return r - reply;
}
-#endif
+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;
+
+ 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_vector *bucket_list = &peer_list->peers;
+ int num_buckets = 1;
+
+ if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
+ num_buckets = bucket_list->size;
+ bucket_list = (ot_vector *)bucket_list->data;
+ }
+
+ 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++) ) )
+ goto bailout_unlock;
+ ++bucket_list;
+ }
+ }
+ mutex_bucket_unlock( bucket, 0 );
+ if( !g_opentracker_running )
+ goto bailout_error;
+ }
+
+ /* The tree is built. Now analyze */
+ r += stats_return_busy_networks( r, slash24s_network_counters_root, amount );
+ goto success;
+
+bailout_unlock:
+ mutex_bucket_unlock( bucket, 0 );
+bailout_error:
+ r = reply;
+success:
+ stats_shift_down_network_count( &slash24s_network_counters_root, 0, STATS_NETWORK_NODE_MAXDEPTH*STATS_NETWORK_NODE_BITWIDTH );
+ if( slash24s_network_counters_root )
+ free( slash24s_network_counters_root );
+ return r-reply;
+}
typedef struct {
unsigned long long torrent_count;
return r - reply;
}
-/* This function collects 4096 /24s in 4096 possible
- malloc blocks
- */
-static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh ) {
-
-#define NUM_TOPBITS 12
-#define NUM_LOWBITS (24-NUM_TOPBITS)
-#define NUM_BUFS (1<<NUM_TOPBITS)
-#define NUM_S24S (1<<NUM_LOWBITS)
-#define MSK_S24S (NUM_S24S-1)
-
- uint32_t *counts[ NUM_BUFS ];
- uint32_t slash24s[amount*2]; /* first dword amount, second dword subnet */
- size_t i, j, k, l;
- char *r = reply;
-
- byte_zero( counts, sizeof( counts ) );
- byte_zero( slash24s, amount * 2 * sizeof(uint32_t) );
-
- r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh );
-
-#if 0
- /* XXX: TOOD: Doesn't work yet with new peer storage model */
- for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
- ot_vector *torrents_list = mutex_bucket_lock( bucket );
- for( j=0; j<torrents_list->size; ++j ) {
- ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
- for( k=0; k<OT_POOLS_COUNT; ++k ) {
- ot_peer *peers = peer_list->peers[k].data;
- size_t numpeers = peer_list->peers[k].size;
- for( l=0; l<numpeers; ++l ) {
- uint32_t s24 = ntohl(*(uint32_t*)(peers+l)) >> 8;
- uint32_t *count = counts[ s24 >> NUM_LOWBITS ];
- if( !count ) {
- count = malloc( sizeof(uint32_t) * NUM_S24S );
- if( !count ) {
- mutex_bucket_unlock( bucket, 0 );
- goto bailout_cleanup;
- }
- byte_zero( count, sizeof( uint32_t ) * NUM_S24S );
- counts[ s24 >> NUM_LOWBITS ] = count;
- }
- count[ s24 & MSK_S24S ]++;
- }
- }
- }
- mutex_bucket_unlock( bucket, 0 );
- if( !g_opentracker_running )
- goto bailout_cleanup;
- }
-#endif
-
- k = l = 0; /* Debug: count allocated bufs */
- for( i=0; i < NUM_BUFS; ++i ) {
- uint32_t *count = counts[i];
- if( !counts[i] )
- continue;
- ++k; /* Debug: count allocated bufs */
- for( j=0; j < NUM_S24S; ++j ) {
- if( count[j] > thresh ) {
- /* This subnet seems to announce more torrents than the last in our list */
- int insert_pos = amount - 1;
- while( ( insert_pos >= 0 ) && ( count[j] > slash24s[ 2 * insert_pos ] ) )
- --insert_pos;
- ++insert_pos;
- memcpy( slash24s + 2 * ( insert_pos + 1 ), slash24s + 2 * ( insert_pos ), 2 * sizeof( uint32_t ) * ( amount - insert_pos - 1 ) );
- slash24s[ 2 * insert_pos ] = count[j];
- slash24s[ 2 * insert_pos + 1 ] = ( i << NUM_TOPBITS ) + j;
- if( slash24s[ 2 * amount - 2 ] > thresh )
- thresh = slash24s[ 2 * amount - 2 ];
- }
- if( count[j] ) ++l;
- }
- free( count );
- }
-
- r += sprintf( r, "Allocated bufs: %zd, used s24s: %zd\n", k, l );
-
- for( i=0; i < amount; ++i )
- if( slash24s[ 2*i ] >= thresh ) {
- uint32_t ip = slash24s[ 2*i +1 ];
- r += sprintf( r, "% 10ld %d.%d.%d.0/24\n", (long)slash24s[ 2*i ], (int)(ip >> 16), (int)(255 & ( ip >> 8 )), (int)(ip & 255) );
- }
-
- return r - reply;
-
- for( i=0; i < NUM_BUFS; ++i )
- free( counts[i] );
-
- return 0;
-}
-
static unsigned long events_per_time( unsigned long long events, time_t t ) {
return events / ( (unsigned int)t ? (unsigned int)t : 1 );
}
return stats_return_renew_bucket( reply );
case TASK_STATS_SYNCS:
return stats_return_sync_mrtg( reply );
-#ifdef WANT_LOG_NETWORKS
- case TASK_STATS_BUSY_NETWORKS:
- return stats_return_busy_networks( reply );
-#endif
default:
return 0;
}
switch( mode & TASK_TASK_MASK ) {
case TASK_STATS_TORRENTS: r += stats_torrents_mrtg( r ); break;
case TASK_STATS_PEERS: r += stats_peers_mrtg( r ); break;
- case TASK_STATS_SLASH24S: r += stats_slash24s_txt( r, 25, 16 ); break;
+ case TASK_STATS_SLASH24S: r += stats_slash24s_txt( r, 128 ); break;
case TASK_STATS_TOP10: r += stats_top10_txt( r ); break;
case TASK_STATS_EVERYTHING: r += stats_return_everything( r ); break;
default: