summaryrefslogtreecommitdiff
path: root/src/trackerlogic.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/trackerlogic.h')
-rw-r--r--src/trackerlogic.h283
1 files changed, 283 insertions, 0 deletions
diff --git a/src/trackerlogic.h b/src/trackerlogic.h
new file mode 100644
index 0000000..7292d36
--- /dev/null
+++ b/src/trackerlogic.h
@@ -0,0 +1,283 @@
1/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever. */
3
4#ifndef OT_TRACKERLOGIC_H__
5#define OT_TRACKERLOGIC_H__
6
7#include <signal.h>
8#include <stdatomic.h>
9#include <stdint.h>
10#include <stdlib.h>
11#include <sys/time.h>
12#include <sys/types.h>
13#include <time.h>
14
15typedef uint8_t ot_hash[20];
16typedef time_t ot_time;
17typedef char ot_ip6[16];
18typedef struct {
19 ot_ip6 address;
20 int bits;
21} ot_net;
22/* List of peers should fit in a single UDP packet (around 1200 bytes) */
23#define OT_MAX_PEERS_UDP6 66
24#define OT_MAX_PEERS_UDP4 200
25
26#define OT_IP_SIZE6 16
27#define OT_IP_SIZE4 4
28#define OT_PORT_SIZE 2
29#define OT_FLAG_SIZE 1
30#define OT_TIME_SIZE 1
31
32/* Some tracker behaviour tunable */
33#ifndef OT_CLIENT_TIMEOUT
34#define OT_CLIENT_TIMEOUT 30
35#endif
36#ifndef OT_CLIENT_TIMEOUT_CHECKINTERVAL
37#define OT_CLIENT_TIMEOUT_CHECKINTERVAL 10
38#endif
39#define OT_CLIENT_TIMEOUT_SEND (60 * 15)
40#define OT_CLIENT_REQUEST_INTERVAL (60 * 30)
41#define OT_CLIENT_REQUEST_VARIATION (60 * 6)
42
43#define OT_TORRENT_TIMEOUT_HOURS 24
44#define OT_TORRENT_TIMEOUT (60 * OT_TORRENT_TIMEOUT_HOURS)
45
46#define OT_CLIENT_REQUEST_INTERVAL_RANDOM \
47 (OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION / 2 + (int)(nrand48(ws->rand48_state) % OT_CLIENT_REQUEST_VARIATION))
48
49/* If WANT_MODEST_FULLSCRAPES is on, ip addresses may not
50 fullscrape more frequently than this amount in seconds */
51#define OT_MODEST_PEER_TIMEOUT (60 * 5)
52
53/* If peers come back before 10 minutes, don't live sync them */
54#define OT_CLIENT_SYNC_RENEW_BOUNDARY 10
55
56/* Number of tracker admin ip addresses allowed */
57#define OT_ADMINIP_MAX 64
58#define OT_MAX_THREADS 64
59
60/* Number of minutes after announce before peer is removed */
61#define OT_PEER_TIMEOUT 45
62
63/* We maintain a list of 1024 pointers to sorted list of ot_torrent structs
64 Sort key is, of course, its hash */
65/* Set from the Makefile, 8 to 16. More buckets means shorter vectors and a
66 cheaper insert, which only pays for a tracker carrying millions of
67 torrents; see DESIGN. */
68#ifndef OT_BUCKET_COUNT_BITS
69#define OT_BUCKET_COUNT_BITS 10
70#endif
71
72#define OT_BUCKET_COUNT (1 << OT_BUCKET_COUNT_BITS)
73#define OT_BUCKET_COUNT_SHIFT (32 - OT_BUCKET_COUNT_BITS)
74
75/* if _DEBUG_RANDOMTORRENTS is set, this is the amount of torrents to create
76 on startup */
77#define RANDOMTORRENTS (1024 * 1024 * 1)
78
79#if defined(CLOCK_REALTIME_COARSE)
80#define OT_CLOCK_CHEAP CLOCK_REALTIME_COARSE /* Linux */
81#elif defined(CLOCK_REALTIME_FAST)
82#define OT_CLOCK_CHEAP CLOCK_REALTIME_FAST /* the BSDs */
83#else
84#define OT_CLOCK_CHEAP CLOCK_REALTIME /* macOS and whatever else */
85#endif
86
87static inline ot_time time_now_seconds(void) {
88 struct timespec now;
89 clock_gettime(OT_CLOCK_CHEAP, &now);
90 return (ot_time)now.tv_sec;
91}
92
93static inline ot_time time_now_minutes(void) { return time_now_seconds() / 60; }
94
95/* For the deadlines the tracker sets on itself, which read better as the
96 span they allow than as an addition to the current second */
97static inline ot_time time_future_seconds(int span) { return time_now_seconds() + span; }
98/* Cleared from the interrupt handler and read by every worker */
99extern _Atomic int g_opentracker_running;
100
101/* Sent to a thread parked in a blocking read */
102#define OT_SIGNAL_WAKE SIGUSR1
103
104
105extern uint32_t g_tracker_id;
106typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG;
107
108#define OT_PEER_COMPARE_SIZE6 ((OT_IP_SIZE6) + (OT_PORT_SIZE))
109#define OT_PEER_COMPARE_SIZE4 ((OT_IP_SIZE4) + (OT_PORT_SIZE))
110#define OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(PEER_SIZE) ((PEER_SIZE) - (OT_TIME_SIZE) - (OT_FLAG_SIZE))
111
112#define OT_PEER_SIZE6 ((OT_TIME_SIZE) + (OT_FLAG_SIZE) + (OT_PEER_COMPARE_SIZE6))
113#define OT_PEER_SIZE4 ((OT_TIME_SIZE) + (OT_FLAG_SIZE) + (OT_PEER_COMPARE_SIZE4))
114
115typedef uint8_t ot_peer; /* Generic pointer to a v6 or v4 peer */
116typedef uint8_t ot_peer6[OT_PEER_SIZE6];
117typedef uint8_t ot_peer4[OT_PEER_SIZE4];
118static const uint8_t PEER_FLAG_SEEDING = 0x80;
119static const uint8_t PEER_FLAG_COMPLETED = 0x40;
120static const uint8_t PEER_FLAG_STOPPED = 0x20;
121static const uint8_t PEER_FLAG_FROM_SYNC = 0x10;
122static const uint8_t PEER_FLAG_LEECHING = 0x00;
123
124/* Takes an ot_peer6 and returns the proper pointer to the peer and sets peer_size */
125ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size);
126size_t peer_size_from_peer6(ot_peer6 *peer);
127
128/* New style */
129#define OT_SETIP(peer, ip) memcpy((uint8_t *)(peer), (ip), OT_IP_SIZE6)
130#define OT_SETPORT(peer, port) memcpy(((uint8_t *)(peer)) + (OT_IP_SIZE6), (port), 2)
131#define OT_PEERFLAG(peer) (((uint8_t *)(peer))[(OT_IP_SIZE6) + 2])
132#define OT_PEERFLAG_D(peer, peersize) (((uint8_t *)(peer))[(peersize) - 2])
133#define OT_PEERTIME(peer, peersize) (((uint8_t *)(peer))[(peersize) - 1])
134
135#define PEERS_BENCODED6 "6:peers6"
136#define PEERS_BENCODED4 "5:peers"
137
138#define OT_HASH_COMPARE_SIZE (sizeof(ot_hash))
139
140struct ot_peerlist;
141typedef struct ot_peerlist ot_peerlist;
142typedef struct {
143 ot_hash hash;
144 ot_peerlist *peer_list6;
145 ot_peerlist *peer_list4;
146} ot_torrent;
147
148#include "ot_vector.h"
149
150struct ot_peerlist {
151 ot_time base;
152 size_t seed_count;
153 size_t peer_count;
154 size_t down_count;
155 /* normal peers vector or
156 pointer to ot_vector[32] buckets if data != NULL and space == 0
157 */
158 ot_vector peers;
159};
160#define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list)->peers.size > (peer_list)->peers.space)
161
162/* The http replies the tracker counts when it has to refuse a request. */
163enum {
164 CODE_HTTPERROR_302,
165 CODE_HTTPERROR_400,
166 CODE_HTTPERROR_400_PARAM,
167 CODE_HTTPERROR_400_COMPACT,
168 CODE_HTTPERROR_402_NOTMODEST,
169 CODE_HTTPERROR_402_PAYMENT_REQUIRED,
170 CODE_HTTPERROR_403_IP,
171 CODE_HTTPERROR_404,
172 CODE_HTTPERROR_500,
173
174 CODE_HTTPERROR_COUNT
175};
176
177/* One statistic. Used when workers report stats to their workstruct */
178typedef _Atomic unsigned long long ot_counter;
179
180/* What each thread counts for itself. The two runs at the end are indexed by
181 the http error code and by the age in minutes of a renewed peer */
182typedef enum {
183 OT_COUNTER_TCP_CONNECTIONS,
184 OT_COUNTER_UDP_CONNECTIONS,
185 OT_COUNTER_TCP_ANNOUNCES,
186 OT_COUNTER_UDP_ANNOUNCES,
187 OT_COUNTER_TCP_SCRAPES,
188 OT_COUNTER_UDP_SCRAPES,
189 OT_COUNTER_TCP_CONNECTS,
190 OT_COUNTER_UDP_CONNECTS,
191 OT_COUNTER_UDP_CONNID_MISSMATCH,
192 OT_COUNTER_COMPLETED,
193 OT_COUNTER_FULLSCRAPES,
194 OT_COUNTER_FULLSCRAPE_REQUESTS,
195 OT_COUNTER_FULLSCRAPE_BYTES,
196 OT_COUNTER_SYNCS,
197 OT_COUNTER_STALLS,
198
199 OT_COUNTER_FAILED, /* CODE_HTTPERROR_COUNT of them */
200 OT_COUNTER_RENEWED = OT_COUNTER_FAILED + CODE_HTTPERROR_COUNT, /* OT_PEER_TIMEOUT of them */
201
202 OT_COUNTER_COUNT = OT_COUNTER_RENEWED + OT_PEER_TIMEOUT
203} ot_counter_index;
204
205struct ot_workstruct {
206 /* Thread specific, static */
207
208 /* This thread's own statistics, and the link ot_stats keeps them on */
209 ot_counter counters[OT_COUNTER_COUNT];
210 struct ot_workstruct *counters_next;
211
212 char *inbuf;
213#define G_INBUF_SIZE 8192
214 char *outbuf;
215#define G_OUTBUF_SIZE 8192
216#ifdef _DEBUG_HTTPERROR
217 char *debugbuf;
218#define G_DEBUGBUF_SIZE 8192
219#endif
220
221 /* The peer currently in the working */
222 ot_peer6 peer; /* Can fit v6 and v4 peers */
223
224 /* Pointers into the request buffer */
225 ot_hash *hash;
226 char *peer_id;
227
228 /* HTTP specific, non static */
229 char *request;
230 ssize_t request_size;
231 ssize_t header_size;
232 char *reply;
233 ssize_t reply_size;
234
235 /* Entropy state for rand48 function so that threads don't need to acquire mutexes for
236 global random() or arc4random() state, which causes heavy load on linuxes */
237 uint16_t rand48_state[3];
238
239 int keep_alive;
240};
241
242/* Everything a thread that serves requests needs for itself. Set up and torn
243 down in one place so that a new kind of worker cannot miss a piece.
244 Returns -1 if the buffers could not be had. */
245int workstruct_init(struct ot_workstruct *ws);
246void workstruct_deinit(struct ot_workstruct *ws);
247
248/*
249 Exported functions
250*/
251
252#ifdef WANT_SYNC_LIVE
253#define WANT_SYNC
254#endif
255
256#ifdef WANT_SYNC
257#define WANT_SYNC_PARAM(param) , param
258#else
259#define WANT_SYNC_PARAM(param)
260#endif
261
262void trackerlogic_init(void);
263void trackerlogic_deinit(void);
264void exerr(const char *message);
265
266/* add_peer_to_torrent does only release the torrent bucket if from_sync is set,
267 otherwise it is released in return_peers_for_torrent */
268size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount);
269size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws);
270void return_tcp_scrape_for_torrent(ot_hash const *hash_list, size_t amount, char **reply, const char *reply_end);
271size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply);
272void add_torrent_from_saved_state(ot_hash const hash, ot_time base, size_t down_count);
273#ifdef _DEBUG_RANDOMTORRENTS
274void trackerlogic_add_random_torrents(size_t amount);
275#endif
276
277/* torrent iterator */
278void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), uintptr_t data);
279
280/* Helper, before it moves to its own object */
281void free_peerlist(ot_peerlist *peer_list);
282
283#endif