summaryrefslogtreecommitdiff
path: root/ot_stats.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_stats.c')
-rw-r--r--ot_stats.c325
1 files changed, 159 insertions, 166 deletions
diff --git a/ot_stats.c b/ot_stats.c
index 6589aef..45dc8db 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -16,15 +16,13 @@
16#include <syslog.h> 16#include <syslog.h>
17#endif 17#endif
18 18
19/* Libowfat */
20#include "io.h"
21
22/* Opentracker */ 19/* Opentracker */
23#include "ot_accesslist.h" 20#include "ot_accesslist.h"
24#include "ot_hex.h" 21#include "ot_hex.h"
25#include "ot_iovec.h" 22#include "ot_iovec.h"
26#include "ot_ip.h" 23#include "ot_ip.h"
27#include "ot_mutex.h" 24#include "ot_mutex.h"
25#include "ot_fmt.h"
28#include "ot_stats.h" 26#include "ot_stats.h"
29#include "trackerlogic.h" 27#include "trackerlogic.h"
30 28
@@ -178,8 +176,8 @@ static size_t stats_get_highscore_networks(stats_network_node *node, int depth,
178 ++j; 176 ++j;
179 --j; 177 --j;
180 178
181 memcpy(scores, scores + 1, j * sizeof(*scores)); 179 memmove(scores, scores + 1, j * sizeof(*scores));
182 memcpy(networks, networks + 1, j * sizeof(*networks)); 180 memmove(networks, networks + 1, j * sizeof(*networks));
183 scores[j] = node_score; 181 scores[j] = node_score;
184 memcpy(networks + j, node_value, sizeof(*networks)); 182 memcpy(networks + j, node_value, sizeof(*networks));
185 } 183 }
@@ -187,12 +185,11 @@ static size_t stats_get_highscore_networks(stats_network_node *node, int depth,
187 return score; 185 return score;
188} 186}
189 187
190static size_t stats_return_busy_networks(char *reply, stats_network_node *tree, size_t amount, int limit) { 188static void stats_return_busy_networks(char **reply, const char *reply_end, stats_network_node *tree, size_t amount, int limit) {
191 ot_ip6 networks[amount]; 189 ot_ip6 networks[amount];
192 ot_ip6 node_value; 190 ot_ip6 node_value;
193 size_t scores[amount]; 191 size_t scores[amount];
194 size_t i; 192 size_t i;
195 char *r = reply;
196 193
197 memset(scores, 0, sizeof(scores)); 194 memset(scores, 0, sizeof(scores));
198 memset(networks, 0, sizeof(networks)); 195 memset(networks, 0, sizeof(networks));
@@ -200,24 +197,21 @@ static size_t stats_return_busy_networks(char *reply, stats_network_node *tree,
200 197
201 stats_get_highscore_networks(tree, 0, node_value, scores, networks, amount, limit); 198 stats_get_highscore_networks(tree, 0, node_value, scores, networks, amount, limit);
202 199
203 r += sprintf(r, "Networks, limit /%d:\n", limit + STATS_NETWORK_NODE_BITWIDTH); 200 fmt_append(reply, reply_end, "Networks, limit /%d:\n", limit + STATS_NETWORK_NODE_BITWIDTH);
204 for (i = amount; i > 0; --i) { 201 for (i = amount; i > 0; --i) {
205 if (scores[i - 1]) { 202 if (scores[i - 1]) {
206 r += sprintf(r, "%08zd: ", scores[i - 1]); 203 char ip_readable[64];
207 // #ifdef WANT_V6 204
208 r += ip_format(r, networks[i - 1]); 205 ip_readable[ip_format(ip_readable, networks[i - 1])] = 0;
209 *r++ = '\n'; 206 fmt_append(reply, reply_end, "%08zd: %s\n", scores[i - 1], ip_readable);
210 } 207 }
211 } 208 }
212 *r++ = '\n'; 209 fmt_append(reply, reply_end, "\n");
213
214 return r - reply;
215} 210}
216 211
217static size_t stats_slash24s_txt(char *reply, size_t amount) { 212static void stats_slash24s_txt(char **reply, const char *reply_end, size_t amount) {
218 stats_network_node *slash24s_network_counters_root = NULL; 213 stats_network_node *slash24s_network_counters_root = NULL;
219 char *r = reply; 214 size_t i, bucket, peer_size = OT_PEER_SIZE4;
220 size_t i, bucket, peer_size = OT_PEER_SIZE4;
221 215
222 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 216 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
223 ot_vector *torrents_list = mutex_bucket_lock(bucket); 217 ot_vector *torrents_list = mutex_bucket_lock(bucket);
@@ -244,35 +238,28 @@ static size_t stats_slash24s_txt(char *reply, size_t amount) {
244 } 238 }
245 mutex_bucket_unlock(bucket, 0); 239 mutex_bucket_unlock(bucket, 0);
246 if (!g_opentracker_running) 240 if (!g_opentracker_running)
247 goto bailout_error; 241 goto done;
248 } 242 }
249 243
250 /* The tree is built. Now analyze */ 244 /* The tree is built. Now analyze */
251 r += stats_return_busy_networks(r, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_MAXDEPTH); 245 stats_return_busy_networks(reply, reply_end, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_MAXDEPTH);
252 r += stats_return_busy_networks(r, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_LIMIT); 246 stats_return_busy_networks(reply, reply_end, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_LIMIT);
253 goto success; 247 goto done;
254 248
255bailout_unlock: 249bailout_unlock:
256 mutex_bucket_unlock(bucket, 0); 250 mutex_bucket_unlock(bucket, 0);
257bailout_error: 251done:
258 r = reply;
259success:
260 stats_shift_down_network_count(&slash24s_network_counters_root, 0, sizeof(int) * 8 - 1); 252 stats_shift_down_network_count(&slash24s_network_counters_root, 0, sizeof(int) * 8 - 1);
261
262 return r - reply;
263} 253}
264 254
265#ifdef WANT_SPOT_WOODPECKER 255#ifdef WANT_SPOT_WOODPECKER
266static stats_network_node *stats_woodpeckers_tree; 256static stats_network_node *stats_woodpeckers_tree;
267static pthread_mutex_t g_woodpeckers_mutex = PTHREAD_MUTEX_INITIALIZER; 257static pthread_mutex_t g_woodpeckers_mutex = PTHREAD_MUTEX_INITIALIZER;
268 258
269static size_t stats_return_woodpeckers(char *reply, int amount) { 259static void stats_return_woodpeckers(char **reply, const char *reply_end, int amount) {
270 char *r = reply;
271
272 pthread_mutex_lock(&g_woodpeckers_mutex); 260 pthread_mutex_lock(&g_woodpeckers_mutex);
273 r += stats_return_busy_networks(r, stats_woodpeckers_tree, amount, STATS_NETWORK_NODE_MAXDEPTH); 261 stats_return_busy_networks(reply, reply_end, stats_woodpeckers_tree, amount, STATS_NETWORK_NODE_MAXDEPTH);
274 pthread_mutex_unlock(&g_woodpeckers_mutex); 262 pthread_mutex_unlock(&g_woodpeckers_mutex);
275 return r - reply;
276} 263}
277#endif 264#endif
278 265
@@ -312,10 +299,10 @@ static inline void stats_insert_into_highscore(size_t val, ot_record* list, size
312 299
313 300
314/* Fetches stats from tracker */ 301/* Fetches stats from tracker */
315size_t stats_top_txt(char *reply, size_t amount) { 302void stats_top_txt(char **reply, const char *reply_end, size_t amount) {
316 size_t j, idx, bucket; 303 size_t j, idx, bucket;
317 ot_record top100s[100], top100c[100], top100l[100]; 304 ot_record top100s[100], top100c[100], top100l[100];
318 char *r = reply, hex_out[42]; 305 char hex_out[42];
319 306
320 if (amount > 100) 307 if (amount > 100)
321 amount = 100; 308 amount = 100;
@@ -326,7 +313,7 @@ size_t stats_top_txt(char *reply, size_t amount) {
326 313
327 /* Iterate over complete torrent list */ 314 /* Iterate over complete torrent list */
328 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 315 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
329 ot_vector *torrents_list = mutex_bucket_lock(bucket); 316 ot_vector *torrents_list = mutex_bucket_lock(bucket);
330 for (j = 0; j < torrents_list->size; ++j) { 317 for (j = 0; j < torrents_list->size; ++j) {
331 ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j; 318 ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j;
332 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; 319 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
@@ -339,114 +326,110 @@ size_t stats_top_txt(char *reply, size_t amount) {
339 } 326 }
340 mutex_bucket_unlock(bucket, 0); 327 mutex_bucket_unlock(bucket, 0);
341 if (!g_opentracker_running) 328 if (!g_opentracker_running)
342 return 0; 329 return;
343 } 330 }
344 331
345 r += sprintf(r, "Top %zd torrents by peers:\n", amount); 332 fmt_append(reply, reply_end, "Top %zd torrents by peers:\n", amount);
346 for (idx = 0; idx < amount; ++idx) 333 for (idx = 0; idx < amount; ++idx)
347 if (top100c[idx].val) 334 if (top100c[idx].val)
348 r += sprintf(r, "\t%zd\t%s\n", top100c[idx].val, hex_fromhash(hex_out, top100c[idx].hash)); 335 fmt_append(reply, reply_end, "\t%zd\t%s\n", top100c[idx].val, hex_from_hash(hex_out, top100c[idx].hash));
349 r += sprintf(r, "Top %zd torrents by seeds:\n", amount); 336 fmt_append(reply, reply_end, "Top %zd torrents by seeds:\n", amount);
350 for (idx = 0; idx < amount; ++idx) 337 for (idx = 0; idx < amount; ++idx)
351 if (top100s[idx].val) 338 if (top100s[idx].val)
352 r += sprintf(r, "\t%zd\t%s\n", top100s[idx].val, hex_fromhash(hex_out, top100s[idx].hash)); 339 fmt_append(reply, reply_end, "\t%zd\t%s\n", top100s[idx].val, hex_from_hash(hex_out, top100s[idx].hash));
353 r += sprintf(r, "Top %zd torrents by leechers:\n", amount); 340 fmt_append(reply, reply_end, "Top %zd torrents by leechers:\n", amount);
354 for (idx = 0; idx < amount; ++idx) 341 for (idx = 0; idx < amount; ++idx)
355 if (top100l[idx].val) 342 if (top100l[idx].val)
356 r += sprintf(r, "\t%zd\t%s\n", top100l[idx].val, hex_fromhash(hex_out, top100l[idx].hash)); 343 fmt_append(reply, reply_end, "\t%zd\t%s\n", top100l[idx].val, hex_from_hash(hex_out, top100l[idx].hash));
357
358 return r - reply;
359} 344}
360 345
361static unsigned long events_per_time(unsigned long long events, time_t t) { return events / ((unsigned int)t ? (unsigned int)t : 1); } 346static unsigned long events_per_time(unsigned long long events, time_t t) { return events / ((unsigned int)t ? (unsigned int)t : 1); }
362 347
363static size_t stats_connections_mrtg(char *reply) { 348static void stats_connections_mrtg(char **reply, const char *reply_end) {
364 ot_time t = time(NULL) - ot_start_time; 349 ot_time t = time(NULL) - ot_start_time;
365 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", 350 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.",
366 ot_overall_tcp_connections + ot_overall_udp_connections, 351 ot_overall_tcp_connections + ot_overall_udp_connections,
367 ot_overall_tcp_successfulannounces + ot_overall_udp_successfulannounces + ot_overall_udp_connects, (int)t, (int)(t / 3600), 352 ot_overall_tcp_successfulannounces + ot_overall_udp_successfulannounces + ot_overall_udp_connects, (int)t, (int)(t / 3600),
368 events_per_time(ot_overall_tcp_connections + ot_overall_udp_connections, t), 353 events_per_time(ot_overall_tcp_connections + ot_overall_udp_connections, t),
369 events_per_time(ot_overall_tcp_successfulannounces + ot_overall_udp_successfulannounces + ot_overall_udp_connects, t)); 354 events_per_time(ot_overall_tcp_successfulannounces + ot_overall_udp_successfulannounces + ot_overall_udp_connects, t));
370} 355}
371 356
372static size_t stats_udpconnections_mrtg(char *reply) { 357static void stats_udpconnections_mrtg(char **reply, const char *reply_end) {
373 ot_time t = time(NULL) - ot_start_time; 358 ot_time t = time(NULL) - ot_start_time;
374 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats, %lu conns/s :: %lu success/s.", ot_overall_udp_connections, 359 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats, %lu conns/s :: %lu success/s.", ot_overall_udp_connections,
375 ot_overall_udp_successfulannounces + ot_overall_udp_connects, (int)t, (int)(t / 3600), events_per_time(ot_overall_udp_connections, t), 360 ot_overall_udp_successfulannounces + ot_overall_udp_connects, (int)t, (int)(t / 3600), events_per_time(ot_overall_udp_connections, t),
376 events_per_time(ot_overall_udp_successfulannounces + ot_overall_udp_connects, t)); 361 events_per_time(ot_overall_udp_successfulannounces + ot_overall_udp_connects, t));
377} 362}
378 363
379static size_t stats_tcpconnections_mrtg(char *reply) { 364static void stats_tcpconnections_mrtg(char **reply, const char *reply_end) {
380 time_t t = time(NULL) - ot_start_time; 365 time_t t = time(NULL) - ot_start_time;
381 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats, %lu conns/s :: %lu success/s.", ot_overall_tcp_connections, 366 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats, %lu conns/s :: %lu success/s.", ot_overall_tcp_connections,
382 ot_overall_tcp_successfulannounces, (int)t, (int)(t / 3600), events_per_time(ot_overall_tcp_connections, t), 367 ot_overall_tcp_successfulannounces, (int)t, (int)(t / 3600), events_per_time(ot_overall_tcp_connections, t),
383 events_per_time(ot_overall_tcp_successfulannounces, t)); 368 events_per_time(ot_overall_tcp_successfulannounces, t));
384} 369}
385 370
386static size_t stats_scrape_mrtg(char *reply) { 371static void stats_scrape_mrtg(char **reply, const char *reply_end) {
387 time_t t = time(NULL) - ot_start_time; 372 time_t t = time(NULL) - ot_start_time;
388 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker scrape stats, %lu scrape/s (tcp and udp)", ot_overall_tcp_successfulscrapes, 373 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker scrape stats, %lu scrape/s (tcp and udp)",
389 ot_overall_udp_successfulscrapes, (int)t, (int)(t / 3600), 374 ot_overall_tcp_successfulscrapes, ot_overall_udp_successfulscrapes, (int)t, (int)(t / 3600),
390 events_per_time((ot_overall_tcp_successfulscrapes + ot_overall_udp_successfulscrapes), t)); 375 events_per_time((ot_overall_tcp_successfulscrapes + ot_overall_udp_successfulscrapes), t));
391} 376}
392 377
393static size_t stats_fullscrapes_mrtg(char *reply) { 378static void stats_fullscrapes_mrtg(char **reply, const char *reply_end) {
394 ot_time t = time(NULL) - ot_start_time; 379 ot_time t = time(NULL) - ot_start_time;
395 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker full scrape stats, %lu conns/s :: %lu bytes/s.", ot_full_scrape_count * 1000, 380 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker full scrape stats, %lu conns/s :: %lu bytes/s.",
396 ot_full_scrape_size, (int)t, (int)(t / 3600), events_per_time(ot_full_scrape_count, t), events_per_time(ot_full_scrape_size, t)); 381 ot_full_scrape_count * 1000, ot_full_scrape_size, (int)t, (int)(t / 3600), events_per_time(ot_full_scrape_count, t),
382 events_per_time(ot_full_scrape_size, t));
397} 383}
398 384
399static size_t stats_peers_mrtg(char *reply) { 385static void stats_peers_mrtg(char **reply, const char *reply_end) {
400 torrent_stats stats = {0, 0, 0}; 386 torrent_stats stats = {0, 0, 0};
401 387
402 iterate_all_torrents(torrent_statter, (uintptr_t)&stats); 388 iterate_all_torrents(torrent_statter, (uintptr_t)&stats);
403 389
404 return sprintf(reply, "%llu\n%llu\nopentracker serving %llu torrents\nopentracker", stats.peer_count, stats.seed_count, stats.torrent_count); 390 fmt_append(reply, reply_end, "%llu\n%llu\nopentracker serving %llu torrents\nopentracker", stats.peer_count, stats.seed_count,
391 stats.torrent_count);
405} 392}
406 393
407static size_t stats_torrents_mrtg(char *reply) { 394static void stats_torrents_mrtg(char **reply, const char *reply_end) {
408 size_t torrent_count = mutex_get_torrent_count(); 395 size_t torrent_count = mutex_get_torrent_count();
409 396
410 return sprintf(reply, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", torrent_count, (size_t)0, torrent_count); 397 fmt_append(reply, reply_end, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", torrent_count, (size_t)0, torrent_count);
411} 398}
412 399
413static size_t stats_httperrors_txt(char *reply) { 400static void stats_httperrors_txt(char **reply, const char *reply_end) {
414 return sprintf(reply, "302 RED %llu\n400 ... %llu\n400 PAR %llu\n400 COM %llu\n403 IP %llu\n404 INV %llu\n500 SRV %llu\n", ot_failed_request_counts[0], 401 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",
415 ot_failed_request_counts[1], ot_failed_request_counts[2], ot_failed_request_counts[3], ot_failed_request_counts[4], 402 ot_failed_request_counts[0], ot_failed_request_counts[1], ot_failed_request_counts[2], ot_failed_request_counts[3],
416 ot_failed_request_counts[5], ot_failed_request_counts[6]); 403 ot_failed_request_counts[4], ot_failed_request_counts[5], ot_failed_request_counts[6]);
417} 404}
418 405
419static size_t stats_return_renew_bucket(char *reply) { 406static void stats_return_renew_bucket(char **reply, const char *reply_end) {
420 char *r = reply; 407 int i;
421 int i;
422 408
423 for (i = 0; i < OT_PEER_TIMEOUT; ++i) 409 for (i = 0; i < OT_PEER_TIMEOUT; ++i)
424 r += sprintf(r, "%02i %llu\n", i, ot_renewed[i]); 410 fmt_append(reply, reply_end, "%02i %llu\n", i, ot_renewed[i]);
425 return r - reply;
426} 411}
427 412
428static size_t stats_return_sync_mrtg(char *reply) { 413static void stats_return_sync_mrtg(char **reply, const char *reply_end) {
429 ot_time t = time(NULL) - ot_start_time; 414 ot_time t = time(NULL) - ot_start_time;
430 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", ot_overall_sync_count, 0LL, (int)t, 415 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", ot_overall_sync_count, 0LL,
431 (int)(t / 3600), events_per_time(ot_overall_tcp_connections + ot_overall_udp_connections, t), 416 (int)t, (int)(t / 3600), events_per_time(ot_overall_tcp_connections + ot_overall_udp_connections, t),
432 events_per_time(ot_overall_tcp_successfulannounces + ot_overall_udp_successfulannounces + ot_overall_udp_connects, t)); 417 events_per_time(ot_overall_tcp_successfulannounces + ot_overall_udp_successfulannounces + ot_overall_udp_connects, t));
433} 418}
434 419
435static size_t stats_return_completed_mrtg(char *reply) { 420static void stats_return_completed_mrtg(char **reply, const char *reply_end) {
436 ot_time t = time(NULL) - ot_start_time; 421 ot_time t = time(NULL) - ot_start_time;
437 422
438 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker, %lu completed/h.", ot_overall_completed, 0LL, (int)t, (int)(t / 3600), 423 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker, %lu completed/h.", ot_overall_completed, 0LL, (int)t, (int)(t / 3600),
439 events_per_time(ot_overall_completed, t / 3600)); 424 events_per_time(ot_overall_completed, t / 3600));
440} 425}
441 426
442#ifdef WANT_LOG_NUMWANT 427#ifdef WANT_LOG_NUMWANT
443extern unsigned long long numwants[201]; 428extern unsigned long long numwants[201];
444static size_t stats_return_numwants(char *reply) { 429static void stats_return_numwants(char **reply, const char *reply_end) {
445 char *r = reply; 430 int i;
446 int i;
447 for (i = 0; i <= 200; ++i) 431 for (i = 0; i <= 200; ++i)
448 r += sprintf(r, "%03d => %lld\n", i, numwants[i]); 432 fmt_append(reply, reply_end, "%03d => %lld\n", i, numwants[i]);
449 return r - reply;
450} 433}
451#endif 434#endif
452 435
@@ -459,148 +442,158 @@ static void stats_return_fulllog(size_t *iovec_entries, struct iovec **iovector,
459 442
460 while (loglist) { 443 while (loglist) {
461 if (r + (loglist->size + 64) >= re) { 444 if (r + (loglist->size + 64) >= re) {
462 r = iovec_fix_increase_or_free(iovec_entries, iovector, r, 32 * OT_STATS_TMPSIZE); 445 r = iovec_next_chunk(iovec_entries, iovector, r, 32 * OT_STATS_TMPSIZE);
463 if (!r) 446 if (!r)
464 return; 447 return;
465 re = r + 32 * OT_STATS_TMPSIZE; 448 re = r + 32 * OT_STATS_TMPSIZE;
466 } 449 }
467 r += sprintf(r, "%08ld: ", loglist->time); 450 char ip_readable[64];
468 r += ip_format(r, loglist->ip); 451
469 *r++ = '\n'; 452 ip_readable[ip_format(ip_readable, loglist->ip)] = 0;
470 memcpy(r, loglist->data, loglist->size); 453 fmt_append(&r, re, "%08ld: %s\n", loglist->time, ip_readable);
471 r += loglist->size; 454 fmt_bytes(&r, re, loglist->data, loglist->size);
472 *r++ = '\n'; 455 fmt_append(&r, re, "\n*\n\n");
473 *r++ = '*';
474 *r++ = '\n';
475 *r++ = '\n';
476 456
477 llnext = loglist->next; 457 llnext = loglist->next;
478 free(loglist->data); 458 free(loglist->data);
479 free(loglist); 459 free(loglist);
480 loglist = llnext; 460 loglist = llnext;
481 } 461 }
482 iovec_fixlast(iovec_entries, iovector, r); 462 iovec_trim_last(iovec_entries, iovector, r);
483} 463}
484#endif 464#endif
485 465
486static size_t stats_return_everything(char *reply) { 466static void stats_return_everything(char **reply, const char *reply_end) {
487 torrent_stats stats = {0, 0, 0}; 467 torrent_stats stats = {0, 0, 0};
488 int i; 468 int i;
489 char *r = reply;
490 469
491 iterate_all_torrents(torrent_statter, (uintptr_t)&stats); 470 iterate_all_torrents(torrent_statter, (uintptr_t)&stats);
492 471
493 r += sprintf(r, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 472 fmt_append(reply, reply_end, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
494 r += sprintf(r, "<stats>\n"); 473 fmt_append(reply, reply_end, "<stats>\n");
495 r += sprintf(r, " <tracker_id>%" PRIu32 "</tracker_id>\n", g_tracker_id); 474 fmt_append(reply, reply_end, " <tracker_id>%" PRIu32 "</tracker_id>\n", g_tracker_id);
496 r += sprintf(r, " <version>\n"); 475 fmt_append(reply, reply_end, " <version>\n");
497 r += stats_return_tracker_version(r); 476 stats_return_tracker_version(reply, reply_end);
498 r += sprintf(r, " </version>\n"); 477 fmt_append(reply, reply_end, " </version>\n");
499 r += sprintf(r, " <uptime>%llu</uptime>\n", (unsigned long long)(time(NULL) - ot_start_time)); 478 fmt_append(reply, reply_end, " <uptime>%llu</uptime>\n", (unsigned long long)(time(NULL) - ot_start_time));
500 r += sprintf(r, " <torrents>\n"); 479 fmt_append(reply, reply_end, " <torrents>\n");
501 r += sprintf(r, " <count_mutex>%zd</count_mutex>\n", mutex_get_torrent_count()); 480 fmt_append(reply, reply_end, " <count_mutex>%zd</count_mutex>\n", mutex_get_torrent_count());
502 r += sprintf(r, " <count_iterator>%llu</count_iterator>\n", stats.torrent_count); 481 fmt_append(reply, reply_end, " <count_iterator>%llu</count_iterator>\n", stats.torrent_count);
503 r += sprintf(r, " </torrents>\n"); 482 fmt_append(reply, reply_end, " </torrents>\n");
504 r += sprintf(r, " <peers>\n <count>%llu</count>\n </peers>\n", stats.peer_count); 483 fmt_append(reply, reply_end, " <peers>\n <count>%llu</count>\n </peers>\n", stats.peer_count);
505 r += sprintf(r, " <seeds>\n <count>%llu</count>\n </seeds>\n", stats.seed_count); 484 fmt_append(reply, reply_end, " <seeds>\n <count>%llu</count>\n </seeds>\n", stats.seed_count);
506 r += sprintf(r, " <completed>\n <count>%llu</count>\n </completed>\n", ot_overall_completed); 485 fmt_append(reply, reply_end, " <completed>\n <count>%llu</count>\n </completed>\n", ot_overall_completed);
507 r += sprintf(r, " <connections>\n"); 486 fmt_append(reply, reply_end, " <connections>\n");
508 r += sprintf(r, " <tcp>\n <accept>%llu</accept>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n </tcp>\n", 487 fmt_append(reply, reply_end, " <tcp>\n <accept>%llu</accept>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n </tcp>\n",
509 ot_overall_tcp_connections, ot_overall_tcp_successfulannounces, ot_overall_tcp_successfulscrapes); 488 ot_overall_tcp_connections, ot_overall_tcp_successfulannounces, ot_overall_tcp_successfulscrapes);
510 r += sprintf(r, " <udp>\n <overall>%llu</overall>\n <connect>%llu</connect>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n <missmatch>%llu</missmatch>\n </udp>\n", 489 fmt_append(reply, reply_end, " <udp>\n <overall>%llu</overall>\n <connect>%llu</connect>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n <missmatch>%llu</missmatch>\n </udp>\n",
511 ot_overall_udp_connections, ot_overall_udp_connects, ot_overall_udp_successfulannounces, ot_overall_udp_successfulscrapes, 490 ot_overall_udp_connections, ot_overall_udp_connects, ot_overall_udp_successfulannounces, ot_overall_udp_successfulscrapes,
512 ot_overall_udp_connectionidmissmatches); 491 ot_overall_udp_connectionidmissmatches);
513 r += sprintf(r, " <livesync>\n <count>%llu</count>\n </livesync>\n", ot_overall_sync_count); 492 fmt_append(reply, reply_end, " <livesync>\n <count>%llu</count>\n </livesync>\n", ot_overall_sync_count);
514 r += sprintf(r, " </connections>\n"); 493 fmt_append(reply, reply_end, " </connections>\n");
515 r += sprintf(r, " <debug>\n"); 494 fmt_append(reply, reply_end, " <debug>\n");
516 r += sprintf(r, " <renew>\n"); 495 fmt_append(reply, reply_end, " <renew>\n");
517 for (i = 0; i < OT_PEER_TIMEOUT; ++i) 496 for (i = 0; i < OT_PEER_TIMEOUT; ++i)
518 r += sprintf(r, " <count interval=\"%02i\">%llu</count>\n", i, ot_renewed[i]); 497 fmt_append(reply, reply_end, " <count interval=\"%02i\">%llu</count>\n", i, ot_renewed[i]);
519 r += sprintf(r, " </renew>\n"); 498 fmt_append(reply, reply_end, " </renew>\n");
520 r += sprintf(r, " <http_error>\n"); 499 fmt_append(reply, reply_end, " <http_error>\n");
521 for (i = 0; i < CODE_HTTPERROR_COUNT; ++i) 500 for (i = 0; i < CODE_HTTPERROR_COUNT; ++i)
522 r += sprintf(r, " <count code=\"%s\">%llu</count>\n", ot_failed_request_names[i], ot_failed_request_counts[i]); 501 fmt_append(reply, reply_end, " <count code=\"%s\">%llu</count>\n", ot_failed_request_names[i], ot_failed_request_counts[i]);
523 r += sprintf(r, " </http_error>\n"); 502 fmt_append(reply, reply_end, " </http_error>\n");
524 r += sprintf(r, " <mutex_stall>\n <count>%llu</count>\n </mutex_stall>\n", ot_overall_stall_count); 503 fmt_append(reply, reply_end, " <mutex_stall>\n <count>%llu</count>\n </mutex_stall>\n", ot_overall_stall_count);
525 r += sprintf(r, " </debug>\n"); 504 fmt_append(reply, reply_end, " </debug>\n");
526 r += sprintf(r, "</stats>"); 505 fmt_append(reply, reply_end, "</stats>");
527 return r - reply;
528} 506}
529 507
530size_t stats_return_tracker_version(char *reply) { 508void stats_return_tracker_version(char **reply, const char *reply_end) {
531#define QUOTE(name) #name 509#define QUOTE(name) #name
532#define SQUOTE(name) QUOTE(name) 510#define SQUOTE(name) QUOTE(name)
533 return sprintf(reply, "https://erdgeist.org/gitweb/opentracker/commit/?id=" SQUOTE(GIT_VERSION) "\n"); 511 fmt_append(reply, reply_end, "https://erdgeist.org/gitweb/opentracker/commit/?id=" SQUOTE(GIT_VERSION) "\n");
534} 512}
535 513
536size_t return_stats_for_tracker(char *reply, int mode, int format) { 514void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format) {
537 (void)format; 515 (void)format;
538 switch (mode & TASK_TASK_MASK) { 516 switch (mode & TASK_TASK_MASK) {
539 case TASK_STATS_CONNS: 517 case TASK_STATS_CONNS:
540 return stats_connections_mrtg(reply); 518 stats_connections_mrtg(reply, reply_end);
519 break;
541 case TASK_STATS_SCRAPE: 520 case TASK_STATS_SCRAPE:
542 return stats_scrape_mrtg(reply); 521 stats_scrape_mrtg(reply, reply_end);
522 break;
543 case TASK_STATS_UDP: 523 case TASK_STATS_UDP:
544 return stats_udpconnections_mrtg(reply); 524 stats_udpconnections_mrtg(reply, reply_end);
525 break;
545 case TASK_STATS_TCP: 526 case TASK_STATS_TCP:
546 return stats_tcpconnections_mrtg(reply); 527 stats_tcpconnections_mrtg(reply, reply_end);
528 break;
547 case TASK_STATS_FULLSCRAPE: 529 case TASK_STATS_FULLSCRAPE:
548 return stats_fullscrapes_mrtg(reply); 530 stats_fullscrapes_mrtg(reply, reply_end);
531 break;
549 case TASK_STATS_COMPLETED: 532 case TASK_STATS_COMPLETED:
550 return stats_return_completed_mrtg(reply); 533 stats_return_completed_mrtg(reply, reply_end);
534 break;
551 case TASK_STATS_HTTPERRORS: 535 case TASK_STATS_HTTPERRORS:
552 return stats_httperrors_txt(reply); 536 stats_httperrors_txt(reply, reply_end);
537 break;
553 case TASK_STATS_VERSION: 538 case TASK_STATS_VERSION:
554 return stats_return_tracker_version(reply); 539 stats_return_tracker_version(reply, reply_end);
540 break;
555 case TASK_STATS_RENEW: 541 case TASK_STATS_RENEW:
556 return stats_return_renew_bucket(reply); 542 stats_return_renew_bucket(reply, reply_end);
543 break;
557 case TASK_STATS_SYNCS: 544 case TASK_STATS_SYNCS:
558 return stats_return_sync_mrtg(reply); 545 stats_return_sync_mrtg(reply, reply_end);
546 break;
559#ifdef WANT_LOG_NUMWANT 547#ifdef WANT_LOG_NUMWANT
560 case TASK_STATS_NUMWANTS: 548 case TASK_STATS_NUMWANTS:
561 return stats_return_numwants(reply); 549 stats_return_numwants(reply, reply_end);
550 break;
562#endif 551#endif
563 default: 552 default:
564 return 0; 553 break;
565 } 554 }
566} 555}
567 556
568static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode) { 557static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode) {
569 char *r; 558 char *r;
559 const char *r_end;
570 560
571 *iovec_entries = 0; 561 *iovec_entries = 0;
572 *iovector = NULL; 562 *iovector = NULL;
573 if (!(r = iovec_increase(iovec_entries, iovector, OT_STATS_TMPSIZE))) 563 if (!(r = iovec_new_chunk(iovec_entries, iovector, OT_STATS_TMPSIZE)))
574 return; 564 return;
565 r_end = r + OT_STATS_TMPSIZE;
575 566
576 switch (mode & TASK_TASK_MASK) { 567 switch (mode & TASK_TASK_MASK) {
577 case TASK_STATS_TORRENTS: 568 case TASK_STATS_TORRENTS:
578 r += stats_torrents_mrtg(r); 569 stats_torrents_mrtg(&r, r_end);
579 break; 570 break;
580 case TASK_STATS_PEERS: 571 case TASK_STATS_PEERS:
581 r += stats_peers_mrtg(r); 572 stats_peers_mrtg(&r, r_end);
582 break; 573 break;
583 case TASK_STATS_SLASH24S: 574 case TASK_STATS_SLASH24S:
584 r += stats_slash24s_txt(r, 128); 575 stats_slash24s_txt(&r, r_end, 128);
585 break; 576 break;
586 case TASK_STATS_TOP10: 577 case TASK_STATS_TOP10:
587 r += stats_top_txt(r, 10); 578 stats_top_txt(&r, r_end, 10);
588 break; 579 break;
589 case TASK_STATS_TOP100: 580 case TASK_STATS_TOP100:
590 r = iovec_fix_increase_or_free(iovec_entries, iovector, r, 4 * OT_STATS_TMPSIZE); 581 r = iovec_next_chunk(iovec_entries, iovector, r, 4 * OT_STATS_TMPSIZE);
591 if (!r) 582 if (!r)
592 return; 583 return;
593 r += stats_top_txt(r, 100); 584 r_end = r + 4 * OT_STATS_TMPSIZE;
585 stats_top_txt(&r, r_end, 100);
594 break; 586 break;
595 case TASK_STATS_EVERYTHING: 587 case TASK_STATS_EVERYTHING:
596 r = iovec_fix_increase_or_free(iovec_entries, iovector, r, OT_STATS_TMPSIZE + 64 * OT_PEER_TIMEOUT); 588 r = iovec_next_chunk(iovec_entries, iovector, r, OT_STATS_TMPSIZE + 64 * OT_PEER_TIMEOUT);
597 if (!r) 589 if (!r)
598 return; 590 return;
599 r += stats_return_everything(r); 591 r_end = r + OT_STATS_TMPSIZE + 64 * OT_PEER_TIMEOUT;
592 stats_return_everything(&r, r_end);
600 break; 593 break;
601#ifdef WANT_SPOT_WOODPECKER 594#ifdef WANT_SPOT_WOODPECKER
602 case TASK_STATS_WOODPECKERS: 595 case TASK_STATS_WOODPECKERS:
603 r += stats_return_woodpeckers(r, 128); 596 stats_return_woodpeckers(&r, r_end, 128);
604 break; 597 break;
605#endif 598#endif
606#ifdef WANT_FULLLOG_NETWORKS 599#ifdef WANT_FULLLOG_NETWORKS
@@ -612,7 +605,7 @@ static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_taskty
612 iovec_free(iovec_entries, iovector); 605 iovec_free(iovec_entries, iovector);
613 return; 606 return;
614 } 607 }
615 iovec_fixlast(iovec_entries, iovector, r); 608 iovec_trim_last(iovec_entries, iovector, r);
616} 609}
617 610
618void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data) { 611void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data) {
@@ -651,9 +644,9 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_
651 localtime_r(&ttt, &time_now); 644 localtime_r(&ttt, &time_now);
652 strftime(timestring, sizeof(timestring), "%FT%T%z", &time_now); 645 strftime(timestring, sizeof(timestring), "%FT%T%z", &time_now);
653 646
654 hex_fromhash(hash_hex, *ws->hash); 647 hex_from_hash(hash_hex, *ws->hash);
655 if (ws->peer_id) 648 if (ws->peer_id)
656 hex_fromhash(peerid_hex, (uint8_t *)ws->peer_id); 649 hex_from_hash(peerid_hex, (uint8_t *)ws->peer_id);
657 else { 650 else {
658 *peerid_hex = 0; 651 *peerid_hex = 0;
659 } 652 }