diff options
Diffstat (limited to 'ot_http.c')
| -rw-r--r-- | ot_http.c | 56 |
1 files changed, 48 insertions, 8 deletions
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "ot_iovec.h" | 22 | #include "ot_iovec.h" |
| 23 | #include "ot_ip.h" | 23 | #include "ot_ip.h" |
| 24 | #include "ot_mutex.h" | 24 | #include "ot_mutex.h" |
| 25 | #include "ot_workqueue.h" | ||
| 25 | #include "ot_scan.h" | 26 | #include "ot_scan.h" |
| 26 | #include "ot_event.h" | 27 | #include "ot_event.h" |
| 27 | #include "ot_fdstate.h" | 28 | #include "ot_fdstate.h" |
| @@ -39,9 +40,33 @@ ssize_t g_stats_path_len; | |||
| 39 | 40 | ||
| 40 | enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 }; | 41 | enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 }; |
| 41 | 42 | ||
| 42 | /* Give up a connection: the one place that knows everything hanging off it. | 43 | struct http_data *http_adopt(const int64_t sock) { |
| 43 | The slot is released before anything is freed, so that a late event or the | 44 | struct http_data *cookie = fdstate_cookie(sock), *heap; |
| 44 | expiry sweep finds a closed descriptor rather than a freed cookie. */ | 45 | int interest; |
| 46 | |||
| 47 | if (!cookie || !(cookie->flag & STRUCT_HTTP_FLAG_ONSTACK)) | ||
| 48 | return cookie; | ||
| 49 | |||
| 50 | if (!(heap = malloc(sizeof(*heap)))) | ||
| 51 | return NULL; | ||
| 52 | |||
| 53 | *heap = *cookie; | ||
| 54 | heap->flag &= ~STRUCT_HTTP_FLAG_ONSTACK; | ||
| 55 | |||
| 56 | /* Publishing the cookie is what lets another thread reach this connection, | ||
| 57 | so nothing may touch it afterwards, not even to read what it asked for */ | ||
| 58 | interest = heap->interest; | ||
| 59 | fdstate_set_cookie((int)sock, heap); | ||
| 60 | |||
| 61 | if (event_add((int)sock, interest, fdstate_generation((int)sock)) == -1) { | ||
| 62 | fdstate_set_cookie((int)sock, cookie); | ||
| 63 | free(heap); | ||
| 64 | return NULL; | ||
| 65 | } | ||
| 66 | return heap; | ||
| 67 | } | ||
| 68 | |||
| 69 | /* Give up a connection: the one place that knows everything hanging off it. */ | ||
| 45 | void http_close(const int64_t sock) { | 70 | void http_close(const int64_t sock) { |
| 46 | struct http_data *cookie = fdstate_cookie(sock); | 71 | struct http_data *cookie = fdstate_cookie(sock); |
| 47 | 72 | ||
| @@ -53,8 +78,9 @@ void http_close(const int64_t sock) { | |||
| 53 | free(cookie->batch); | 78 | free(cookie->batch); |
| 54 | buf_reset(&cookie->request); | 79 | buf_reset(&cookie->request); |
| 55 | if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) | 80 | if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) |
| 56 | mutex_workqueue_canceltask(sock); | 81 | workqueue_canceltask(sock); |
| 57 | free(cookie); | 82 | if (!(cookie->flag & STRUCT_HTTP_FLAG_ONSTACK)) |
| 83 | free(cookie); | ||
| 58 | } | 84 | } |
| 59 | 85 | ||
| 60 | event_close((int)sock); | 86 | event_close((int)sock); |
| @@ -140,6 +166,10 @@ void http_interest_set(const int64_t sock, struct http_data *cookie, int what) { | |||
| 140 | if (cookie->interest == what) | 166 | if (cookie->interest == what) |
| 141 | return; | 167 | return; |
| 142 | cookie->interest = what; | 168 | cookie->interest = what; |
| 169 | /* Still on a stack, so not in the event loop yet: whoever adopts this | ||
| 170 | connection registers whatever it asked for last */ | ||
| 171 | if (cookie->flag & STRUCT_HTTP_FLAG_ONSTACK) | ||
| 172 | return; | ||
| 143 | event_modify((int)sock, what, fdstate_generation((int)sock)); | 173 | event_modify((int)sock, what, fdstate_generation((int)sock)); |
| 144 | } | 174 | } |
| 145 | 175 | ||
| @@ -327,13 +357,17 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c | |||
| 327 | } | 357 | } |
| 328 | #endif | 358 | #endif |
| 329 | #endif | 359 | #endif |
| 330 | /* Pass this task to the worker thread */ | ||
| 331 | cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED; | 360 | cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED; |
| 332 | 361 | ||
| 333 | /* Clients waiting for us should not easily timeout */ | 362 | /* Clients waiting for us should not easily timeout */ |
| 334 | fdstate_set_expiry(sock, 0); | 363 | fdstate_set_expiry(sock, 0); |
| 335 | fullscrape_deliver(sock, format); | ||
| 336 | http_interest_set(sock, cookie, 0); | 364 | http_interest_set(sock, cookie, 0); |
| 365 | |||
| 366 | /* Everything this connection needs has been written, so it can be given | ||
| 367 | a home of its own and only then be made reachable by a worker thread */ | ||
| 368 | if (!http_adopt(sock)) | ||
| 369 | HTTPERROR_500; | ||
| 370 | fullscrape_deliver(sock, format); | ||
| 337 | return ws->reply_size = -2; | 371 | return ws->reply_size = -2; |
| 338 | } | 372 | } |
| 339 | #endif | 373 | #endif |
| @@ -345,6 +379,9 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c | |||
| 345 | 379 | ||
| 346 | /* Complex stats also include expensive memory debugging tools */ | 380 | /* Complex stats also include expensive memory debugging tools */ |
| 347 | fdstate_set_expiry(sock, 0); | 381 | fdstate_set_expiry(sock, 0); |
| 382 | |||
| 383 | if (!http_adopt(sock)) | ||
| 384 | HTTPERROR_500; | ||
| 348 | stats_deliver(sock, mode); | 385 | stats_deliver(sock, mode); |
| 349 | return ws->reply_size = -2; | 386 | return ws->reply_size = -2; |
| 350 | } | 387 | } |
| @@ -427,8 +464,11 @@ static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct * | |||
| 427 | cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED; | 464 | cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED; |
| 428 | /* Clients waiting for us should not easily timeout */ | 465 | /* Clients waiting for us should not easily timeout */ |
| 429 | fdstate_set_expiry(sock, 0); | 466 | fdstate_set_expiry(sock, 0); |
| 430 | fullscrape_deliver(sock, format); | ||
| 431 | http_interest_set(sock, cookie, 0); | 467 | http_interest_set(sock, cookie, 0); |
| 468 | |||
| 469 | if (!http_adopt(sock)) | ||
| 470 | HTTPERROR_500; | ||
| 471 | fullscrape_deliver(sock, format); | ||
| 432 | return ws->reply_size = -2; | 472 | return ws->reply_size = -2; |
| 433 | } | 473 | } |
| 434 | #endif | 474 | #endif |
