summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c123
1 files changed, 72 insertions, 51 deletions
diff --git a/opentracker.c b/opentracker.c
index 50fff29..21eeb42 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -21,9 +21,6 @@
21#include <syslog.h> 21#include <syslog.h>
22#endif 22#endif
23 23
24/* Libowfat */
25#include "io.h"
26
27/* Opentracker */ 24/* Opentracker */
28#include "ot_accesslist.h" 25#include "ot_accesslist.h"
29#include "ot_config.h" 26#include "ot_config.h"
@@ -34,6 +31,8 @@
34#include "ot_mutex.h" 31#include "ot_mutex.h"
35#include "ot_random.h" 32#include "ot_random.h"
36#include "ot_scan.h" 33#include "ot_scan.h"
34#include "ot_event.h"
35#include "ot_fdstate.h"
37#include "ot_socket.h" 36#include "ot_socket.h"
38#include "ot_stats.h" 37#include "ot_stats.h"
39#include "ot_udp.h" 38#include "ot_udp.h"
@@ -117,7 +116,7 @@ static ssize_t header_complete(char *request, ssize_t byte_count) {
117} 116}
118 117
119static void handle_dead(const int64_t sock) { 118static void handle_dead(const int64_t sock) {
120 struct http_data *cookie = io_getcookie(sock); 119 struct http_data *cookie = fdstate_cookie(sock);
121 if (cookie) { 120 if (cookie) {
122 if (cookie->batch) 121 if (cookie->batch)
123 batch_reset(cookie->batch); 122 batch_reset(cookie->batch);
@@ -127,14 +126,17 @@ static void handle_dead(const int64_t sock) {
127 mutex_workqueue_canceltask(sock); 126 mutex_workqueue_canceltask(sock);
128 free(cookie); 127 free(cookie);
129 } 128 }
130 io_close(sock); 129 /* The generation has to move before the kernel can reissue the number */
130 fdstate_close(sock);
131 event_del((int)sock);
132 close((int)sock);
131} 133}
132 134
133static void handle_read(const int64_t sock, struct ot_workstruct *ws) { 135static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
134 struct http_data *cookie = io_getcookie(sock); 136 struct http_data *cookie = fdstate_cookie(sock);
135 ssize_t byte_count = io_tryread(sock, ws->inbuf, G_INBUF_SIZE); 137 ssize_t byte_count = read((int)sock, ws->inbuf, G_INBUF_SIZE);
136 138
137 if (byte_count == 0 || byte_count == -3) { 139 if (byte_count == 0 || (byte_count == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)) {
138 handle_dead(sock); 140 handle_dead(sock);
139 return; 141 return;
140 } 142 }
@@ -175,7 +177,7 @@ static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
175} 177}
176 178
177static void handle_write(const int64_t sock) { 179static void handle_write(const int64_t sock) {
178 struct http_data *cookie = io_getcookie(sock); 180 struct http_data *cookie = fdstate_cookie(sock);
179 int chunked = 0; 181 int chunked = 0;
180 182
181 if (cookie) { 183 if (cookie) {
@@ -194,7 +196,7 @@ static void handle_write(const int64_t sock) {
194 196
195 /* In a chunked transfer, wait for the next piece once everything queued has gone out */ 197 /* In a chunked transfer, wait for the next piece once everything queued has gone out */
196 if (chunked) 198 if (chunked)
197 io_dontwantwrite(sock); 199 http_interest_drop(sock, cookie, EVENT_OUT);
198 else 200 else
199 handle_dead(sock); 201 handle_dead(sock);
200} 202}
@@ -204,34 +206,33 @@ static void handle_accept(const int64_t serversocket) {
204 int64_t sock; 206 int64_t sock;
205 ot_ip6 ip; 207 ot_ip6 ip;
206 uint16_t port; 208 uint16_t port;
207 tai6464 t;
208 209
209 while ((sock = socket_accept(serversocket, ip, &port)) != -1) { 210 while ((sock = socket_accept(serversocket, ip, &port)) != -1) {
210 211
211 /* Put fd into a non-blocking mode */ 212 socket_set_blocking((int)sock, 0);
212 io_nonblock(sock);
213 213
214 if (!io_fd(sock) || !(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) { 214 if (!(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) {
215 io_close(sock); 215 close((int)sock);
216 continue; 216 continue;
217 } 217 }
218 memset(cookie, 0, sizeof(struct http_data)); 218 memset(cookie, 0, sizeof(struct http_data));
219 memcpy(cookie->ip, ip, sizeof(ot_ip6)); 219 memcpy(cookie->ip, ip, sizeof(ot_ip6));
220 cookie->interest = EVENT_IN;
220 221
221 io_setcookie(sock, cookie); 222 if (event_add((int)sock, EVENT_IN, fdstate_open(sock, cookie, g_now_seconds + OT_CLIENT_TIMEOUT)) == -1) {
222 io_wantread(sock); 223 fdstate_close(sock);
224 free(cookie);
225 close((int)sock);
226 continue;
227 }
223 228
224 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip); 229 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
225
226 /* That breaks taia encapsulation. But there is no way to take system
227 time this often in FreeBSD and libowfat does not allow to set unix time */
228 taia_uint(&t, 0); /* Clear t */
229 tai_unix(&(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT));
230 io_timeout(sock, t);
231 } 230 }
232 io_eagain(serversocket);
233} 231}
234 232
233/* How many ready descriptors one wait hands back at a time */
234#define OT_EVENT_BATCH 512
235
235static void *server_mainloop(void *args) { 236static void *server_mainloop(void *args) {
236 struct ot_workstruct ws; 237 struct ot_workstruct ws;
237 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 238 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
@@ -254,30 +255,46 @@ static void *server_mainloop(void *args) {
254 random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); 255 random_bytes(ws.rand48_state, sizeof(ws.rand48_state));
255 256
256 for (;;) { 257 for (;;) {
257 int64_t sock; 258 ot_event ready[OT_EVENT_BATCH];
259 int64_t sock;
260 int count, i;
261
262 count = event_wait(ready, OT_EVENT_BATCH, OT_CLIENT_TIMEOUT_CHECKINTERVAL * 1000);
258 263
259 io_wait(); 264 for (i = 0; i < count; ++i) {
265 const void *cookie;
266
267 sock = ready[i].fd;
268 /* A descriptor closed earlier in this same batch may already have been
269 handed out again by accept, so an event is only ours if the
270 generation it was registered under is still the one in place */
271 if (fdstate_generation((int)sock) != ready[i].generation)
272 continue;
273 cookie = fdstate_cookie((int)sock);
260 274
261 while ((sock = io_canread()) != -1) {
262 const void *cookie = io_getcookie(sock);
263 if ((intptr_t)cookie == FLAG_TCP) 275 if ((intptr_t)cookie == FLAG_TCP)
264 handle_accept(sock); 276 handle_accept(sock);
265 else if ((intptr_t)cookie == FLAG_UDP) 277 else if ((intptr_t)cookie == FLAG_UDP)
266 handle_udp6(sock, &ws); 278 handle_udp6(sock, &ws);
267 else if ((intptr_t)cookie == FLAG_SELFPIPE) 279 else if ((intptr_t)cookie == FLAG_SELFPIPE)
268 io_tryread(sock, ws.inbuf, G_INBUF_SIZE); 280 while (read((int)sock, ws.inbuf, G_INBUF_SIZE) > 0)
269 else 281 ;
270 handle_read(sock, &ws); 282 else {
283 if (ready[i].what & EVENT_IN)
284 handle_read(sock, &ws);
285 /* The read may have closed it, so look again before writing */
286 if ((ready[i].what & EVENT_OUT) && fdstate_generation((int)sock) == ready[i].generation)
287 handle_write(sock);
288 }
271 } 289 }
272 290
273 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1) 291 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1)
274 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial); 292 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial);
275 293
276 while ((sock = io_canwrite()) != -1)
277 handle_write(sock);
278
279 if (g_now_seconds > next_timeout_check) { 294 if (g_now_seconds > next_timeout_check) {
280 while ((sock = io_timeouted()) != -1) 295 int cursor = 0;
296
297 while ((sock = fdstate_next_expired(g_now_seconds, &cursor)) != -1)
281 handle_dead(sock); 298 handle_dead(sock);
282 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 299 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
283 } 300 }
@@ -320,11 +337,8 @@ static void listen_bind_one(ot_listen *entry) {
320 panic("socket_udp_bind"); 337 panic("socket_udp_bind");
321 } 338 }
322 339
323 if (!io_fd(entry->sock)) 340 if (event_add((int)entry->sock, EVENT_IN, fdstate_open(entry->sock, (void *)entry->proto, 0)) == -1)
324 panic("io_fd"); 341 panic("event_add");
325
326 io_setcookie(entry->sock, (void *)entry->proto);
327 io_wantread(entry->sock);
328 342
329#ifdef _DEBUG 343#ifdef _DEBUG
330 fputs(" success.\n", stderr); 344 fputs(" success.\n", stderr);
@@ -353,7 +367,8 @@ static void listen_start_udp_workers(void) {
353 if (entry->proto != FLAG_UDP || entry->workers <= 0) 367 if (entry->proto != FLAG_UDP || entry->workers <= 0)
354 continue; 368 continue;
355 369
356 io_block(entry->sock); 370 socket_set_blocking((int)entry->sock, 1);
371 event_del((int)entry->sock);
357 udp_workers_install(entry->sock, (unsigned int)entry->workers); 372 udp_workers_install(entry->sock, (unsigned int)entry->workers);
358 } 373 }
359} 374}
@@ -376,14 +391,14 @@ void load_state(const char *const state_filename) {
376 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) { 391 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) {
377 size_t i; 392 size_t i;
378 393
379 if (!hex_tohash(infohash, inbuf)) 394 if (!hex_to_hash(infohash, inbuf))
380 continue; 395 continue;
381 i = 2 * sizeof(ot_hash); 396 i = 2 * sizeof(ot_hash);
382 397
383 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &base, UINT64_MAX))) 398 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &base, UINT64_MAX)))
384 continue; 399 continue;
385 i += consumed; 400 i += consumed;
386 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &downcount, UINT64_MAX))) 401 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &downcount, UINT64_MAX)))
387 continue; 402 continue;
388 add_torrent_from_saved_state(infohash, base, downcount); 403 add_torrent_from_saved_state(infohash, base, downcount);
389 } 404 }
@@ -452,6 +467,10 @@ int main(int argc, char **argv) {
452 pthread_t thread_id; /* time cacher */ 467 pthread_t thread_id; /* time cacher */
453 468
454 random_init(); 469 random_init();
470 if (fdstate_init() == -1)
471 panic("fdstate_init");
472 if (event_init() == -1)
473 panic("event_init");
455 config_parse(argc, argv); 474 config_parse(argc, argv);
456 475
457 listen_bind_all(); 476 listen_bind_all();
@@ -470,15 +489,15 @@ int main(int argc, char **argv) {
470 pthread_create(&thread_id, NULL, time_caching_worker, NULL); 489 pthread_create(&thread_id, NULL, time_caching_worker, NULL);
471 490
472 /* Create our self pipe which allows us to interrupt mainloops 491 /* Create our self pipe which allows us to interrupt mainloops
473 io_wait in case some data is available to send out */ 492 wait in case some data is available to send out */
474 if (pipe(g_self_pipe) == -1) 493 if (pipe(g_self_pipe) == -1)
475 panic("selfpipe failed: "); 494 panic("selfpipe failed: ");
476 if (!io_fd(g_self_pipe[0])) 495 /* Both ends have to be non blocking: the loop drains the read end until it
477 panic("selfpipe io_fd failed: "); 496 is empty, and a worker nudging a full pipe has already made its point */
478 if (!io_fd(g_self_pipe[1])) 497 socket_set_blocking(g_self_pipe[0], 0);
479 panic("selfpipe io_fd failed: "); 498 socket_set_blocking(g_self_pipe[1], 0);
480 io_setcookie(g_self_pipe[0], (void *)FLAG_SELFPIPE); 499 if (event_add(g_self_pipe[0], EVENT_IN, fdstate_open(g_self_pipe[0], (void *)FLAG_SELFPIPE, 0)) == -1)
481 io_wantread(g_self_pipe[0]); 500 panic("selfpipe event_add");
482 501
483 /* Init all sub systems. This call may fail with an exit() */ 502 /* Init all sub systems. This call may fail with an exit() */
484 trackerlogic_init(); 503 trackerlogic_init();
@@ -498,5 +517,7 @@ int main(int argc, char **argv) {
498 517
499 server_mainloop(0); 518 server_mainloop(0);
500 519
520 event_deinit();
521 fdstate_deinit();
501 return 0; 522 return 0;
502} 523}