summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c138
1 files changed, 83 insertions, 55 deletions
diff --git a/opentracker.c b/opentracker.c
index 50fff29..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,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,12 +177,13 @@ 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;
182 int keep_alive = 0;
180 183
181 if (cookie) { 184 if (cookie) {
182 if (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) 185 chunked = (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) != 0;
183 chunked = 1; 186 keep_alive = (cookie->flag & STRUCT_HTTP_FLAG_KEEPALIVE) != 0;
184 187
185 if (cookie->batch) { 188 if (cookie->batch) {
186 if (batch_send(sock, cookie->batch) == BATCH_FAILED) { 189 if (batch_send(sock, cookie->batch) == BATCH_FAILED) {
@@ -194,8 +197,14 @@ static void handle_write(const int64_t sock) {
194 197
195 /* 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 */
196 if (chunked) 199 if (chunked)
197 io_dontwantwrite(sock); 200 http_interest_drop(sock, cookie, EVENT_OUT);
198 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
199 handle_dead(sock); 208 handle_dead(sock);
200} 209}
201 210
@@ -204,34 +213,33 @@ static void handle_accept(const int64_t serversocket) {
204 int64_t sock; 213 int64_t sock;
205 ot_ip6 ip; 214 ot_ip6 ip;
206 uint16_t port; 215 uint16_t port;
207 tai6464 t;
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 /* 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 } 237 }
232 io_eagain(serversocket);
233} 238}
234 239
240/* How many ready descriptors one wait hands back at a time */
241#define OT_EVENT_BATCH 512
242
235static void *server_mainloop(void *args) { 243static void *server_mainloop(void *args) {
236 struct ot_workstruct ws; 244 struct ot_workstruct ws;
237 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;
@@ -254,30 +262,46 @@ static void *server_mainloop(void *args) {
254 random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); 262 random_bytes(ws.rand48_state, sizeof(ws.rand48_state));
255 263
256 for (;;) { 264 for (;;) {
257 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);
258 270
259 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);
260 281
261 while ((sock = io_canread()) != -1) {
262 const void *cookie = io_getcookie(sock);
263 if ((intptr_t)cookie == FLAG_TCP) 282 if ((intptr_t)cookie == FLAG_TCP)
264 handle_accept(sock); 283 handle_accept(sock);
265 else if ((intptr_t)cookie == FLAG_UDP) 284 else if ((intptr_t)cookie == FLAG_UDP)
266 handle_udp6(sock, &ws); 285 handle_udp6(sock, &ws);
267 else if ((intptr_t)cookie == FLAG_SELFPIPE) 286 else if ((intptr_t)cookie == FLAG_SELFPIPE)
268 io_tryread(sock, ws.inbuf, G_INBUF_SIZE); 287 while (read((int)sock, ws.inbuf, G_INBUF_SIZE) > 0)
269 else 288 ;
270 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 }
271 } 296 }
272 297
273 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1) 298 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1)
274 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial); 299 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial);
275 300
276 while ((sock = io_canwrite()) != -1)
277 handle_write(sock);
278
279 if (g_now_seconds > next_timeout_check) { 301 if (g_now_seconds > next_timeout_check) {
280 while ((sock = io_timeouted()) != -1) 302 int cursor = 0;
303
304 while ((sock = fdstate_next_expired(g_now_seconds, &cursor)) != -1)
281 handle_dead(sock); 305 handle_dead(sock);
282 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 306 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
283 } 307 }
@@ -320,11 +344,8 @@ static void listen_bind_one(ot_listen *entry) {
320 panic("socket_udp_bind"); 344 panic("socket_udp_bind");
321 } 345 }
322 346
323 if (!io_fd(entry->sock)) 347 if (event_add((int)entry->sock, EVENT_IN, fdstate_open(entry->sock, (void *)entry->proto, 0)) == -1)
324 panic("io_fd"); 348 panic("event_add");
325
326 io_setcookie(entry->sock, (void *)entry->proto);
327 io_wantread(entry->sock);
328 349
329#ifdef _DEBUG 350#ifdef _DEBUG
330 fputs(" success.\n", stderr); 351 fputs(" success.\n", stderr);
@@ -353,7 +374,8 @@ static void listen_start_udp_workers(void) {
353 if (entry->proto != FLAG_UDP || entry->workers <= 0) 374 if (entry->proto != FLAG_UDP || entry->workers <= 0)
354 continue; 375 continue;
355 376
356 io_block(entry->sock); 377 socket_set_blocking((int)entry->sock, 1);
378 event_del((int)entry->sock);
357 udp_workers_install(entry->sock, (unsigned int)entry->workers); 379 udp_workers_install(entry->sock, (unsigned int)entry->workers);
358 } 380 }
359} 381}
@@ -376,14 +398,14 @@ void load_state(const char *const state_filename) {
376 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) { 398 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) {
377 size_t i; 399 size_t i;
378 400
379 if (!hex_tohash(infohash, inbuf)) 401 if (!hex_to_hash(infohash, inbuf))
380 continue; 402 continue;
381 i = 2 * sizeof(ot_hash); 403 i = 2 * sizeof(ot_hash);
382 404
383 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &base, UINT64_MAX))) 405 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &base, UINT64_MAX)))
384 continue; 406 continue;
385 i += consumed; 407 i += consumed;
386 if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &downcount, UINT64_MAX))) 408 if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &downcount, UINT64_MAX)))
387 continue; 409 continue;
388 add_torrent_from_saved_state(infohash, base, downcount); 410 add_torrent_from_saved_state(infohash, base, downcount);
389 } 411 }
@@ -452,6 +474,10 @@ int main(int argc, char **argv) {
452 pthread_t thread_id; /* time cacher */ 474 pthread_t thread_id; /* time cacher */
453 475
454 random_init(); 476 random_init();
477 if (fdstate_init() == -1)
478 panic("fdstate_init");
479 if (event_init() == -1)
480 panic("event_init");
455 config_parse(argc, argv); 481 config_parse(argc, argv);
456 482
457 listen_bind_all(); 483 listen_bind_all();
@@ -470,15 +496,15 @@ int main(int argc, char **argv) {
470 pthread_create(&thread_id, NULL, time_caching_worker, NULL); 496 pthread_create(&thread_id, NULL, time_caching_worker, NULL);
471 497
472 /* Create our self pipe which allows us to interrupt mainloops 498 /* Create our self pipe which allows us to interrupt mainloops
473 io_wait in case some data is available to send out */ 499 wait in case some data is available to send out */
474 if (pipe(g_self_pipe) == -1) 500 if (pipe(g_self_pipe) == -1)
475 panic("selfpipe failed: "); 501 panic("selfpipe failed: ");
476 if (!io_fd(g_self_pipe[0])) 502 /* Both ends have to be non blocking: the loop drains the read end until it
477 panic("selfpipe io_fd failed: "); 503 is empty, and a worker nudging a full pipe has already made its point */
478 if (!io_fd(g_self_pipe[1])) 504 socket_set_blocking(g_self_pipe[0], 0);
479 panic("selfpipe io_fd failed: "); 505 socket_set_blocking(g_self_pipe[1], 0);
480 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)
481 io_wantread(g_self_pipe[0]); 507 panic("selfpipe event_add");
482 508
483 /* Init all sub systems. This call may fail with an exit() */ 509 /* Init all sub systems. This call may fail with an exit() */
484 trackerlogic_init(); 510 trackerlogic_init();
@@ -498,5 +524,7 @@ int main(int argc, char **argv) {
498 524
499 server_mainloop(0); 525 server_mainloop(0);
500 526
527 event_deinit();
528 fdstate_deinit();
501 return 0; 529 return 0;
502} 530}