1 /* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
14 #include <sys/types.h>
28 #include "ot_accesslist.h"
32 #include "trackerlogic.h"
34 #ifndef NO_FULLSCRAPE_LOGGING
35 #define LOG_TO_STDERR(...) fprintf(stderr, __VA_ARGS__)
37 #define LOG_TO_STDERR(...)
40 /* Forward declaration */
41 static void stats_make(int *iovec_entries
, struct iovec
**iovector
, ot_tasktype mode
);
42 #define OT_STATS_TMPSIZE 8192
44 /* Clumsy counters... to be rethought */
45 static unsigned long long ot_overall_tcp_connections
;
46 static unsigned long long ot_overall_udp_connections
;
47 static unsigned long long ot_overall_tcp_successfulannounces
;
48 static unsigned long long ot_overall_udp_successfulannounces
;
49 static unsigned long long ot_overall_tcp_successfulscrapes
;
50 static unsigned long long ot_overall_udp_successfulscrapes
;
51 static unsigned long long ot_overall_udp_connectionidmissmatches
;
52 static unsigned long long ot_overall_tcp_connects
;
53 static unsigned long long ot_overall_udp_connects
;
54 static unsigned long long ot_overall_completed
;
55 static unsigned long long ot_full_scrape_count
;
56 static unsigned long long ot_full_scrape_request_count
;
57 static unsigned long long ot_full_scrape_size
;
58 static unsigned long long ot_failed_request_counts
[CODE_HTTPERROR_COUNT
];
59 static char *ot_failed_request_names
[] = {
60 "302 Redirect", "400 Parse Error", "400 Invalid Parameter", "400 Invalid Parameter (compact=0)", "400 Not Modest",
61 "402 Payment Required", "403 Access Denied", "404 Not found", "500 Internal Server Error"};
62 static unsigned long long ot_renewed
[OT_PEER_TIMEOUT
];
63 static unsigned long long ot_overall_sync_count
;
64 static unsigned long long ot_overall_stall_count
;
66 static time_t ot_start_time
;
68 #define STATS_NETWORK_NODE_BITWIDTH 4
69 #define STATS_NETWORK_NODE_COUNT (1 << STATS_NETWORK_NODE_BITWIDTH)
71 #define __BYTE(P, D) (((uint8_t *)P)[D / 8])
72 #define __MSK (STATS_NETWORK_NODE_COUNT - 1)
73 #define __SHFT(D) ((D ^ STATS_NETWORK_NODE_BITWIDTH) & STATS_NETWORK_NODE_BITWIDTH)
75 #define __LDR(P, D) ((__BYTE((P), (D)) >> __SHFT((D))) & __MSK)
76 #define __STR(P, D, V) __BYTE((P), (D)) = (__BYTE((P), (D)) & ~(__MSK << __SHFT((D)))) | ((V) << __SHFT((D)))
80 #define STATS_NETWORK_NODE_MAXDEPTH (68 - STATS_NETWORK_NODE_BITWIDTH)
81 #define STATS_NETWORK_NODE_LIMIT (48 - STATS_NETWORK_NODE_BITWIDTH)
83 #define STATS_NETWORK_NODE_MAXDEPTH (28 - STATS_NETWORK_NODE_BITWIDTH)
84 #define STATS_NETWORK_NODE_LIMIT (24 - STATS_NETWORK_NODE_BITWIDTH)
86 typedef union stats_network_node stats_network_node
;
87 union stats_network_node
{
88 size_t counters
[STATS_NETWORK_NODE_COUNT
];
89 stats_network_node
*children
[STATS_NETWORK_NODE_COUNT
];
92 #ifdef WANT_LOG_NETWORKS
93 static stats_network_node
*stats_network_counters_root
;
96 static int stat_increase_network_count(stats_network_node
**pnode
, int depth
, uintptr_t ip
) {
97 int foo
= __LDR(ip
, depth
);
98 stats_network_node
*node
;
101 *pnode
= malloc(sizeof(stats_network_node
));
104 memset(*pnode
, 0, sizeof(stats_network_node
));
108 if (depth
< STATS_NETWORK_NODE_MAXDEPTH
)
109 return stat_increase_network_count(node
->children
+ foo
, depth
+ STATS_NETWORK_NODE_BITWIDTH
, ip
);
111 node
->counters
[foo
]++;
115 static int stats_shift_down_network_count(stats_network_node
**node
, int depth
, int shift
) {
121 for (i
= 0; i
< STATS_NETWORK_NODE_COUNT
; ++i
)
122 if (depth
< STATS_NETWORK_NODE_MAXDEPTH
)
123 rest
+= stats_shift_down_network_count((*node
)->children
+ i
, depth
+ STATS_NETWORK_NODE_BITWIDTH
, shift
);
125 rest
+= (*node
)->counters
[i
] >>= shift
;
135 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
,
144 for (i
= 0; i
< STATS_NETWORK_NODE_COUNT
; ++i
)
145 if (node
->children
[i
]) {
146 __STR(node_value
, depth
, i
);
147 score
+= stats_get_highscore_networks(node
->children
[i
], depth
+ STATS_NETWORK_NODE_BITWIDTH
, node_value
, scores
, networks
, network_count
, limit
);
152 if (depth
> limit
&& depth
< STATS_NETWORK_NODE_MAXDEPTH
) {
153 for (i
= 0; i
< STATS_NETWORK_NODE_COUNT
; ++i
)
154 if (node
->children
[i
])
155 score
+= stats_get_highscore_networks(node
->children
[i
], depth
+ STATS_NETWORK_NODE_BITWIDTH
, node_value
, scores
, networks
, network_count
, limit
);
159 if (depth
> limit
&& depth
== STATS_NETWORK_NODE_MAXDEPTH
) {
160 for (i
= 0; i
< STATS_NETWORK_NODE_COUNT
; ++i
)
161 score
+= node
->counters
[i
];
165 /* if( depth == limit ) */
166 for (i
= 0; i
< STATS_NETWORK_NODE_COUNT
; ++i
) {
170 if (depth
== STATS_NETWORK_NODE_MAXDEPTH
)
171 node_score
= node
->counters
[i
];
173 node_score
= stats_get_highscore_networks(node
->children
[i
], depth
+ STATS_NETWORK_NODE_BITWIDTH
, node_value
, scores
, networks
, network_count
, limit
);
177 if (node_score
<= scores
[0])
180 __STR(node_value
, depth
, i
);
181 while (j
< network_count
&& node_score
> scores
[j
])
185 memcpy(scores
, scores
+ 1, j
* sizeof(*scores
));
186 memcpy(networks
, networks
+ 1, j
* sizeof(*networks
));
187 scores
[j
] = node_score
;
188 memcpy(networks
+ j
, node_value
, sizeof(*networks
));
194 static size_t stats_return_busy_networks(char *reply
, stats_network_node
*tree
, int amount
, int limit
) {
195 ot_ip6 networks
[amount
];
197 size_t scores
[amount
];
201 memset(scores
, 0, sizeof(scores
));
202 memset(networks
, 0, sizeof(networks
));
203 memset(node_value
, 0, sizeof(node_value
));
205 stats_get_highscore_networks(tree
, 0, node_value
, scores
, networks
, amount
, limit
);
207 r
+= sprintf(r
, "Networks, limit /%d:\n", limit
+ STATS_NETWORK_NODE_BITWIDTH
);
208 for (i
= amount
- 1; i
>= 0; --i
) {
210 r
+= sprintf(r
, "%08zd: ", scores
[i
]);
212 r
+= fmt_ip6c(r
, networks
[i
]);
215 r
+= fmt_ip4( r
, networks
[i
]);
225 static size_t stats_slash24s_txt(char *reply
, size_t amount
) {
226 stats_network_node
*slash24s_network_counters_root
= NULL
;
229 size_t i
, peer_size
= OT_PEER_SIZE4
;
231 for (bucket
= 0; bucket
< OT_BUCKET_COUNT
; ++bucket
) {
232 ot_vector
*torrents_list
= mutex_bucket_lock(bucket
);
233 for (i
= 0; i
< torrents_list
->size
; ++i
) {
234 ot_peerlist
*peer_list
= (((ot_torrent
*)(torrents_list
->data
))[i
]).peer_list4
;
235 ot_vector
*bucket_list
= &peer_list
->peers
;
238 if (OT_PEERLIST_HASBUCKETS(peer_list
)) {
239 num_buckets
= bucket_list
->size
;
240 bucket_list
= (ot_vector
*)bucket_list
->data
;
243 while (num_buckets
--) {
244 ot_peer
*peers
= (ot_peer
*)bucket_list
->data
;
245 size_t numpeers
= bucket_list
->size
;
247 if (stat_increase_network_count(&slash24s_network_counters_root
, 0, (uintptr_t)(peers
)))
254 mutex_bucket_unlock(bucket
, 0);
255 if (!g_opentracker_running
)
259 /* The tree is built. Now analyze */
260 r
+= stats_return_busy_networks(r
, slash24s_network_counters_root
, amount
, STATS_NETWORK_NODE_MAXDEPTH
);
261 r
+= stats_return_busy_networks(r
, slash24s_network_counters_root
, amount
, STATS_NETWORK_NODE_LIMIT
);
265 mutex_bucket_unlock(bucket
, 0);
269 stats_shift_down_network_count(&slash24s_network_counters_root
, 0, sizeof(int) * 8 - 1);
274 #ifdef WANT_SPOT_WOODPECKER
275 static stats_network_node
*stats_woodpeckers_tree
;
276 static pthread_mutex_t g_woodpeckers_mutex
= PTHREAD_MUTEX_INITIALIZER
;
278 static size_t stats_return_woodpeckers(char *reply
, int amount
) {
281 pthread_mutex_lock(&g_woodpeckers_mutex
);
282 r
+= stats_return_busy_networks(r
, stats_woodpeckers_tree
, amount
, STATS_NETWORK_NODE_MAXDEPTH
);
283 pthread_mutex_unlock(&g_woodpeckers_mutex
);
289 unsigned long long torrent_count
;
290 unsigned long long peer_count
;
291 unsigned long long seed_count
;
294 static int torrent_statter(ot_torrent
*torrent
, uintptr_t data
) {
295 torrent_stats
*stats
= (torrent_stats
*)data
;
296 stats
->torrent_count
++;
297 stats
->peer_count
+= torrent
->peer_list6
->peer_count
+ torrent
->peer_list4
->peer_count
;
298 stats
->seed_count
+= torrent
->peer_list6
->seed_count
+ torrent
->peer_list4
->seed_count
;
302 /* Converter function from memory to human readable hex strings */
303 static char *to_hex(char *d
, uint8_t *s
) {
304 char *m
= "0123456789ABCDEF";
320 /* Fetches stats from tracker */
321 size_t stats_top_txt(char *reply
, int amount
) {
323 ot_record top100s
[100], top100c
[100];
324 char *r
= reply
, hex_out
[42];
330 byte_zero(top100s
, sizeof(top100s
));
331 byte_zero(top100c
, sizeof(top100c
));
333 for (bucket
= 0; bucket
< OT_BUCKET_COUNT
; ++bucket
) {
334 ot_vector
*torrents_list
= mutex_bucket_lock(bucket
);
335 for (j
= 0; j
< torrents_list
->size
; ++j
) {
336 ot_torrent
*torrent
= (ot_torrent
*)(torrents_list
->data
) + j
;
337 size_t peer_count
= torrent
->peer_list6
->peer_count
+ torrent
->peer_list4
->peer_count
;
338 size_t seed_count
= torrent
->peer_list6
->seed_count
+ torrent
->peer_list4
->seed_count
;
340 while ((idx
>= 0) && (peer_count
> top100c
[idx
].val
))
342 if (idx
++ != amount
- 1) {
343 memmove(top100c
+ idx
+ 1, top100c
+ idx
, (amount
- 1 - idx
) * sizeof(ot_record
));
344 memcpy(&top100c
[idx
].hash
, &torrent
->hash
, sizeof(ot_hash
));
345 top100c
[idx
].val
= peer_count
;
348 while ((idx
>= 0) && (seed_count
> top100s
[idx
].val
))
350 if (idx
++ != amount
- 1) {
351 memmove(top100s
+ idx
+ 1, top100s
+ idx
, (amount
- 1 - idx
) * sizeof(ot_record
));
352 memcpy(&top100s
[idx
].hash
, &torrent
->hash
, sizeof(ot_hash
));
353 top100s
[idx
].val
= seed_count
;
356 mutex_bucket_unlock(bucket
, 0);
357 if (!g_opentracker_running
)
361 r
+= sprintf(r
, "Top %d torrents by peers:\n", amount
);
362 for (idx
= 0; idx
< amount
; ++idx
)
363 if (top100c
[idx
].val
)
364 r
+= sprintf(r
, "\t%zd\t%s\n", top100c
[idx
].val
, to_hex(hex_out
, top100c
[idx
].hash
));
365 r
+= sprintf(r
, "Top %d torrents by seeds:\n", amount
);
366 for (idx
= 0; idx
< amount
; ++idx
)
367 if (top100s
[idx
].val
)
368 r
+= sprintf(r
, "\t%zd\t%s\n", top100s
[idx
].val
, to_hex(hex_out
, top100s
[idx
].hash
));
373 static unsigned long events_per_time(unsigned long long events
, time_t t
) { return events
/ ((unsigned int)t
? (unsigned int)t
: 1); }
375 static size_t stats_connections_mrtg(char *reply
) {
376 ot_time t
= time(NULL
) - ot_start_time
;
377 return sprintf(reply
, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.",
378 ot_overall_tcp_connections
+ ot_overall_udp_connections
,
379 ot_overall_tcp_successfulannounces
+ ot_overall_udp_successfulannounces
+ ot_overall_udp_connects
, (int)t
, (int)(t
/ 3600),
380 events_per_time(ot_overall_tcp_connections
+ ot_overall_udp_connections
, t
),
381 events_per_time(ot_overall_tcp_successfulannounces
+ ot_overall_udp_successfulannounces
+ ot_overall_udp_connects
, t
));
384 static size_t stats_udpconnections_mrtg(char *reply
) {
385 ot_time t
= time(NULL
) - ot_start_time
;
386 return sprintf(reply
, "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats, %lu conns/s :: %lu success/s.", ot_overall_udp_connections
,
387 ot_overall_udp_successfulannounces
+ ot_overall_udp_connects
, (int)t
, (int)(t
/ 3600), events_per_time(ot_overall_udp_connections
, t
),
388 events_per_time(ot_overall_udp_successfulannounces
+ ot_overall_udp_connects
, t
));
391 static size_t stats_tcpconnections_mrtg(char *reply
) {
392 time_t t
= time(NULL
) - ot_start_time
;
393 return sprintf(reply
, "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats, %lu conns/s :: %lu success/s.", ot_overall_tcp_connections
,
394 ot_overall_tcp_successfulannounces
, (int)t
, (int)(t
/ 3600), events_per_time(ot_overall_tcp_connections
, t
),
395 events_per_time(ot_overall_tcp_successfulannounces
, t
));
398 static size_t stats_scrape_mrtg(char *reply
) {
399 time_t t
= time(NULL
) - ot_start_time
;
400 return sprintf(reply
, "%llu\n%llu\n%i seconds (%i hours)\nopentracker scrape stats, %lu scrape/s (tcp and udp)", ot_overall_tcp_successfulscrapes
,
401 ot_overall_udp_successfulscrapes
, (int)t
, (int)(t
/ 3600),
402 events_per_time((ot_overall_tcp_successfulscrapes
+ ot_overall_udp_successfulscrapes
), t
));
405 static size_t stats_fullscrapes_mrtg(char *reply
) {
406 ot_time t
= time(NULL
) - ot_start_time
;
407 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,
408 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
));
411 static size_t stats_peers_mrtg(char *reply
) {
412 torrent_stats stats
= {0, 0, 0};
414 iterate_all_torrents(torrent_statter
, (uintptr_t)&stats
);
416 return sprintf(reply
, "%llu\n%llu\nopentracker serving %llu torrents\nopentracker", stats
.peer_count
, stats
.seed_count
, stats
.torrent_count
);
419 static size_t stats_torrents_mrtg(char *reply
) {
420 size_t torrent_count
= mutex_get_torrent_count();
422 return sprintf(reply
, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", torrent_count
, (size_t)0, torrent_count
);
425 static size_t stats_httperrors_txt(char *reply
) {
426 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],
427 ot_failed_request_counts
[1], ot_failed_request_counts
[2], ot_failed_request_counts
[3], ot_failed_request_counts
[4],
428 ot_failed_request_counts
[5], ot_failed_request_counts
[6]);
431 static size_t stats_return_renew_bucket(char *reply
) {
435 for (i
= 0; i
< OT_PEER_TIMEOUT
; ++i
)
436 r
+= sprintf(r
, "%02i %llu\n", i
, ot_renewed
[i
]);
440 static size_t stats_return_sync_mrtg(char *reply
) {
441 ot_time t
= time(NULL
) - ot_start_time
;
442 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
,
443 (int)(t
/ 3600), events_per_time(ot_overall_tcp_connections
+ ot_overall_udp_connections
, t
),
444 events_per_time(ot_overall_tcp_successfulannounces
+ ot_overall_udp_successfulannounces
+ ot_overall_udp_connects
, t
));
447 static size_t stats_return_completed_mrtg(char *reply
) {
448 ot_time t
= time(NULL
) - ot_start_time
;
450 return sprintf(reply
, "%llu\n%llu\n%i seconds (%i hours)\nopentracker, %lu completed/h.", ot_overall_completed
, 0LL, (int)t
, (int)(t
/ 3600),
451 events_per_time(ot_overall_completed
, t
/ 3600));
454 #ifdef WANT_LOG_NUMWANT
455 extern unsigned long long numwants
[201];
456 static size_t stats_return_numwants(char *reply
) {
459 for (i
= 0; i
<= 200; ++i
)
460 r
+= sprintf(r
, "%03d => %lld\n", i
, numwants
[i
]);
465 #ifdef WANT_FULLLOG_NETWORKS
466 static void stats_return_fulllog(int *iovec_entries
, struct iovec
**iovector
, char *r
) {
467 ot_log
*loglist
= g_logchain_first
, *llnext
;
468 char *re
= r
+ OT_STATS_TMPSIZE
;
470 g_logchain_first
= g_logchain_last
= 0;
473 if (r
+ (loglist
->size
+ 64) >= re
) {
474 r
= iovec_fix_increase_or_free(iovec_entries
, iovector
, r
, 32 * OT_STATS_TMPSIZE
);
477 re
= r
+ 32 * OT_STATS_TMPSIZE
;
479 r
+= sprintf(r
, "%08ld: ", loglist
->time
);
480 r
+= fmt_ip6c(r
, loglist
->ip
);
482 memcpy(r
, loglist
->data
, loglist
->size
);
489 llnext
= loglist
->next
;
494 iovec_fixlast(iovec_entries
, iovector
, r
);
498 static size_t stats_return_everything(char *reply
) {
499 torrent_stats stats
= {0, 0, 0};
503 iterate_all_torrents(torrent_statter
, (uintptr_t)&stats
);
505 r
+= sprintf(r
, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
506 r
+= sprintf(r
, "<stats>\n");
507 r
+= sprintf(r
, " <tracker_id>%" PRIu32
"</tracker_id>\n", g_tracker_id
);
508 r
+= sprintf(r
, " <version>\n");
509 r
+= stats_return_tracker_version(r
);
510 r
+= sprintf(r
, " </version>\n");
511 r
+= sprintf(r
, " <uptime>%llu</uptime>\n", (unsigned long long)(time(NULL
) - ot_start_time
));
512 r
+= sprintf(r
, " <torrents>\n");
513 r
+= sprintf(r
, " <count_mutex>%zd</count_mutex>\n", mutex_get_torrent_count());
514 r
+= sprintf(r
, " <count_iterator>%llu</count_iterator>\n", stats
.torrent_count
);
515 r
+= sprintf(r
, " </torrents>\n");
516 r
+= sprintf(r
, " <peers>\n <count>%llu</count>\n </peers>\n", stats
.peer_count
);
517 r
+= sprintf(r
, " <seeds>\n <count>%llu</count>\n </seeds>\n", stats
.seed_count
);
518 r
+= sprintf(r
, " <completed>\n <count>%llu</count>\n </completed>\n", ot_overall_completed
);
519 r
+= sprintf(r
, " <connections>\n");
520 r
+= sprintf(r
, " <tcp>\n <accept>%llu</accept>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n </tcp>\n",
521 ot_overall_tcp_connections
, ot_overall_tcp_successfulannounces
, ot_overall_tcp_successfulscrapes
);
522 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",
523 ot_overall_udp_connections
, ot_overall_udp_connects
, ot_overall_udp_successfulannounces
, ot_overall_udp_successfulscrapes
,
524 ot_overall_udp_connectionidmissmatches
);
525 r
+= sprintf(r
, " <livesync>\n <count>%llu</count>\n </livesync>\n", ot_overall_sync_count
);
526 r
+= sprintf(r
, " </connections>\n");
527 r
+= sprintf(r
, " <debug>\n");
528 r
+= sprintf(r
, " <renew>\n");
529 for (i
= 0; i
< OT_PEER_TIMEOUT
; ++i
)
530 r
+= sprintf(r
, " <count interval=\"%02i\">%llu</count>\n", i
, ot_renewed
[i
]);
531 r
+= sprintf(r
, " </renew>\n");
532 r
+= sprintf(r
, " <http_error>\n");
533 for (i
= 0; i
< CODE_HTTPERROR_COUNT
; ++i
)
534 r
+= sprintf(r
, " <count code=\"%s\">%llu</count>\n", ot_failed_request_names
[i
], ot_failed_request_counts
[i
]);
535 r
+= sprintf(r
, " </http_error>\n");
536 r
+= sprintf(r
, " <mutex_stall>\n <count>%llu</count>\n </mutex_stall>\n", ot_overall_stall_count
);
537 r
+= sprintf(r
, " </debug>\n");
538 r
+= sprintf(r
, "</stats>");
542 size_t stats_return_tracker_version(char *reply
) {
543 #define QUOTE(name) #name
544 #define SQUOTE(name) QUOTE(name)
545 return sprintf(reply
, "https://erdgeist.org/gitweb/opentracker/commit/?id=" SQUOTE(GIT_VERSION
) "\n");
548 size_t return_stats_for_tracker(char *reply
, int mode
, int format
) {
550 switch (mode
& TASK_TASK_MASK
) {
551 case TASK_STATS_CONNS
:
552 return stats_connections_mrtg(reply
);
553 case TASK_STATS_SCRAPE
:
554 return stats_scrape_mrtg(reply
);
556 return stats_udpconnections_mrtg(reply
);
558 return stats_tcpconnections_mrtg(reply
);
559 case TASK_STATS_FULLSCRAPE
:
560 return stats_fullscrapes_mrtg(reply
);
561 case TASK_STATS_COMPLETED
:
562 return stats_return_completed_mrtg(reply
);
563 case TASK_STATS_HTTPERRORS
:
564 return stats_httperrors_txt(reply
);
565 case TASK_STATS_VERSION
:
566 return stats_return_tracker_version(reply
);
567 case TASK_STATS_RENEW
:
568 return stats_return_renew_bucket(reply
);
569 case TASK_STATS_SYNCS
:
570 return stats_return_sync_mrtg(reply
);
571 #ifdef WANT_LOG_NUMWANT
572 case TASK_STATS_NUMWANTS
:
573 return stats_return_numwants(reply
);
580 static void stats_make(int *iovec_entries
, struct iovec
**iovector
, ot_tasktype mode
) {
585 if (!(r
= iovec_increase(iovec_entries
, iovector
, OT_STATS_TMPSIZE
)))
588 switch (mode
& TASK_TASK_MASK
) {
589 case TASK_STATS_TORRENTS
:
590 r
+= stats_torrents_mrtg(r
);
592 case TASK_STATS_PEERS
:
593 r
+= stats_peers_mrtg(r
);
595 case TASK_STATS_SLASH24S
:
596 r
+= stats_slash24s_txt(r
, 128);
598 case TASK_STATS_TOP10
:
599 r
+= stats_top_txt(r
, 10);
601 case TASK_STATS_TOP100
:
602 r
= iovec_fix_increase_or_free(iovec_entries
, iovector
, r
, 4 * OT_STATS_TMPSIZE
);
605 r
+= stats_top_txt(r
, 100);
607 case TASK_STATS_EVERYTHING
:
608 r
= iovec_fix_increase_or_free(iovec_entries
, iovector
, r
, OT_STATS_TMPSIZE
+ 64 * OT_PEER_TIMEOUT
);
611 r
+= stats_return_everything(r
);
613 #ifdef WANT_SPOT_WOODPECKER
614 case TASK_STATS_WOODPECKERS
:
615 r
+= stats_return_woodpeckers(r
, 128);
618 #ifdef WANT_FULLLOG_NETWORKS
619 case TASK_STATS_FULLLOG
:
620 stats_return_fulllog(iovec_entries
, iovector
, r
);
624 iovec_free(iovec_entries
, iovector
);
627 iovec_fixlast(iovec_entries
, iovector
, r
);
630 void stats_issue_event(ot_status_event event
, PROTO_FLAG proto
, uintptr_t event_data
) {
633 if (proto
== FLAG_TCP
)
634 ot_overall_tcp_connections
++;
636 ot_overall_udp_connections
++;
637 #ifdef WANT_LOG_NETWORKS
638 stat_increase_network_count(&stats_network_counters_root
, 0, event_data
);
642 if (proto
== FLAG_TCP
)
643 ot_overall_tcp_successfulannounces
++;
645 ot_overall_udp_successfulannounces
++;
648 if (proto
== FLAG_TCP
)
649 ot_overall_tcp_connects
++;
651 ot_overall_udp_connects
++;
653 case EVENT_COMPLETED
:
656 struct ot_workstruct
*ws
= (struct ot_workstruct
*)event_data
;
658 char hash_hex
[42], peerid_hex
[42], ip_readable
[64];
663 localtime_r(&ttt
, &time_now
);
664 strftime(timestring
, sizeof(timestring
), "%FT%T%z", &time_now
);
666 to_hex(hash_hex
, *ws
->hash
);
668 to_hex(peerid_hex
, (uint8_t *)ws
->peer_id
);
673 ip_readable
[fmt_ip6c(ip_readable
, (char *)&ws
->peer
)] = 0;
676 ip_readable
[ fmt_ip4( ip_readable
, (char*)&ws
->peer
) ] = 0;
678 syslog(LOG_INFO
, "time=%s event=completed info_hash=%s peer_id=%s ip=%s", timestring
, hash_hex
, peerid_hex
, ip_readable
);
681 ot_overall_completed
++;
684 if (proto
== FLAG_TCP
)
685 ot_overall_tcp_successfulscrapes
++;
687 ot_overall_udp_successfulscrapes
++;
689 case EVENT_FULLSCRAPE
:
690 ot_full_scrape_count
++;
691 ot_full_scrape_size
+= event_data
;
693 case EVENT_FULLSCRAPE_REQUEST
: {
694 ot_ip6
*ip
= (ot_ip6
*)event_data
; /* ugly hack to transfer ip to stats */
696 int off
= snprintf(_debug
, sizeof(_debug
), "[%08d] scrp: ", (unsigned int)(g_now_seconds
- ot_start_time
) / 60);
697 off
+= fmt_ip6c(_debug
+ off
, *ip
);
698 off
+= snprintf(_debug
+ off
, sizeof(_debug
) - off
, " - FULL SCRAPE\n");
699 (void)write(2, _debug
, off
);
700 ot_full_scrape_request_count
++;
702 case EVENT_FULLSCRAPE_REQUEST_GZIP
: {
703 ot_ip6
*ip
= (ot_ip6
*)event_data
; /* ugly hack to transfer ip to stats */
705 int off
= snprintf(_debug
, sizeof(_debug
), "[%08d] scrp: ", (unsigned int)(g_now_seconds
- ot_start_time
) / 60);
706 off
+= fmt_ip6c(_debug
+ off
, *ip
);
707 off
+= snprintf(_debug
+ off
, sizeof(_debug
) - off
, " - FULL SCRAPE\n");
708 (void)write(2, _debug
, off
);
709 ot_full_scrape_request_count
++;
712 ot_failed_request_counts
[event_data
]++;
715 ot_renewed
[event_data
]++;
718 ot_overall_sync_count
+= event_data
;
720 case EVENT_BUCKET_LOCKED
:
721 ot_overall_stall_count
++;
723 #ifdef WANT_SPOT_WOODPECKER
724 case EVENT_WOODPECKER
:
725 pthread_mutex_lock(&g_woodpeckers_mutex
);
726 stat_increase_network_count(&stats_woodpeckers_tree
, 0, event_data
);
727 pthread_mutex_unlock(&g_woodpeckers_mutex
);
730 case EVENT_CONNID_MISSMATCH
:
731 ++ot_overall_udp_connectionidmissmatches
;
737 void stats_cleanup() {
738 #ifdef WANT_SPOT_WOODPECKER
739 pthread_mutex_lock(&g_woodpeckers_mutex
);
740 stats_shift_down_network_count(&stats_woodpeckers_tree
, 0, 1);
741 pthread_mutex_unlock(&g_woodpeckers_mutex
);
745 static void *stats_worker(void *args
) {
747 struct iovec
*iovector
;
752 ot_tasktype tasktype
= TASK_STATS
;
753 ot_taskid taskid
= mutex_workqueue_poptask(&tasktype
);
754 stats_make(&iovec_entries
, &iovector
, tasktype
);
755 if (mutex_workqueue_pushresult(taskid
, iovec_entries
, iovector
))
756 iovec_free(&iovec_entries
, &iovector
);
761 void stats_deliver(int64 sock
, int tasktype
) { mutex_workqueue_pushtask(sock
, tasktype
); }
763 static pthread_t thread_id
;
765 ot_start_time
= g_now_seconds
;
766 pthread_create(&thread_id
, NULL
, stats_worker
, NULL
);
769 void stats_deinit() {
770 pthread_cancel(thread_id
);