From ad541c67761b8aa6da1566802c347cac4018d0c2 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Mon, 2 Nov 2026 20:50:24 +0100 Subject: Move the build sources into src/ --- ot_stats.c | 866 ------------------------------------------------------------- 1 file changed, 866 deletions(-) delete mode 100644 ot_stats.c (limited to 'ot_stats.c') diff --git a/ot_stats.c b/ot_stats.c deleted file mode 100644 index 2d6335b..0000000 --- a/ot_stats.c +++ /dev/null @@ -1,866 +0,0 @@ -/* This software was written by Dirk Engling - It is considered beerware. Prost. Skol. Cheers or whatever. */ - -/* System */ -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef WANT_SYSLOGS -#include -#endif - -/* Opentracker */ -#include "ot_accesslist.h" -#include "ot_event.h" -#include "ot_hex.h" -#include "ot_iovec.h" -#include "ot_ip.h" -#include "ot_mutex.h" -#include "ot_workqueue.h" -#include "ot_fmt.h" -#include "ot_stats.h" -#include "trackerlogic.h" - -#ifndef NO_FULLSCRAPE_LOGGING -#define LOG_TO_STDERR(...) fprintf(stderr, __VA_ARGS__) -#else -#define LOG_TO_STDERR(...) -#endif - -/* Forward declaration */ -static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode); -#define OT_STATS_TMPSIZE 8192 - -/* Each serving thread keeps its own statistics tally. The list is linked - through intrusive next pointers within the workstruct. - - Registration happens once per thread and the adding up once per statistics - request, so this lock is never on anybody's hot path. */ -static struct ot_workstruct *g_counter_contexts; -static ot_counter g_retired[OT_COUNTER_COUNT]; -static pthread_mutex_t g_counter_mutex = PTHREAD_MUTEX_INITIALIZER; - -void stats_counters_register(struct ot_workstruct *ws) { - pthread_mutex_lock(&g_counter_mutex); - ws->counters_next = g_counter_contexts; - g_counter_contexts = ws; - pthread_mutex_unlock(&g_counter_mutex); -} - -void stats_counters_retire(struct ot_workstruct *ws) { - struct ot_workstruct **link; - size_t i; - - pthread_mutex_lock(&g_counter_mutex); - for (link = &g_counter_contexts; *link; link = &(*link)->counters_next) - if (*link == ws) { - *link = ws->counters_next; - break; - } - - /* When retiring a worker thread, collect the counter tally in the global */ - for (i = 0; i < OT_COUNTER_COUNT; ++i) - atomic_fetch_add_explicit(g_retired + i, atomic_load_explicit(ws->counters + i, memory_order_relaxed), memory_order_relaxed); - pthread_mutex_unlock(&g_counter_mutex); -} - -/* What every thread has counted so far, added together */ -static void counters_total(unsigned long long *total) { - struct ot_workstruct *ws; - size_t i; - - pthread_mutex_lock(&g_counter_mutex); - for (i = 0; i < OT_COUNTER_COUNT; ++i) - total[i] = atomic_load_explicit(g_retired + i, memory_order_relaxed); - for (ws = g_counter_contexts; ws; ws = ws->counters_next) - for (i = 0; i < OT_COUNTER_COUNT; ++i) - total[i] += atomic_load_explicit(ws->counters + i, memory_order_relaxed); - pthread_mutex_unlock(&g_counter_mutex); -} - -#define COUNT(index, by) atomic_fetch_add_explicit(ws->counters + (index), (unsigned long long)(by), memory_order_relaxed) - -static const char *ot_failed_request_names[] = { - "302 Redirect", "400 Parse Error", "400 Invalid Parameter", "400 Invalid Parameter (compact=0)", "400 Not Modest", - "402 Payment Required", "403 Access Denied", "404 Not found", "500 Internal Server Error"}; - -static time_t ot_start_time; - -#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))) - -#if 0 -// XXX -#define STATS_NETWORK_NODE_MAXDEPTH (68 - STATS_NETWORK_NODE_BITWIDTH) -#define STATS_NETWORK_NODE_LIMIT (48 - STATS_NETWORK_NODE_BITWIDTH) -#endif -#define STATS_NETWORK_NODE_MAXDEPTH (28 - STATS_NETWORK_NODE_BITWIDTH) -#define STATS_NETWORK_NODE_LIMIT (24 - STATS_NETWORK_NODE_BITWIDTH) - -typedef union stats_network_node stats_network_node; -union stats_network_node { - size_t counters[STATS_NETWORK_NODE_COUNT]; - stats_network_node *children[STATS_NETWORK_NODE_COUNT]; -}; - -static int stat_increase_network_count(stats_network_node **pnode, int depth, uintptr_t ip) { - int foo = __LDR(ip, depth); - stats_network_node *node; - - if (!*pnode) { - *pnode = malloc(sizeof(stats_network_node)); - if (!*pnode) - return -1; - memset(*pnode, 0, sizeof(stats_network_node)); - } - node = *pnode; - - if (depth < STATS_NETWORK_NODE_MAXDEPTH) - return stat_increase_network_count(node->children + foo, depth + STATS_NETWORK_NODE_BITWIDTH, ip); - - node->counters[foo]++; - return 0; -} - -static int stats_shift_down_network_count(stats_network_node **node, int depth, int shift) { - size_t i, rest = 0; - - if (!*node) - return 0; - - for (i = 0; i < STATS_NETWORK_NODE_COUNT; ++i) - if (depth < STATS_NETWORK_NODE_MAXDEPTH) - rest += stats_shift_down_network_count((*node)->children + i, depth + STATS_NETWORK_NODE_BITWIDTH, shift); - else - rest += (*node)->counters[i] >>= shift; - - if (!rest) { - free(*node); - *node = NULL; - } - - return rest; -} - -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 i, score = 0; - - if (!node) - return 0; - - if (depth < limit) { - for (i = 0; i < STATS_NETWORK_NODE_COUNT; ++i) - 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; - - memmove(scores, scores + 1, j * sizeof(*scores)); - memmove(networks, networks + 1, j * sizeof(*networks)); - scores[j] = node_score; - memcpy(networks + j, node_value, sizeof(*networks)); - } - - return score; -} - -static void stats_return_busy_networks(char **reply, const char *reply_end, stats_network_node *tree, size_t amount, int limit) { - ot_ip6 networks[amount]; - ot_ip6 node_value; - size_t scores[amount]; - size_t i; - - 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, limit); - - fmt_append(reply, reply_end, "Networks, limit /%d:\n", limit + STATS_NETWORK_NODE_BITWIDTH); - for (i = amount; i > 0; --i) { - if (scores[i - 1]) { - char ip_readable[64]; - - ip_readable[ip_format(ip_readable, networks[i - 1])] = 0; - fmt_append(reply, reply_end, "%08zd: %s\n", scores[i - 1], ip_readable); - } - } - fmt_append(reply, reply_end, "\n"); -} - -static void stats_slash24s_txt(char **reply, const char *reply_end, size_t amount) { - stats_network_node *slash24s_network_counters_root = NULL; - size_t i, bucket, 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_list4; - 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; - peers += peer_size; - } - ++bucket_list; - } - } - mutex_bucket_unlock(bucket, 0); - if (!g_opentracker_running) - goto done; - } - - /* The tree is built. Now analyze */ - stats_return_busy_networks(reply, reply_end, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_MAXDEPTH); - stats_return_busy_networks(reply, reply_end, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_LIMIT); - goto done; - -bailout_unlock: - mutex_bucket_unlock(bucket, 0); -done: - stats_shift_down_network_count(&slash24s_network_counters_root, 0, sizeof(int) * 8 - 1); -} - -#ifdef WANT_SPOT_WOODPECKER -static stats_network_node *stats_woodpeckers_tree; -static pthread_mutex_t g_woodpeckers_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void stats_return_woodpeckers(char **reply, const char *reply_end, int amount) { - pthread_mutex_lock(&g_woodpeckers_mutex); - stats_return_busy_networks(reply, reply_end, stats_woodpeckers_tree, amount, STATS_NETWORK_NODE_MAXDEPTH); - pthread_mutex_unlock(&g_woodpeckers_mutex); -} -#endif - -typedef struct { - unsigned long long torrent_count; - unsigned long long peer_count; - unsigned long long seed_count; -} torrent_stats; - -static int torrent_statter(ot_torrent *torrent, uintptr_t data) { - torrent_stats *stats = (torrent_stats *)data; - stats->torrent_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; -} - -/* Converter function from memory to human readable hex strings */ -typedef struct { - size_t val; - ot_hash hash; -} ot_record; - -static inline void stats_insert_into_highscore(size_t val, ot_record* list, size_t amount, ot_hash* hash) { - size_t i; - for (i = 0; (i < amount) && (list[i].val > val); ++i) - {} - /* if we score better than a record in the list, we need to make room in the high - score array by moving lower scoring entries up */ - if (i < amount) { - memmove(list + i + 1, list + i, (amount - i - 1) * sizeof(ot_record)); - - memcpy(&list[i].hash, hash, sizeof(ot_hash)); - list[i].val = val; - } -} - - -/* Fetches stats from tracker */ -void stats_top_txt(char **reply, const char *reply_end, size_t amount) { - size_t j, idx, bucket; - ot_record top100s[100], top100c[100], top100l[100]; - char hex_out[42]; - - if (amount > 100) - amount = 100; - - memset(top100s, 0, sizeof(top100s)); - memset(top100c, 0, sizeof(top100c)); - memset(top100l, 0, sizeof(top100l)); - - /* Iterate over complete torrent list */ - 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_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; - size_t leech_count = peer_count - seed_count; - - stats_insert_into_highscore(peer_count, top100c, amount, &torrent->hash); - stats_insert_into_highscore(seed_count, top100s, amount, &torrent->hash); - stats_insert_into_highscore(leech_count, top100l, amount, &torrent->hash); - } - mutex_bucket_unlock(bucket, 0); - if (!g_opentracker_running) - return; - } - - fmt_append(reply, reply_end, "Top %zd torrents by peers:\n", amount); - for (idx = 0; idx < amount; ++idx) - if (top100c[idx].val) - fmt_append(reply, reply_end, "\t%zd\t%s\n", top100c[idx].val, hex_from_hash(hex_out, top100c[idx].hash)); - fmt_append(reply, reply_end, "Top %zd torrents by seeds:\n", amount); - for (idx = 0; idx < amount; ++idx) - if (top100s[idx].val) - fmt_append(reply, reply_end, "\t%zd\t%s\n", top100s[idx].val, hex_from_hash(hex_out, top100s[idx].hash)); - fmt_append(reply, reply_end, "Top %zd torrents by leechers:\n", amount); - for (idx = 0; idx < amount; ++idx) - if (top100l[idx].val) - fmt_append(reply, reply_end, "\t%zd\t%s\n", top100l[idx].val, hex_from_hash(hex_out, top100l[idx].hash)); -} - -static unsigned long events_per_time(unsigned long long events, time_t t) { return events / ((unsigned int)t ? (unsigned int)t : 1); } - -static void stats_connections_mrtg(char **reply, const char *reply_end) { - ot_time t = time(NULL) - ot_start_time; - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", - total[OT_COUNTER_TCP_CONNECTIONS] + total[OT_COUNTER_UDP_CONNECTIONS], - total[OT_COUNTER_TCP_ANNOUNCES] + total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], (int)t, (int)(t / 3600), - events_per_time(total[OT_COUNTER_TCP_CONNECTIONS] + total[OT_COUNTER_UDP_CONNECTIONS], t), - events_per_time(total[OT_COUNTER_TCP_ANNOUNCES] + total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], t)); -} - -static void stats_udpconnections_mrtg(char **reply, const char *reply_end) { - ot_time t = time(NULL) - ot_start_time; - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats, %lu conns/s :: %lu success/s.", total[OT_COUNTER_UDP_CONNECTIONS], - total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], (int)t, (int)(t / 3600), - events_per_time(total[OT_COUNTER_UDP_CONNECTIONS], t), - events_per_time(total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], t)); -} - -static void stats_tcpconnections_mrtg(char **reply, const char *reply_end) { - time_t t = time(NULL) - ot_start_time; - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats, %lu conns/s :: %lu success/s.", total[OT_COUNTER_TCP_CONNECTIONS], - total[OT_COUNTER_TCP_ANNOUNCES], (int)t, (int)(t / 3600), events_per_time(total[OT_COUNTER_TCP_CONNECTIONS], t), - events_per_time(total[OT_COUNTER_TCP_ANNOUNCES], t)); -} - -static void stats_scrape_mrtg(char **reply, const char *reply_end) { - time_t t = time(NULL) - ot_start_time; - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker scrape stats, %lu scrape/s (tcp and udp)", - total[OT_COUNTER_TCP_SCRAPES], total[OT_COUNTER_UDP_SCRAPES], (int)t, (int)(t / 3600), - events_per_time((total[OT_COUNTER_TCP_SCRAPES] + total[OT_COUNTER_UDP_SCRAPES]), t)); -} - -static void stats_fullscrapes_mrtg(char **reply, const char *reply_end) { - ot_time t = time(NULL) - ot_start_time; - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker full scrape stats, %lu conns/s :: %lu bytes/s.", - total[OT_COUNTER_FULLSCRAPES] * 1000, total[OT_COUNTER_FULLSCRAPE_BYTES], (int)t, (int)(t / 3600), - events_per_time(total[OT_COUNTER_FULLSCRAPES], t), - events_per_time(total[OT_COUNTER_FULLSCRAPE_BYTES], t)); -} - -static void stats_peers_mrtg(char **reply, const char *reply_end) { - torrent_stats stats = {0, 0, 0}; - - iterate_all_torrents(torrent_statter, (uintptr_t)&stats); - - fmt_append(reply, reply_end, "%llu\n%llu\nopentracker serving %llu torrents\nopentracker", stats.peer_count, stats.seed_count, - stats.torrent_count); -} - -static void stats_torrents_mrtg(char **reply, const char *reply_end) { - size_t torrent_count = mutex_get_torrent_count(); - - fmt_append(reply, reply_end, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", torrent_count, (size_t)0, torrent_count); -} - -static void stats_httperrors_txt(char **reply, const char *reply_end) { - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - fmt_append(reply, reply_end, "302 RED %llu\n400 ... %llu\n400 PAR %llu\n400 COM %llu\n403 IP %llu\n404 INV %llu\n500 SRV %llu\n", - total[OT_COUNTER_FAILED + 0], total[OT_COUNTER_FAILED + 1], total[OT_COUNTER_FAILED + 2], total[OT_COUNTER_FAILED + 3], - total[OT_COUNTER_FAILED + 4], total[OT_COUNTER_FAILED + 5], total[OT_COUNTER_FAILED + 6]); -} - -static void stats_return_renew_bucket(char **reply, const char *reply_end) { - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - int i; - - for (i = 0; i < OT_PEER_TIMEOUT; ++i) - fmt_append(reply, reply_end, "%02i %llu\n", i, total[OT_COUNTER_RENEWED + i]); -} - -static void stats_return_sync_mrtg(char **reply, const char *reply_end) { - ot_time t = time(NULL) - ot_start_time; - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", total[OT_COUNTER_SYNCS], 0LL, - (int)t, (int)(t / 3600), events_per_time(total[OT_COUNTER_TCP_CONNECTIONS] + total[OT_COUNTER_UDP_CONNECTIONS], t), - events_per_time(total[OT_COUNTER_TCP_ANNOUNCES] + total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], t)); -} - -static void stats_return_completed_mrtg(char **reply, const char *reply_end) { - ot_time t = time(NULL) - ot_start_time; - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - - fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker, %lu completed/h.", total[OT_COUNTER_COMPLETED], 0LL, (int)t, (int)(t / 3600), - events_per_time(total[OT_COUNTER_COMPLETED], t / 3600)); -} - -#ifdef WANT_LOG_NUMWANT -extern unsigned long long numwants[201]; -static void stats_return_numwants(char **reply, const char *reply_end) { - int i; - for (i = 0; i <= 200; ++i) - fmt_append(reply, reply_end, "%03d => %lld\n", i, numwants[i]); -} -#endif - -static void stats_return_everything(char **reply, const char *reply_end) { - unsigned long long total[OT_COUNTER_COUNT]; - - counters_total(total); - - torrent_stats stats = {0, 0, 0}; - int i; - - iterate_all_torrents(torrent_statter, (uintptr_t)&stats); - - fmt_append(reply, reply_end, "\n"); - fmt_append(reply, reply_end, "\n"); - fmt_append(reply, reply_end, " %llu\n", (unsigned long long)(time(NULL) - ot_start_time)); - fmt_append(reply, reply_end, " \n"); - fmt_append(reply, reply_end, " %zd\n", mutex_get_torrent_count()); - fmt_append(reply, reply_end, " %llu\n", stats.torrent_count); - fmt_append(reply, reply_end, " \n"); - fmt_append(reply, reply_end, " \n %llu\n \n", stats.peer_count); - fmt_append(reply, reply_end, " \n %llu\n \n", stats.seed_count); - fmt_append(reply, reply_end, " \n %llu\n \n", total[OT_COUNTER_COMPLETED]); - fmt_append(reply, reply_end, " \n"); - fmt_append(reply, reply_end, " \n %llu\n %llu\n %llu\n \n", - total[OT_COUNTER_TCP_CONNECTIONS], total[OT_COUNTER_TCP_ANNOUNCES], total[OT_COUNTER_TCP_SCRAPES]); - fmt_append(reply, reply_end, " \n %llu\n %llu\n %llu\n %llu\n %llu\n \n", - total[OT_COUNTER_UDP_CONNECTIONS], total[OT_COUNTER_UDP_CONNECTS], total[OT_COUNTER_UDP_ANNOUNCES], total[OT_COUNTER_UDP_SCRAPES], - total[OT_COUNTER_UDP_CONNID_MISSMATCH]); - fmt_append(reply, reply_end, " \n %llu\n \n", total[OT_COUNTER_SYNCS]); - fmt_append(reply, reply_end, " \n"); - fmt_append(reply, reply_end, " \n"); - fmt_append(reply, reply_end, " \n"); - for (i = 0; i < OT_PEER_TIMEOUT; ++i) - fmt_append(reply, reply_end, " %llu\n", i, total[OT_COUNTER_RENEWED + i]); - fmt_append(reply, reply_end, " \n"); - fmt_append(reply, reply_end, " \n"); - for (i = 0; i < CODE_HTTPERROR_COUNT; ++i) - fmt_append(reply, reply_end, " %llu\n", ot_failed_request_names[i], total[OT_COUNTER_FAILED + i]); - fmt_append(reply, reply_end, " \n"); - fmt_append(reply, reply_end, " \n %llu\n \n", total[OT_COUNTER_STALLS]); - fmt_append(reply, reply_end, " \n"); - fmt_append(reply, reply_end, ""); -} - -/* The names as the Makefile spells them, so that what a binary reports maps - straight back onto the FEATURES lines it was built from */ -static const char *const build_features[] = { -#ifdef WANT_V4_ONLY - "WANT_V4_ONLY", -#endif -#ifdef WANT_ACCESSLIST_BLACK - "WANT_ACCESSLIST_BLACK", -#endif -#ifdef WANT_ACCESSLIST_WHITE - "WANT_ACCESSLIST_WHITE", -#endif -#ifdef WANT_DYNAMIC_ACCESSLIST - "WANT_DYNAMIC_ACCESSLIST", -#endif -#ifdef WANT_SYNC_LIVE - "WANT_SYNC_LIVE", -#endif -#ifdef WANT_IP_FROM_QUERY_STRING - "WANT_IP_FROM_QUERY_STRING", -#endif -#ifdef WANT_IP_FROM_PROXY - "WANT_IP_FROM_PROXY", -#endif -#ifdef WANT_COMPRESSION_GZIP - "WANT_COMPRESSION_GZIP", -#endif -#ifdef WANT_COMPRESSION_GZIP_ALWAYS - "WANT_COMPRESSION_GZIP_ALWAYS", -#endif -#ifdef WANT_COMPRESSION_ZSTD - "WANT_COMPRESSION_ZSTD", -#endif -#ifdef WANT_COMPRESSION_ZSTD_ALWAYS - "WANT_COMPRESSION_ZSTD_ALWAYS", -#endif -#ifdef WANT_FULLSCRAPE - "WANT_FULLSCRAPE", -#endif -#ifdef WANT_MODEST_FULLSCRAPES - "WANT_MODEST_FULLSCRAPES", -#endif -#ifdef WANT_KEEPALIVE - "WANT_KEEPALIVE", -#endif -#ifdef WANT_RESTRICT_STATS - "WANT_RESTRICT_STATS", -#endif -#ifdef WANT_LOG_NUMWANT - "WANT_LOG_NUMWANT", -#endif -#ifdef WANT_SPOT_WOODPECKER - "WANT_SPOT_WOODPECKER", -#endif -#ifdef WANT_SYSLOGS - "WANT_SYSLOGS", -#endif -#ifdef WANT_DEV_RANDOM - "WANT_DEV_RANDOM", -#endif -#ifdef WANT_INSECURE_RANDOM_FALLBACK - "WANT_INSECURE_RANDOM_FALLBACK", -#endif -#ifdef _DEBUG - "_DEBUG", -#endif -#ifdef _DEBUG_HTTPERROR - "_DEBUG_HTTPERROR", -#endif -#ifdef _DEBUG_RANDOMTORRENTS - "_DEBUG_RANDOMTORRENTS", -#endif - NULL}; - -void stats_return_tracker_features(char **reply, const char *reply_end) { - size_t i; - - fmt_append(reply, reply_end, "events: %s\n", event_mechanism()); - fmt_append(reply, reply_end, "features:"); - for (i = 0; build_features[i]; ++i) - fmt_append(reply, reply_end, " %s", build_features[i]); - if (!build_features[0]) - fmt_append(reply, reply_end, " none"); - fmt_append(reply, reply_end, "\n"); -} - -void stats_return_tracker_version(char **reply, const char *reply_end) { - fmt_append(reply, reply_end, "opentracker %s", OT_VERSION); - if (*GIT_VERSION && strcmp(GIT_VERSION, OT_TAG)) - fmt_append(reply, reply_end, " (%s)", GIT_VERSION); - fmt_append(reply, reply_end, "\n"); - if (*OT_TAG) - fmt_append(reply, reply_end, "https://erdgeist.org/gitweb/opentracker/tag/?h=%s\n", OT_TAG); -} - -void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format) { - (void)format; - switch (mode & TASK_TASK_MASK) { - case TASK_STATS_CONNS: - stats_connections_mrtg(reply, reply_end); - break; - case TASK_STATS_SCRAPE: - stats_scrape_mrtg(reply, reply_end); - break; - case TASK_STATS_UDP: - stats_udpconnections_mrtg(reply, reply_end); - break; - case TASK_STATS_TCP: - stats_tcpconnections_mrtg(reply, reply_end); - break; - case TASK_STATS_FULLSCRAPE: - stats_fullscrapes_mrtg(reply, reply_end); - break; - case TASK_STATS_COMPLETED: - stats_return_completed_mrtg(reply, reply_end); - break; - case TASK_STATS_HTTPERRORS: - stats_httperrors_txt(reply, reply_end); - break; - case TASK_STATS_RENEW: - stats_return_renew_bucket(reply, reply_end); - break; - case TASK_STATS_SYNCS: - stats_return_sync_mrtg(reply, reply_end); - break; -#ifdef WANT_LOG_NUMWANT - case TASK_STATS_NUMWANTS: - stats_return_numwants(reply, reply_end); - break; -#endif - default: - break; - } -} - -static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode) { - char *r; - const char *r_end; - - *iovec_entries = 0; - *iovector = NULL; - if (!(r = iovec_new_chunk(iovec_entries, iovector, OT_STATS_TMPSIZE))) - return; - r_end = r + OT_STATS_TMPSIZE; - - switch (mode & TASK_TASK_MASK) { - case TASK_STATS_TORRENTS: - stats_torrents_mrtg(&r, r_end); - break; - case TASK_STATS_PEERS: - stats_peers_mrtg(&r, r_end); - break; - case TASK_STATS_SLASH24S: - stats_slash24s_txt(&r, r_end, 128); - break; - case TASK_STATS_TOP10: - stats_top_txt(&r, r_end, 10); - break; - case TASK_STATS_TOP100: - r = iovec_next_chunk(iovec_entries, iovector, r, 4 * OT_STATS_TMPSIZE); - if (!r) - return; - r_end = r + 4 * OT_STATS_TMPSIZE; - stats_top_txt(&r, r_end, 100); - break; - case TASK_STATS_EVERYTHING: - r = iovec_next_chunk(iovec_entries, iovector, r, OT_STATS_TMPSIZE + 64 * OT_PEER_TIMEOUT); - if (!r) - return; - r_end = r + OT_STATS_TMPSIZE + 64 * OT_PEER_TIMEOUT; - stats_return_everything(&r, r_end); - break; -#ifdef WANT_SPOT_WOODPECKER - case TASK_STATS_WOODPECKERS: - stats_return_woodpeckers(&r, r_end, 128); - break; -#endif - default: - iovec_free(iovec_entries, iovector); - return; - } - iovec_trim_last(iovec_entries, iovector, r); -} - -void stats_issue_event(struct ot_workstruct *ws, ot_status_event event, PROTO_FLAG proto, uintptr_t event_data) { - if (!ws) - return; - - switch (event) { - case EVENT_ACCEPT: - if (proto == FLAG_TCP) - COUNT(OT_COUNTER_TCP_CONNECTIONS, 1); - else - COUNT(OT_COUNTER_UDP_CONNECTIONS, 1); - break; - case EVENT_ANNOUNCE: - if (proto == FLAG_TCP) - COUNT(OT_COUNTER_TCP_ANNOUNCES, 1); - else - COUNT(OT_COUNTER_UDP_ANNOUNCES, 1); - break; - case EVENT_CONNECT: - if (proto == FLAG_TCP) - COUNT(OT_COUNTER_TCP_CONNECTS, 1); - else - COUNT(OT_COUNTER_UDP_CONNECTS, 1); - break; - case EVENT_COMPLETED: -#ifdef WANT_SYSLOGS - { - char timestring[64]; - char hash_hex[42], peerid_hex[42], ip_readable[64]; - struct tm time_now; - time_t ttt; - - time(&ttt); - localtime_r(&ttt, &time_now); - strftime(timestring, sizeof(timestring), "%FT%T%z", &time_now); - - hex_from_hash(hash_hex, *ws->hash); - if (ws->peer_id) - hex_from_hash(peerid_hex, (uint8_t *)ws->peer_id); - else { - *peerid_hex = 0; - } - - ip_readable[ip_format(ip_readable, (char *)&ws->peer)] = 0; - syslog(LOG_INFO, "time=%s event=completed info_hash=%s peer_id=%s ip=%s", timestring, hash_hex, peerid_hex, ip_readable); - } -#endif - COUNT(OT_COUNTER_COMPLETED, 1); - break; - case EVENT_SCRAPE: - if (proto == FLAG_TCP) - COUNT(OT_COUNTER_TCP_SCRAPES, 1); - else - COUNT(OT_COUNTER_UDP_SCRAPES, 1); - break; - case EVENT_FULLSCRAPE: - COUNT(OT_COUNTER_FULLSCRAPES, 1); - COUNT(OT_COUNTER_FULLSCRAPE_BYTES, event_data); - break; - case EVENT_FULLSCRAPE_REQUEST: { - ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */ - char _debug[512]; - int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(time_now_seconds() - ot_start_time) / 60); - off += ip_format(_debug + off, *ip); - off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n"); - (void)write(2, _debug, off); - COUNT(OT_COUNTER_FULLSCRAPE_REQUESTS, 1); - } break; - case EVENT_FULLSCRAPE_REQUEST_GZIP: { - ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */ - char _debug[512]; - int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(time_now_seconds() - ot_start_time) / 60); - off += ip_format(_debug + off, *ip); - off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n"); - (void)write(2, _debug, off); - COUNT(OT_COUNTER_FULLSCRAPE_REQUESTS, 1); - } break; - case EVENT_FAILED: - COUNT(OT_COUNTER_FAILED + event_data, 1); - break; - case EVENT_RENEW: - COUNT(OT_COUNTER_RENEWED + event_data, 1); - break; - case EVENT_SYNC: - COUNT(OT_COUNTER_SYNCS, event_data); - break; - case EVENT_BUCKET_LOCKED: - COUNT(OT_COUNTER_STALLS, 1); - break; -#ifdef WANT_SPOT_WOODPECKER - case EVENT_WOODPECKER: - pthread_mutex_lock(&g_woodpeckers_mutex); - stat_increase_network_count(&stats_woodpeckers_tree, 0, event_data); - pthread_mutex_unlock(&g_woodpeckers_mutex); - break; -#endif - case EVENT_CONNID_MISSMATCH: - COUNT(OT_COUNTER_UDP_CONNID_MISSMATCH, 1); - default: - break; - } -} - -void stats_cleanup(void) { -#ifdef WANT_SPOT_WOODPECKER - pthread_mutex_lock(&g_woodpeckers_mutex); - stats_shift_down_network_count(&stats_woodpeckers_tree, 0, 1); - pthread_mutex_unlock(&g_woodpeckers_mutex); -#endif -} - -static void *stats_worker(void *args) { - size_t iovec_entries; - struct iovec *iovector; - - (void)args; - - while (g_opentracker_running) { - ot_tasktype tasktype = TASK_STATS; - ot_taskid taskid = workqueue_poptask(&tasktype); - if (!taskid) - break; - stats_make(&iovec_entries, &iovector, tasktype); - if (workqueue_pushresult(taskid, iovec_entries, iovector)) - iovec_free(&iovec_entries, &iovector); - } - return NULL; -} - -void stats_deliver(int64_t sock, int tasktype) { workqueue_pushtask(sock, tasktype); } - -static pthread_t thread_id; -void stats_init(void) { - ot_start_time = time_now_seconds(); - pthread_create(&thread_id, NULL, stats_worker, NULL); -} - -void stats_deinit(void) { - workqueue_wakeall(); - pthread_join(thread_id, NULL); -} -- cgit v1.3