summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c134
1 files changed, 83 insertions, 51 deletions
diff --git a/opentracker.c b/opentracker.c
index 60bdceb..11da486 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,8 +31,9 @@
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_timeout.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"
@@ -118,7 +116,7 @@ static ssize_t header_complete(char *request, ssize_t byte_count) {
118} 116}
119 117
120static void handle_dead(const int64_t sock) { 118static void handle_dead(const int64_t sock) {
121 struct http_data *cookie = io_getcookie(sock); 119 struct http_data *cookie = fdstate_cookie(sock);
122 if (cookie) { 120 if (cookie) {
123 if (cookie->batch) 121 if (cookie->batch)
124 batch_reset(cookie->batch); 122 batch_reset(cookie->batch);
@@ -128,14 +126,17 @@ static void handle_dead(const int64_t sock) {
128 mutex_workqueue_canceltask(sock); 126 mutex_workqueue_canceltask(sock);
129 free(cookie); 127 free(cookie);
130 } 128 }
131 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);
132} 133}
133 134
134static void handle_read(const int64_t sock, struct ot_workstruct *ws) { 135static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
135 struct http_data *cookie = io_getcookie(sock); 136 struct http_data *cookie = fdstate_cookie(sock);
136 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);
137 138
138 if (byte_count == 0 || byte_count == -3) { 139 if (byte_count == 0 || (byte_count == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)) {
139 handle_dead(sock); 140 handle_dead(sock);
140 return; 141 return;
141 } 142 }
@@ -176,12 +177,13 @@ static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
176} 177}
177 178
178static void handle_write(const int64_t sock) { 179static void handle_write(const int64_t sock) {
179 struct http_data *cookie = io_getcookie(sock); 180 struct http_data *cookie = fdstate_cookie(sock);
180 int chunked = 0; 181 int chunked = 0;
182 int keep_alive = 0;
181 183
182 if (cookie) { 184 if (cookie) {
183 if (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) 185 chunked = (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) != 0;
184 chunked = 1; 186 keep_alive = (cookie->flag & STRUCT_HTTP_FLAG_KEEPALIVE) != 0;
185 187
186 if (cookie->batch) { 188 if (cookie->batch) {
187 if (batch_send(sock, cookie->batch) == BATCH_FAILED) { 189 if (batch_send(sock, cookie->batch) == BATCH_FAILED) {
@@ -195,8 +197,14 @@ static void handle_write(const int64_t sock) {
195 197
196 /* In a chunked transfer, wait for the next piece once everything queued has gone out */ 198 /* In a chunked transfer, wait for the next piece once everything queued has gone out */
197 if (chunked) 199 if (chunked)
198 io_dontwantwrite(sock); 200 http_interest_drop(sock, cookie, EVENT_OUT);
199 else 201 else if (keep_alive) {
202 /* The reply is out and the client asked to keep the connection, so stop
203 waiting to write and go back to waiting for the next request */
204 http_interest_drop(sock, cookie, EVENT_OUT);
205 http_interest_add(sock, cookie, EVENT_IN);
206 fdstate_set_expiry(sock, g_now_seconds + OT_CLIENT_TIMEOUT);
207 } else
200 handle_dead(sock); 208 handle_dead(sock);
201} 209}
202 210
@@ -208,26 +216,30 @@ static void handle_accept(const int64_t serversocket) {
208 216
209 while ((sock = socket_accept(serversocket, ip, &port)) != -1) { 217 while ((sock = socket_accept(serversocket, ip, &port)) != -1) {
210 218
211 /* Put fd into a non-blocking mode */ 219 socket_set_blocking((int)sock, 0);
212 io_nonblock(sock);
213 220
214 if (!io_fd(sock) || !(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) { 221 if (!(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) {
215 io_close(sock); 222 close((int)sock);
216 continue; 223 continue;
217 } 224 }
218 memset(cookie, 0, sizeof(struct http_data)); 225 memset(cookie, 0, sizeof(struct http_data));
219 memcpy(cookie->ip, ip, sizeof(ot_ip6)); 226 memcpy(cookie->ip, ip, sizeof(ot_ip6));
227 cookie->interest = EVENT_IN;
220 228
221 io_setcookie(sock, cookie); 229 if (event_add((int)sock, EVENT_IN, fdstate_open(sock, cookie, g_now_seconds + OT_CLIENT_TIMEOUT)) == -1) {
222 io_wantread(sock); 230 fdstate_close(sock);
231 free(cookie);
232 close((int)sock);
233 continue;
234 }
223 235
224 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip); 236 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
225
226 timeout_in(sock, OT_CLIENT_TIMEOUT);
227 } 237 }
228 io_eagain(serversocket);
229} 238}
230 239
240/* How many ready descriptors one wait hands back at a time */
241#define OT_EVENT_BATCH 512
242
231static void *server_mainloop(void *args) { 243static void *server_mainloop(void *args) {
232 struct ot_workstruct ws; 244 struct ot_workstruct ws;
233 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 245 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
@@ -250,30 +262,46 @@ static void *server_mainloop(void *args) {
250 random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); 262 random_bytes(ws.rand48_state, sizeof(ws.rand48_state));
251 263
252 for (;;) { 264 for (;;) {
253 int64_t sock; 265 ot_event ready[OT_EVENT_BATCH];
266 int64_t sock;
267 int count, i;
268
269 count = event_wait(ready, OT_EVENT_BATCH, OT_CLIENT_TIMEOUT_CHECKINTERVAL * 1000);
254 270
255 io_wait(); 271 for (i = 0; i < count; ++i) {
272 const void *cookie;
273
274 sock = ready[i].fd;
275 /* A descriptor closed earlier in this same batch may already have been
276 handed out again by accept, so an event is only ours if the
277 generation it was registered under is still the one in place */
278 if (fdstate_generation((int)sock) != ready[i].generation)
279 continue;
280 cookie = fdstate_cookie((int)sock);
256 281
257 while ((sock = io_canread()) != -1) {
258 const void *cookie = io_getcookie(sock);
259 if ((intptr_t)cookie == FLAG_TCP) 282 if ((intptr_t)cookie == FLAG_TCP)
260 handle_accept(sock); 283 handle_accept(sock);
261 else if ((intptr_t)cookie == FLAG_UDP) 284 else if ((intptr_t)cookie == FLAG_UDP)
262 handle_udp6(sock, &ws); 285 handle_udp6(sock, &ws);
263 else if ((intptr_t)cookie == FLAG_SELFPIPE) 286 else if ((intptr_t)cookie == FLAG_SELFPIPE)
264 io_tryread(sock, ws.inbuf, G_INBUF_SIZE); 287 while (read((int)sock, ws.inbuf, G_INBUF_SIZE) > 0)
265 else 288 ;
266 handle_read(sock, &ws); 289 else {
290 if (ready[i].what & EVENT_IN)
291 handle_read(sock, &ws);
292 /* The read may have closed it, so look again before writing */
293 if ((ready[i].what & EVENT_OUT) && fdstate_generation((int)sock) == ready[i].generation)
294 handle_write(sock);
295 }
267 } 296 }
268 297
269 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1) 298 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1)
270 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial); 299 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial);
271 300
272 while ((sock = io_canwrite()) != -1)
273 handle_write(sock);
274
275 if (g_now_seconds > next_timeout_check) { 301 if (g_now_seconds > next_timeout_check) {
276 while ((sock = io_timeouted()) != -1) 302 int cursor = 0;
303
304 while ((sock = fdstate_next_expired(g_now_seconds, &cursor)) != -1)
277 handle_dead(sock); 305 handle_dead(sock);
278 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 306 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
279 } 307 }
@@ -316,11 +344,8 @@ static void listen_bind_one(ot_listen *entry) {
316 panic("socket_udp_bind"); 344 panic("socket_udp_bind");
317 } 345 }
318 346
319 if (!io_fd(entry->sock)) 347 if (event_add((int)entry->sock, EVENT_IN, fdstate_open(entry->sock, (void *)entry->proto, 0)) == -1)
320 panic("io_fd"); 348 panic("event_add");
321
322 io_setcookie(entry->sock, (void *)entry->proto);
323 io_wantread(entry->sock);
324 349
325#ifdef _DEBUG 350#ifdef _DEBUG
326 fputs(" success.\n", stderr); 351 fputs(" success.\n", stderr);
@@ -349,7 +374,8 @@ static void listen_start_udp_workers(void) {
349 if (entry->proto != FLAG_UDP || entry->workers <= 0) 374 if (entry->proto != FLAG_UDP || entry->workers <= 0)
350 continue; 375 continue;
351 376
352 io_block(entry->sock); 377 socket_set_blocking((int)entry->sock, 1);
378 event_del((int)entry->sock);
353 udp_workers_install(entry->sock, (unsigned int)entry->workers); 379 udp_workers_install(entry->sock, (unsigned int)entry->workers);
354 } 380 }
355} 381}
@@ -372,14 +398,14 @@ void load_state(const char *const state_filename) {
372 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) { 398 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) {
373 size_t i; 399 size_t i;
374 400
375 if (!hex_tohash(infohash, inbuf)) 401 if (!hex_to_hash(infohash, inbuf))
376 continue; 402 continue;
377 i = 2 * sizeof(ot_hash); 403 i = 2 * sizeof(ot_hash);
378 404
379 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &base, UINT64_MAX))) 405 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &base, UINT64_MAX)))
380 continue; 406 continue;
381 i += consumed; 407 i += consumed;
382 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &downcount, UINT64_MAX))) 408 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &downcount, UINT64_MAX)))
383 continue; 409 continue;
384 add_torrent_from_saved_state(infohash, base, downcount); 410 add_torrent_from_saved_state(infohash, base, downcount);
385 } 411 }
@@ -448,6 +474,10 @@ int main(int argc, char **argv) {
448 pthread_t thread_id; /* time cacher */ 474 pthread_t thread_id; /* time cacher */
449 475
450 random_init(); 476 random_init();
477 if (fdstate_init() == -1)
478 panic("fdstate_init");
479 if (event_init() == -1)
480 panic("event_init");
451 config_parse(argc, argv); 481 config_parse(argc, argv);
452 482
453 listen_bind_all(); 483 listen_bind_all();
@@ -466,15 +496,15 @@ int main(int argc, char **argv) {
466 pthread_create(&thread_id, NULL, time_caching_worker, NULL); 496 pthread_create(&thread_id, NULL, time_caching_worker, NULL);
467 497
468 /* Create our self pipe which allows us to interrupt mainloops 498 /* Create our self pipe which allows us to interrupt mainloops
469 io_wait in case some data is available to send out */ 499 wait in case some data is available to send out */
470 if (pipe(g_self_pipe) == -1) 500 if (pipe(g_self_pipe) == -1)
471 panic("selfpipe failed: "); 501 panic("selfpipe failed: ");
472 if (!io_fd(g_self_pipe[0])) 502 /* Both ends have to be non blocking: the loop drains the read end until it
473 panic("selfpipe io_fd failed: "); 503 is empty, and a worker nudging a full pipe has already made its point */
474 if (!io_fd(g_self_pipe[1])) 504 socket_set_blocking(g_self_pipe[0], 0);
475 panic("selfpipe io_fd failed: "); 505 socket_set_blocking(g_self_pipe[1], 0);
476 io_setcookie(g_self_pipe[0], (void *)FLAG_SELFPIPE); 506 if (event_add(g_self_pipe[0], EVENT_IN, fdstate_open(g_self_pipe[0], (void *)FLAG_SELFPIPE, 0)) == -1)
477 io_wantread(g_self_pipe[0]); 507 panic("selfpipe event_add");
478 508
479 /* Init all sub systems. This call may fail with an exit() */ 509 /* Init all sub systems. This call may fail with an exit() */
480 trackerlogic_init(); 510 trackerlogic_init();
@@ -494,5 +524,7 @@ int main(int argc, char **argv) {
494 524
495 server_mainloop(0); 525 server_mainloop(0);
496 526
527 event_deinit();
528 fdstate_deinit();
497 return 0; 529 return 0;
498} 530}