summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c188
1 files changed, 95 insertions, 93 deletions
diff --git a/opentracker.c b/opentracker.c
index 96a265a..eb97b42 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -21,10 +21,6 @@
21#include <syslog.h> 21#include <syslog.h>
22#endif 22#endif
23 23
24/* Libowfat */
25#include "io.h"
26#include "iob.h"
27
28/* Opentracker */ 24/* Opentracker */
29#include "ot_accesslist.h" 25#include "ot_accesslist.h"
30#include "ot_config.h" 26#include "ot_config.h"
@@ -35,15 +31,16 @@
35#include "ot_mutex.h" 31#include "ot_mutex.h"
36#include "ot_random.h" 32#include "ot_random.h"
37#include "ot_scan.h" 33#include "ot_scan.h"
34#include "ot_event.h"
35#include "ot_fdstate.h"
38#include "ot_socket.h" 36#include "ot_socket.h"
39#include "ot_stats.h" 37#include "ot_stats.h"
40#include "ot_udp.h" 38#include "ot_udp.h"
41#include "trackerlogic.h" 39#include "trackerlogic.h"
42 40
43/* Globals */ 41/* Globals */
44time_t g_now_seconds;
45uint32_t g_tracker_id; 42uint32_t g_tracker_id;
46volatile int g_opentracker_running = 1; 43_Atomic int g_opentracker_running = 1;
47int g_self_pipe[2]; 44int g_self_pipe[2];
48 45
49 46
@@ -118,25 +115,27 @@ static ssize_t header_complete(char *request, ssize_t byte_count) {
118} 115}
119 116
120static void handle_dead(const int64_t sock) { 117static void handle_dead(const int64_t sock) {
121 struct http_data *cookie = io_getcookie(sock); 118 struct http_data *cookie = fdstate_cookie(sock);
122 if (cookie) { 119 if (cookie) {
123 size_t i; 120 if (cookie->batch)
124 for (i = 0; i < cookie->batches; ++i) 121 batch_reset(cookie->batch);
125 iob_reset(cookie->batch + i);
126 free(cookie->batch); 122 free(cookie->batch);
127 buf_reset(&cookie->request); 123 buf_reset(&cookie->request);
128 if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) 124 if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER))
129 mutex_workqueue_canceltask(sock); 125 mutex_workqueue_canceltask(sock);
130 free(cookie); 126 free(cookie);
131 } 127 }
132 io_close(sock); 128 /* The generation has to move before the kernel can reissue the number */
129 fdstate_close(sock);
130 event_del((int)sock);
131 close((int)sock);
133} 132}
134 133
135static void handle_read(const int64_t sock, struct ot_workstruct *ws) { 134static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
136 struct http_data *cookie = io_getcookie(sock); 135 struct http_data *cookie = fdstate_cookie(sock);
137 ssize_t byte_count = io_tryread(sock, ws->inbuf, G_INBUF_SIZE); 136 ssize_t byte_count = read((int)sock, ws->inbuf, G_INBUF_SIZE);
138 137
139 if (byte_count == 0 || byte_count == -3) { 138 if (byte_count == 0 || (byte_count == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)) {
140 handle_dead(sock); 139 handle_dead(sock);
141 return; 140 return;
142 } 141 }
@@ -177,37 +176,34 @@ static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
177} 176}
178 177
179static void handle_write(const int64_t sock) { 178static void handle_write(const int64_t sock) {
180 struct http_data *cookie = io_getcookie(sock); 179 struct http_data *cookie = fdstate_cookie(sock);
181 size_t i; 180 int chunked = 0;
182 int chunked = 0; 181 int keep_alive = 0;
183 182
184 /* Look for the first io_batch still containing bytes to write */
185 if (cookie) { 183 if (cookie) {
186 if (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) 184 chunked = (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) != 0;
187 chunked = 1; 185 keep_alive = (cookie->flag & STRUCT_HTTP_FLAG_KEEPALIVE) != 0;
188
189 for (i = 0; i < cookie->batches; ++i) {
190 if (cookie->batch[i].bytesleft) {
191 int64_t res = iob_send(sock, cookie->batch + i);
192
193 if (res == -3) {
194 handle_dead(sock);
195 return;
196 }
197
198 if (!cookie->batch[i].bytesleft)
199 continue;
200 186
201 if (res == -1 || res > 0 || i < cookie->batches - 1) 187 if (cookie->batch) {
202 return; 188 if (batch_send(sock, cookie->batch) == BATCH_FAILED) {
189 handle_dead(sock);
190 return;
203 } 191 }
192 if (batch_pending(cookie->batch))
193 return;
204 } 194 }
205 } 195 }
206 196
207 /* In a chunked transfer after all batches accumulated have been sent, wait for the next one */ 197 /* In a chunked transfer, wait for the next piece once everything queued has gone out */
208 if (chunked) 198 if (chunked)
209 io_dontwantwrite(sock); 199 http_interest_drop(sock, cookie, EVENT_OUT);
210 else 200 else if (keep_alive) {
201 /* The reply is out and the client asked to keep the connection, so stop
202 waiting to write and go back to waiting for the next request */
203 http_interest_drop(sock, cookie, EVENT_OUT);
204 http_interest_add(sock, cookie, EVENT_IN);
205 fdstate_set_expiry(sock, time_future_seconds(OT_CLIENT_TIMEOUT));
206 } else
211 handle_dead(sock); 207 handle_dead(sock);
212} 208}
213 209
@@ -216,37 +212,35 @@ static void handle_accept(const int64_t serversocket) {
216 int64_t sock; 212 int64_t sock;
217 ot_ip6 ip; 213 ot_ip6 ip;
218 uint16_t port; 214 uint16_t port;
219 tai6464 t;
220 215
221 while ((sock = socket_accept(serversocket, ip, &port)) != -1) { 216 while ((sock = socket_accept(serversocket, ip, &port)) != -1) {
222 217
223 /* Put fd into a non-blocking mode */ 218 socket_set_blocking((int)sock, 0);
224 io_nonblock(sock);
225 219
226 if (!io_fd(sock) || !(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) { 220 if (!(cookie = (struct http_data *)calloc(1, sizeof(struct http_data)))) {
227 io_close(sock); 221 close((int)sock);
228 continue; 222 continue;
229 } 223 }
230 memset(cookie, 0, sizeof(struct http_data));
231 memcpy(cookie->ip, ip, sizeof(ot_ip6)); 224 memcpy(cookie->ip, ip, sizeof(ot_ip6));
225 cookie->interest = EVENT_IN;
232 226
233 io_setcookie(sock, cookie); 227 if (event_add((int)sock, EVENT_IN, fdstate_open(sock, cookie, time_future_seconds(OT_CLIENT_TIMEOUT))) == -1) {
234 io_wantread(sock); 228 fdstate_close(sock);
229 free(cookie);
230 close((int)sock);
231 continue;
232 }
235 233
236 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip); 234 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
237
238 /* That breaks taia encapsulation. But there is no way to take system
239 time this often in FreeBSD and libowfat does not allow to set unix time */
240 taia_uint(&t, 0); /* Clear t */
241 tai_unix(&(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT));
242 io_timeout(sock, t);
243 } 235 }
244 io_eagain(serversocket);
245} 236}
246 237
238/* How many ready descriptors one wait hands back at a time */
239#define OT_EVENT_BATCH 512
240
247static void *server_mainloop(void *args) { 241static void *server_mainloop(void *args) {
248 struct ot_workstruct ws; 242 struct ot_workstruct ws;
249 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 243 time_t next_timeout_check = time_future_seconds(OT_CLIENT_TIMEOUT_CHECKINTERVAL);
250 struct iovec *iovector; 244 struct iovec *iovector;
251 size_t iovec_entries; 245 size_t iovec_entries;
252 int is_partial; 246 int is_partial;
@@ -266,32 +260,48 @@ static void *server_mainloop(void *args) {
266 random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); 260 random_bytes(ws.rand48_state, sizeof(ws.rand48_state));
267 261
268 for (;;) { 262 for (;;) {
269 int64_t sock; 263 ot_event ready[OT_EVENT_BATCH];
264 int64_t sock;
265 int count, i;
266
267 count = event_wait(ready, OT_EVENT_BATCH, OT_CLIENT_TIMEOUT_CHECKINTERVAL * 1000);
268
269 for (i = 0; i < count; ++i) {
270 const void *cookie;
270 271
271 io_wait(); 272 sock = ready[i].fd;
273 /* A descriptor closed earlier in this same batch may already have been
274 handed out again by accept, so an event is only ours if the
275 generation it was registered under is still the one in place */
276 if (fdstate_generation((int)sock) != ready[i].generation)
277 continue;
278 cookie = fdstate_cookie((int)sock);
272 279
273 while ((sock = io_canread()) != -1) {
274 const void *cookie = io_getcookie(sock);
275 if ((intptr_t)cookie == FLAG_TCP) 280 if ((intptr_t)cookie == FLAG_TCP)
276 handle_accept(sock); 281 handle_accept(sock);
277 else if ((intptr_t)cookie == FLAG_UDP) 282 else if ((intptr_t)cookie == FLAG_UDP)
278 handle_udp6(sock, &ws); 283 handle_udp6(sock, &ws);
279 else if ((intptr_t)cookie == FLAG_SELFPIPE) 284 else if ((intptr_t)cookie == FLAG_SELFPIPE)
280 io_tryread(sock, ws.inbuf, G_INBUF_SIZE); 285 while (read((int)sock, ws.inbuf, G_INBUF_SIZE) > 0)
281 else 286 ;
282 handle_read(sock, &ws); 287 else {
288 if (ready[i].what & EVENT_IN)
289 handle_read(sock, &ws);
290 /* The read may have closed it, so look again before writing */
291 if ((ready[i].what & EVENT_OUT) && fdstate_generation((int)sock) == ready[i].generation)
292 handle_write(sock);
293 }
283 } 294 }
284 295
285 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1) 296 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1)
286 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial); 297 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial);
287 298
288 while ((sock = io_canwrite()) != -1) 299 if (time_now_seconds() > next_timeout_check) {
289 handle_write(sock); 300 int cursor = 0;
290 301
291 if (g_now_seconds > next_timeout_check) { 302 while ((sock = fdstate_next_expired(time_now_seconds(), &cursor)) != -1)
292 while ((sock = io_timeouted()) != -1)
293 handle_dead(sock); 303 handle_dead(sock);
294 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 304 next_timeout_check = time_future_seconds(OT_CLIENT_TIMEOUT_CHECKINTERVAL);
295 } 305 }
296 306
297 livesync_ticker(); 307 livesync_ticker();
@@ -332,11 +342,8 @@ static void listen_bind_one(ot_listen *entry) {
332 panic("socket_udp_bind"); 342 panic("socket_udp_bind");
333 } 343 }
334 344
335 if (!io_fd(entry->sock)) 345 if (event_add((int)entry->sock, EVENT_IN, fdstate_open(entry->sock, (void *)entry->proto, 0)) == -1)
336 panic("io_fd"); 346 panic("event_add");
337
338 io_setcookie(entry->sock, (void *)entry->proto);
339 io_wantread(entry->sock);
340 347
341#ifdef _DEBUG 348#ifdef _DEBUG
342 fputs(" success.\n", stderr); 349 fputs(" success.\n", stderr);
@@ -365,7 +372,8 @@ static void listen_start_udp_workers(void) {
365 if (entry->proto != FLAG_UDP || entry->workers <= 0) 372 if (entry->proto != FLAG_UDP || entry->workers <= 0)
366 continue; 373 continue;
367 374
368 io_block(entry->sock); 375 socket_set_blocking((int)entry->sock, 1);
376 event_del((int)entry->sock);
369 udp_workers_install(entry->sock, (unsigned int)entry->workers); 377 udp_workers_install(entry->sock, (unsigned int)entry->workers);
370 } 378 }
371} 379}
@@ -388,14 +396,14 @@ void load_state(const char *const state_filename) {
388 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) { 396 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) {
389 size_t i; 397 size_t i;
390 398
391 if (!hex_tohash(infohash, inbuf)) 399 if (!hex_to_hash(infohash, inbuf))
392 continue; 400 continue;
393 i = 2 * sizeof(ot_hash); 401 i = 2 * sizeof(ot_hash);
394 402
395 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &base, UINT64_MAX))) 403 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &base, UINT64_MAX)))
396 continue; 404 continue;
397 i += consumed; 405 i += consumed;
398 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &downcount, UINT64_MAX))) 406 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &downcount, UINT64_MAX)))
399 continue; 407 continue;
400 add_torrent_from_saved_state(infohash, base, downcount); 408 add_torrent_from_saved_state(infohash, base, downcount);
401 } 409 }
@@ -451,19 +459,13 @@ int drop_privileges(const char *const serveruser, const char *const serverdir) {
451} 459}
452 460
453/* Maintain our copy of the clock. time() on BSDs is very expensive. */ 461/* Maintain our copy of the clock. time() on BSDs is very expensive. */
454static void *time_caching_worker(void *args) {
455 (void)args;
456 while (1) {
457 g_now_seconds = time(NULL);
458 sleep(5);
459 }
460 return NULL;
461}
462
463int main(int argc, char **argv) { 462int main(int argc, char **argv) {
464 pthread_t thread_id; /* time cacher */
465 463
466 random_init(); 464 random_init();
465 if (fdstate_init() == -1)
466 panic("fdstate_init");
467 if (event_init() == -1)
468 panic("event_init");
467 config_parse(argc, argv); 469 config_parse(argc, argv);
468 470
469 listen_bind_all(); 471 listen_bind_all();
@@ -478,19 +480,17 @@ int main(int argc, char **argv) {
478 if (drop_privileges(g_serveruser ? g_serveruser : "nobody", g_serverdir) == -1) 480 if (drop_privileges(g_serveruser ? g_serveruser : "nobody", g_serverdir) == -1)
479 panic("drop_privileges failed, exiting. Last error"); 481 panic("drop_privileges failed, exiting. Last error");
480 482
481 g_now_seconds = time(NULL);
482 pthread_create(&thread_id, NULL, time_caching_worker, NULL);
483 483
484 /* Create our self pipe which allows us to interrupt mainloops 484 /* Create our self pipe which allows us to interrupt mainloops
485 io_wait in case some data is available to send out */ 485 wait in case some data is available to send out */
486 if (pipe(g_self_pipe) == -1) 486 if (pipe(g_self_pipe) == -1)
487 panic("selfpipe failed: "); 487 panic("selfpipe failed: ");
488 if (!io_fd(g_self_pipe[0])) 488 /* Both ends have to be non blocking: the loop drains the read end until it
489 panic("selfpipe io_fd failed: "); 489 is empty, and a worker nudging a full pipe has already made its point */
490 if (!io_fd(g_self_pipe[1])) 490 socket_set_blocking(g_self_pipe[0], 0);
491 panic("selfpipe io_fd failed: "); 491 socket_set_blocking(g_self_pipe[1], 0);
492 io_setcookie(g_self_pipe[0], (void *)FLAG_SELFPIPE); 492 if (event_add(g_self_pipe[0], EVENT_IN, fdstate_open(g_self_pipe[0], (void *)FLAG_SELFPIPE, 0)) == -1)
493 io_wantread(g_self_pipe[0]); 493 panic("selfpipe event_add");
494 494
495 /* Init all sub systems. This call may fail with an exit() */ 495 /* Init all sub systems. This call may fail with an exit() */
496 trackerlogic_init(); 496 trackerlogic_init();
@@ -510,5 +510,7 @@ int main(int argc, char **argv) {
510 510
511 server_mainloop(0); 511 server_mainloop(0);
512 512
513 event_deinit();
514 fdstate_deinit();
513 return 0; 515 return 0;
514} 516}