diff options
Diffstat (limited to 'opentracker.c')
| -rw-r--r-- | opentracker.c | 118 |
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 | ||
| 136 | static void handle_read(const int64_t sock, struct ot_workstruct *ws) { | 135 | static 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 | ||
| 180 | static void handle_write(const int64_t sock) { | 179 | static 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 | |||
| 232 | static void *server_mainloop(void *args) { | 243 | static 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 | } |
