summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c118
1 files changed, 72 insertions, 46 deletions
diff --git a/opentracker.c b/opentracker.c
index 0f0b314..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,6 +31,7 @@
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"
37#include "ot_fdstate.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"
@@ -130,14 +128,15 @@ static void handle_dead(const int64_t sock) {
130 } 128 }
131 /* The generation has to move before the kernel can reissue the number */ 129 /* The generation has to move before the kernel can reissue the number */
132 fdstate_close(sock); 130 fdstate_close(sock);
133 io_close(sock); 131 event_del((int)sock);
132 close((int)sock);
134} 133}
135 134
136static void handle_read(const int64_t sock, struct ot_workstruct *ws) { 135static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
137 struct http_data *cookie = fdstate_cookie(sock); 136 struct http_data *cookie = fdstate_cookie(sock);
138 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);
139 138
140 if (byte_count == 0 || byte_count == -3) { 139 if (byte_count == 0 || (byte_count == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)) {
141 handle_dead(sock); 140 handle_dead(sock);
142 return; 141 return;
143 } 142 }
@@ -178,12 +177,13 @@ static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
178} 177}
179 178
180static void handle_write(const int64_t sock) { 179static void handle_write(const int64_t sock) {
181 struct http_data *cookie = fdstate_cookie(sock); 180 struct http_data *cookie = fdstate_cookie(sock);
182 int chunked = 0; 181 int chunked = 0;
182 int keep_alive = 0;
183 183
184 if (cookie) { 184 if (cookie) {
185 if (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) 185 chunked = (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) != 0;
186 chunked = 1; 186 keep_alive = (cookie->flag & STRUCT_HTTP_FLAG_KEEPALIVE) != 0;
187 187
188 if (cookie->batch) { 188 if (cookie->batch) {
189 if (batch_send(sock, cookie->batch) == BATCH_FAILED) { 189 if (batch_send(sock, cookie->batch) == BATCH_FAILED) {
@@ -197,8 +197,14 @@ static void handle_write(const int64_t sock) {
197 197
198 /* 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 */
199 if (chunked) 199 if (chunked)
200 io_dontwantwrite(sock); 200 http_interest_drop(sock, cookie, EVENT_OUT);
201 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
202 handle_dead(sock); 208 handle_dead(sock);
203} 209}
204 210
@@ -210,25 +216,30 @@ static void handle_accept(const int64_t serversocket) {
210 216
211 while ((sock = socket_accept(serversocket, ip, &port)) != -1) { 217 while ((sock = socket_accept(serversocket, ip, &port)) != -1) {
212 218
213 /* Put fd into a non-blocking mode */ 219 socket_set_blocking((int)sock, 0);
214 io_nonblock(sock);
215 220
216 if (!io_fd(sock) || !(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) { 221 if (!(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) {
217 io_close(sock); 222 close((int)sock);
218 continue; 223 continue;
219 } 224 }
220 memset(cookie, 0, sizeof(struct http_data)); 225 memset(cookie, 0, sizeof(struct http_data));
221 memcpy(cookie->ip, ip, sizeof(ot_ip6)); 226 memcpy(cookie->ip, ip, sizeof(ot_ip6));
227 cookie->interest = EVENT_IN;
222 228
223 fdstate_open(sock, cookie, g_now_seconds + OT_CLIENT_TIMEOUT); 229 if (event_add((int)sock, EVENT_IN, fdstate_open(sock, cookie, g_now_seconds + OT_CLIENT_TIMEOUT)) == -1) {
224 io_wantread(sock); 230 fdstate_close(sock);
231 free(cookie);
232 close((int)sock);
233 continue;
234 }
225 235
226 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip); 236 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
227
228 } 237 }
229 io_eagain(serversocket);
230} 238}
231 239
240/* How many ready descriptors one wait hands back at a time */
241#define OT_EVENT_BATCH 512
242
232static void *server_mainloop(void *args) { 243static void *server_mainloop(void *args) {
233 struct ot_workstruct ws; 244 struct ot_workstruct ws;
234 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;
@@ -251,28 +262,42 @@ static void *server_mainloop(void *args) {
251 random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); 262 random_bytes(ws.rand48_state, sizeof(ws.rand48_state));
252 263
253 for (;;) { 264 for (;;) {
254 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);
270
271 for (i = 0; i < count; ++i) {
272 const void *cookie;
255 273
256 io_wait(); 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);
257 281
258 while ((sock = io_canread()) != -1) {
259 const void *cookie = fdstate_cookie(sock);
260 if ((intptr_t)cookie == FLAG_TCP) 282 if ((intptr_t)cookie == FLAG_TCP)
261 handle_accept(sock); 283 handle_accept(sock);
262 else if ((intptr_t)cookie == FLAG_UDP) 284 else if ((intptr_t)cookie == FLAG_UDP)
263 handle_udp6(sock, &ws); 285 handle_udp6(sock, &ws);
264 else if ((intptr_t)cookie == FLAG_SELFPIPE) 286 else if ((intptr_t)cookie == FLAG_SELFPIPE)
265 io_tryread(sock, ws.inbuf, G_INBUF_SIZE); 287 while (read((int)sock, ws.inbuf, G_INBUF_SIZE) > 0)
266 else 288 ;
267 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 }
268 } 296 }
269 297
270 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1) 298 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1)
271 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial); 299 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial);
272 300
273 while ((sock = io_canwrite()) != -1)
274 handle_write(sock);
275
276 if (g_now_seconds > next_timeout_check) { 301 if (g_now_seconds > next_timeout_check) {
277 int cursor = 0; 302 int cursor = 0;
278 303
@@ -319,11 +344,8 @@ static void listen_bind_one(ot_listen *entry) {
319 panic("socket_udp_bind"); 344 panic("socket_udp_bind");
320 } 345 }
321 346
322 if (!io_fd(entry->sock)) 347 if (event_add((int)entry->sock, EVENT_IN, fdstate_open(entry->sock, (void *)entry->proto, 0)) == -1)
323 panic("io_fd"); 348 panic("event_add");
324
325 fdstate_open(entry->sock, (void *)entry->proto, 0);
326 io_wantread(entry->sock);
327 349
328#ifdef _DEBUG 350#ifdef _DEBUG
329 fputs(" success.\n", stderr); 351 fputs(" success.\n", stderr);
@@ -352,7 +374,8 @@ static void listen_start_udp_workers(void) {
352 if (entry->proto != FLAG_UDP || entry->workers <= 0) 374 if (entry->proto != FLAG_UDP || entry->workers <= 0)
353 continue; 375 continue;
354 376
355 io_block(entry->sock); 377 socket_set_blocking((int)entry->sock, 1);
378 event_del((int)entry->sock);
356 udp_workers_install(entry->sock, (unsigned int)entry->workers); 379 udp_workers_install(entry->sock, (unsigned int)entry->workers);
357 } 380 }
358} 381}
@@ -375,14 +398,14 @@ void load_state(const char *const state_filename) {
375 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) { 398 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) {
376 size_t i; 399 size_t i;
377 400
378 if (!hex_tohash(infohash, inbuf)) 401 if (!hex_to_hash(infohash, inbuf))
379 continue; 402 continue;
380 i = 2 * sizeof(ot_hash); 403 i = 2 * sizeof(ot_hash);
381 404
382 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &base, UINT64_MAX))) 405 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &base, UINT64_MAX)))
383 continue; 406 continue;
384 i += consumed; 407 i += consumed;
385 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &downcount, UINT64_MAX))) 408 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &downcount, UINT64_MAX)))
386 continue; 409 continue;
387 add_torrent_from_saved_state(infohash, base, downcount); 410 add_torrent_from_saved_state(infohash, base, downcount);
388 } 411 }
@@ -453,6 +476,8 @@ int main(int argc, char **argv) {
453 random_init(); 476 random_init();
454 if (fdstate_init() == -1) 477 if (fdstate_init() == -1)
455 panic("fdstate_init"); 478 panic("fdstate_init");
479 if (event_init() == -1)
480 panic("event_init");
456 config_parse(argc, argv); 481 config_parse(argc, argv);
457 482
458 listen_bind_all(); 483 listen_bind_all();
@@ -471,15 +496,15 @@ int main(int argc, char **argv) {
471 pthread_create(&thread_id, NULL, time_caching_worker, NULL); 496 pthread_create(&thread_id, NULL, time_caching_worker, NULL);
472 497
473 /* Create our self pipe which allows us to interrupt mainloops 498 /* Create our self pipe which allows us to interrupt mainloops
474 io_wait in case some data is available to send out */ 499 wait in case some data is available to send out */
475 if (pipe(g_self_pipe) == -1) 500 if (pipe(g_self_pipe) == -1)
476 panic("selfpipe failed: "); 501 panic("selfpipe failed: ");
477 if (!io_fd(g_self_pipe[0])) 502 /* Both ends have to be non blocking: the loop drains the read end until it
478 panic("selfpipe io_fd failed: "); 503 is empty, and a worker nudging a full pipe has already made its point */
479 if (!io_fd(g_self_pipe[1])) 504 socket_set_blocking(g_self_pipe[0], 0);
480 panic("selfpipe io_fd failed: "); 505 socket_set_blocking(g_self_pipe[1], 0);
481 fdstate_open(g_self_pipe[0], (void *)FLAG_SELFPIPE, 0); 506 if (event_add(g_self_pipe[0], EVENT_IN, fdstate_open(g_self_pipe[0], (void *)FLAG_SELFPIPE, 0)) == -1)
482 io_wantread(g_self_pipe[0]); 507 panic("selfpipe event_add");
483 508
484 /* Init all sub systems. This call may fail with an exit() */ 509 /* Init all sub systems. This call may fail with an exit() */
485 trackerlogic_init(); 510 trackerlogic_init();
@@ -499,6 +524,7 @@ int main(int argc, char **argv) {
499 524
500 server_mainloop(0); 525 server_mainloop(0);
501 526
527 event_deinit();
502 fdstate_deinit(); 528 fdstate_deinit();
503 return 0; 529 return 0;
504} 530}