refactor: http_session

master
Sean McBride 3 years ago
parent c7758bbb00
commit 80b4d0e99c

@ -1,59 +0,0 @@
#pragma once
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "current_sandbox.h"
#include "http.h"
#include "http_total.h"
#include "likely.h"
#include "sandbox_types.h"
#include "scheduler.h"
#include "panic.h"
/**
* Sends Response Back to Client
* @return RC. -1 on Failure
*/
static inline int
current_sandbox_send_response()
{
struct sandbox *sandbox = current_sandbox_get();
assert(sandbox != NULL);
struct vec_u8 *response = &sandbox->http->response;
assert(response != NULL);
int rc;
/* Determine values to template into our HTTP response */
size_t response_body_size = response->length;
char *module_content_type = sandbox->module->response_content_type;
const char *content_type = strlen(module_content_type) > 0 ? module_content_type : "text/plain";
/* Capture Timekeeping data for end-to-end latency */
uint64_t end_time = __getcycles();
sandbox->total_time = end_time - sandbox->timestamp_of.request_arrival;
/* Send HTTP Response Header and Body */
rc = http_header_200_write(sandbox->http->client_socket_descriptor, content_type, response_body_size);
if (rc < 0) goto err;
rc = client_socket_send(sandbox->http->client_socket_descriptor, (const char *)response->buffer,
response_body_size, current_sandbox_sleep);
if (rc < 0) goto err;
http_total_increment_2xx();
rc = 0;
done:
return rc;
err:
debuglog("Error sending to client: %s", strerror(errno));
rc = -1;
goto done;
}

@ -3,6 +3,7 @@
#include <sys/socket.h>
#include <stdint.h>
#include "client_socket.h"
#include "http_request.h"
#include "http_parser.h"
#include "vec.h"
@ -13,20 +14,132 @@ VEC(u8)
struct http_session {
/* HTTP State */
struct sockaddr client_address; /* client requesting connection! */
int client_socket_descriptor;
int socket;
http_parser http_parser;
struct http_request http_request;
struct vec_u8 request;
struct vec_u8 response;
};
static inline void
http_session_init_parser(struct http_session *session)
/**
* @param session sandbox that we want to init
* @returns 0 on success, -1 on error
*/
static inline int
http_session_init(struct http_session *session, size_t max_request_size, size_t max_response_size,
int socket_descriptor, const struct sockaddr *socket_address)
{
assert(session != NULL);
assert(socket_address != NULL);
session->socket = socket_descriptor;
memcpy(&session->client_address, socket_address, sizeof(struct sockaddr));
http_parser_init(&session->http_parser, HTTP_REQUEST);
/* Set the session as the data the http-parser has access to */
session->http_parser.data = &session->http_request;
int rc;
rc = vec_u8_init(&session->request, max_request_size);
if (rc < 0) return -1;
rc = vec_u8_init(&session->response, max_response_size);
if (rc < 0) {
vec_u8_deinit(&session->request);
return -1;
}
return 0;
}
static inline struct http_session *
http_session_alloc(size_t max_request_size, size_t max_response_size, int socket_descriptor,
const struct sockaddr *socket_address)
{
struct http_session *session = calloc(sizeof(struct http_session), 1);
if (session == NULL) return NULL;
int rc = http_session_init(session, max_request_size, max_response_size, socket_descriptor, socket_address);
if (rc != 0) {
free(session);
return NULL;
}
return session;
}
/**
* Deinitialize Linear Memory, cleaning up the backing buffer
* @param sandbox
*/
static inline void
http_session_deinit(struct http_session *session)
{
assert(session);
vec_u8_deinit(&session->request);
vec_u8_deinit(&session->response);
}
static inline void
http_session_free(struct http_session *session)
{
assert(session);
http_session_deinit(session);
free(session);
}
/**
* Writes buffer to the client socket
* @param session - the HTTP session we want to send a 500 to
* @param on_eagain - cb to execute when client socket returns EAGAIN. If NULL, error out
* @returns 0 on success, -1 on error.
*/
static inline int
http_session_send_err(struct http_session *session, int status_code, void_cb on_eagain)
{
return client_socket_send(session->socket, http_header_build(status_code), http_header_len(status_code),
on_eagain);
}
static inline int
http_session_send_err_oneshot(struct http_session *session, int status_code)
{
return client_socket_send_oneshot(session->socket, http_header_build(status_code),
http_header_len(status_code));
}
static inline int
http_session_send_response(struct http_session *session, const char *response_content_type, void_cb on_eagain)
{
struct vec_u8 *response = &session->response;
assert(response != NULL);
int rc;
/* Determine values to template into our HTTP response */
const char *content_type = strlen(response_content_type) > 0 ? response_content_type : "text/plain";
/* Send HTTP Response Header and Body */
rc = http_header_200_write(session->socket, content_type, response->length);
if (rc < 0) goto err;
rc = client_socket_send(session->socket, (const char *)response->buffer, response->length, on_eagain);
if (rc < 0) goto err;
http_total_increment_2xx();
rc = 0;
done:
return rc;
err:
debuglog("Error sending to client: %s", strerror(errno));
rc = -1;
goto done;
}
static inline void
http_session_close(struct http_session *session)
{
return client_socket_close(session->socket, &session->client_address);
}

@ -4,7 +4,6 @@
#include <stddef.h>
#include <stdint.h>
#include "client_socket.h"
#include "panic.h"
#include "sandbox_types.h"
@ -18,17 +17,6 @@ int sandbox_prepare_execution_environment(struct sandbox *sandbox);
void sandbox_free(struct sandbox *sandbox);
void sandbox_main(struct sandbox *sandbox);
void sandbox_switch_to(struct sandbox *next_sandbox);
static inline void
sandbox_close_http(struct sandbox *sandbox)
{
assert(sandbox != NULL);
int rc = epoll_ctl(worker_thread_epoll_file_descriptor, EPOLL_CTL_DEL, sandbox->http->client_socket_descriptor,
NULL);
if (unlikely(rc < 0)) panic_err();
client_socket_close(sandbox->http->client_socket_descriptor, &sandbox->http->client_address);
}
/**
* Free Linear Memory, leaving stack in place
@ -43,18 +31,6 @@ sandbox_free_linear_memory(struct sandbox *sandbox)
sandbox->memory = NULL;
}
/**
* Deinitialize Linear Memory, cleaning up the backing buffer
* @param sandbox
*/
static inline void
sandbox_deinit_http_buffers(struct sandbox *sandbox)
{
assert(sandbox);
vec_u8_deinit(&sandbox->http->request);
vec_u8_deinit(&sandbox->http->response);
}
/**
* Given a sandbox, returns the module that sandbox is executing
* @param sandbox the sandbox whose module we want
@ -73,19 +49,3 @@ sandbox_get_priority(void *element)
struct sandbox *sandbox = (struct sandbox *)element;
return sandbox->absolute_deadline;
};
static inline void
sandbox_open_http(struct sandbox *sandbox)
{
assert(sandbox != NULL);
http_session_init_parser(sandbox->http);
/* Freshly allocated sandbox going runnable for first time, so register client socket with epoll */
struct epoll_event accept_evt;
accept_evt.data.ptr = (void *)sandbox;
accept_evt.events = EPOLLIN | EPOLLOUT | EPOLLET;
int rc = epoll_ctl(worker_thread_epoll_file_descriptor, EPOLL_CTL_ADD, sandbox->http->client_socket_descriptor,
&accept_evt);
if (unlikely(rc < 0)) panic_err();
}

@ -46,7 +46,7 @@ sandbox_receive_request(struct sandbox *sandbox)
goto err_nobufs;
}
ssize_t bytes_received = recv(sandbox->http->client_socket_descriptor, &request->buffer[request_length],
ssize_t bytes_received = recv(sandbox->http->socket, &request->buffer[request_length],
request_capacity - request_length, 0);
if (bytes_received < 0) {
@ -54,8 +54,7 @@ sandbox_receive_request(struct sandbox *sandbox)
current_sandbox_sleep();
continue;
} else {
debuglog("Error reading socket %d - %s\n", sandbox->http->client_socket_descriptor,
strerror(errno));
debuglog("Error reading socket %d - %s\n", sandbox->http->socket, strerror(errno));
goto err;
}
}
@ -70,8 +69,7 @@ sandbox_receive_request(struct sandbox *sandbox)
}
debuglog("Sandbox %lu: recv returned 0 before a complete request was received\n", sandbox->id);
debuglog("Socket: %d. Address: %s\n", sandbox->http->client_socket_descriptor,
client_address_text);
debuglog("Socket: %d. Address: %s\n", sandbox->http->socket, client_address_text);
http_request_print(&sandbox->http->http_request);
goto err;
}
@ -91,7 +89,7 @@ sandbox_receive_request(struct sandbox *sandbox)
http_errno_name((enum http_errno)sandbox->http->http_parser.http_errno),
http_errno_description((enum http_errno)sandbox->http->http_parser.http_errno));
debuglog("Length Parsed %zu, Length Read %zu\n", bytes_parsed, (size_t)bytes_received);
debuglog("Error parsing socket %d\n", sandbox->http->client_socket_descriptor);
debuglog("Error parsing socket %d\n", sandbox->http->socket);
goto err;
}

@ -36,7 +36,8 @@ sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state)
case SANDBOX_RUNNING_SYS: {
local_runqueue_delete(sandbox);
sandbox_free_linear_memory(sandbox);
sandbox_deinit_http_buffers(sandbox);
http_session_free(sandbox->http);
sandbox->http = NULL;
break;
}
default: {

@ -33,7 +33,8 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state)
sandbox->total_time = now - sandbox->timestamp_of.request_arrival;
local_runqueue_delete(sandbox);
sandbox_free_linear_memory(sandbox);
sandbox_deinit_http_buffers(sandbox);
http_session_free(sandbox->http);
sandbox->http = NULL;
break;
}
default: {

@ -4,7 +4,6 @@
#include <errno.h>
#include <stdint.h>
#include "client_socket.h"
#include "current_sandbox.h"
#include "global_request_scheduler.h"
#include "global_request_scheduler_deque.h"

@ -3,7 +3,7 @@
#include <assert.h>
#include <errno.h>
#include "client_socket.h"
#include "http_session.h"
#include "panic.h"
#include "runtime.h"
#include "sandbox_functions.h"
@ -61,9 +61,8 @@ scheduler_execute_epoll_loop(void)
case SANDBOX_ERROR:
panic("Expected to have closed socket");
default:
client_socket_send_oneshot(sandbox->http->client_socket_descriptor,
http_header_build(503), http_header_len(503));
sandbox_close_http(sandbox);
http_session_send_err_oneshot(sandbox->http, 503);
http_session_close(sandbox->http);
sandbox_set_as_error(sandbox, sandbox->state);
}
} else {

@ -0,0 +1,21 @@
#include "worker_thread.h"
static inline void
worker_thread_epoll_add_sandbox(struct sandbox *sandbox)
{
assert(sandbox != NULL);
/* Freshly allocated sandbox going runnable for first time, so register client socket with epoll */
struct epoll_event accept_evt;
accept_evt.data.ptr = (void *)sandbox;
accept_evt.events = EPOLLIN | EPOLLOUT | EPOLLET;
int rc = epoll_ctl(worker_thread_epoll_file_descriptor, EPOLL_CTL_ADD, sandbox->http->socket, &accept_evt);
if (unlikely(rc < 0)) panic_err();
}
static inline void
worker_thread_epoll_remove_sandbox(struct sandbox *sandbox)
{
assert(sandbox != NULL);
int rc = epoll_ctl(worker_thread_epoll_file_descriptor, EPOLL_CTL_DEL, sandbox->http->socket, NULL);
if (unlikely(rc < 0)) panic_err();
}

@ -3,7 +3,6 @@
#include "admissions_control.h"
#include "debuglog.h"
#include "client_socket.h"
/*
* Unitless estimate of the instantaneous fraction of system capacity required to complete all previously

@ -3,7 +3,6 @@
#include <threads.h>
#include "current_sandbox.h"
#include "current_sandbox_send_response.h"
#include "sandbox_functions.h"
#include "sandbox_receive_request.h"
#include "sandbox_set_as_asleep.h"
@ -15,6 +14,7 @@
#include "scheduler.h"
#include "software_interrupt.h"
#include "wasi.h"
#include "worker_thread_epoll.h"
thread_local struct sandbox *worker_thread_current_sandbox = NULL;
@ -82,48 +82,42 @@ current_sandbox_wasm_trap_handler(int trapno)
struct sandbox *sandbox = current_sandbox_get();
sandbox_syscall(sandbox);
int client_socket_descriptor = sandbox->http->client_socket_descriptor;
struct http_session *session = sandbox->http;
switch (trapno) {
case WASM_TRAP_INVALID_INDEX:
error_message = "WebAssembly Trap: Invalid Index\n";
client_socket_send(client_socket_descriptor, http_header_build(500), http_header_len(500),
current_sandbox_sleep);
http_session_send_err(session, 500, current_sandbox_sleep);
break;
case WASM_TRAP_MISMATCHED_TYPE:
error_message = "WebAssembly Trap: Mismatched Type\n";
client_socket_send(client_socket_descriptor, http_header_build(500), http_header_len(500),
current_sandbox_sleep);
http_session_send_err(session, 500, current_sandbox_sleep);
break;
case WASM_TRAP_PROTECTED_CALL_STACK_OVERFLOW:
error_message = "WebAssembly Trap: Protected Call Stack Overflow\n";
client_socket_send(client_socket_descriptor, http_header_build(500), http_header_len(500),
current_sandbox_sleep);
http_session_send_err(session, 500, current_sandbox_sleep);
break;
case WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY:
error_message = "WebAssembly Trap: Out of Bounds Linear Memory Access\n";
client_socket_send(client_socket_descriptor, http_header_build(500), http_header_len(500),
current_sandbox_sleep);
http_session_send_err(session, 500, current_sandbox_sleep);
break;
case WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION:
error_message = "WebAssembly Trap: Illegal Arithmetic Operation\n";
client_socket_send(client_socket_descriptor, http_header_build(500), http_header_len(500),
current_sandbox_sleep);
http_session_send_err(session, 500, current_sandbox_sleep);
break;
case WASM_TRAP_UNREACHABLE:
error_message = "WebAssembly Trap: Unreachable Instruction\n";
client_socket_send(client_socket_descriptor, http_header_build(500), http_header_len(500),
current_sandbox_sleep);
http_session_send_err(session, 500, current_sandbox_sleep);
break;
default:
error_message = "WebAssembly Trap: Unknown Trapno\n";
client_socket_send(client_socket_descriptor, http_header_build(500), http_header_len(500),
current_sandbox_sleep);
http_session_send_err(session, 500, current_sandbox_sleep);
break;
}
debuglog("%s", error_message);
sandbox_close_http(sandbox);
worker_thread_epoll_remove_sandbox(sandbox);
http_session_close(sandbox->http);
generic_thread_dump_lock_overhead();
current_sandbox_exit();
assert(0);
@ -140,18 +134,17 @@ current_sandbox_init()
int rc = 0;
char *error_message = NULL;
sandbox_open_http(sandbox);
worker_thread_epoll_add_sandbox(sandbox);
/* TODO: Move to listener code */
rc = sandbox_receive_request(sandbox);
if (rc == -2) {
error_message = "Request size exceeded Buffer\n";
/* Request size exceeded Buffer, send 413 Payload Too Large */
client_socket_send(sandbox->http->client_socket_descriptor, http_header_build(413),
http_header_len(413), current_sandbox_sleep);
http_session_send_err(sandbox->http, 413, current_sandbox_sleep);
goto err;
} else if (rc == -1) {
client_socket_send(sandbox->http->client_socket_descriptor, http_header_build(400),
http_header_len(400), current_sandbox_sleep);
http_session_send_err(sandbox->http, 400, current_sandbox_sleep);
goto err;
}
@ -184,7 +177,8 @@ current_sandbox_init()
err:
debuglog("%s", error_message);
sandbox_close_http(sandbox);
worker_thread_epoll_remove_sandbox(sandbox);
http_session_close(sandbox->http);
generic_thread_dump_lock_overhead();
current_sandbox_exit();
return NULL;
@ -200,9 +194,11 @@ current_sandbox_fini()
sandbox_syscall(sandbox);
sandbox->timestamp_of.completion = __getcycles();
sandbox->total_time = sandbox->timestamp_of.completion - sandbox->timestamp_of.request_arrival;
/* Retrieve the result, construct the HTTP response, and send to client */
if (current_sandbox_send_response() < 0) {
if (http_session_send_response(sandbox->http, sandbox->module->response_content_type, current_sandbox_sleep)
< 0) {
error_message = "Unable to build and send client response\n";
goto err;
};
@ -212,10 +208,12 @@ current_sandbox_fini()
sandbox->timestamp_of.response = __getcycles();
assert(sandbox->state == SANDBOX_RUNNING_SYS);
sandbox_close_http(sandbox);
sandbox_set_as_returned(sandbox, SANDBOX_RUNNING_SYS);
worker_thread_epoll_remove_sandbox(sandbox);
done:
http_session_close(sandbox->http);
sandbox_set_as_returned(sandbox, SANDBOX_RUNNING_SYS);
/* Cleanup connection and exit sandbox */
generic_thread_dump_lock_overhead();
current_sandbox_exit();
@ -224,7 +222,6 @@ err:
debuglog("%s", error_message);
assert(sandbox->state == SANDBOX_RUNNING_SYS);
sandbox_close_http(sandbox);
goto done;
}

@ -183,19 +183,15 @@ listener_thread_main(void *dummy)
(const struct sockaddr *)&client_address,
request_arrival_timestamp, work_admitted);
if (unlikely(sandbox == NULL)) {
client_socket_send_oneshot(sandbox->http->client_socket_descriptor,
http_header_build(503), http_header_len(503));
client_socket_close(sandbox->http->client_socket_descriptor,
&sandbox->http->client_address);
http_session_send_err_oneshot(sandbox->http, 503);
http_session_close(sandbox->http);
}
/* If the global request scheduler is full, return a 429 to the client */
sandbox = global_request_scheduler_add(sandbox);
if (unlikely(sandbox == NULL)) {
client_socket_send_oneshot(sandbox->http->client_socket_descriptor,
http_header_build(429), http_header_len(429));
client_socket_close(sandbox->http->client_socket_descriptor,
&sandbox->http->client_address);
http_session_send_err_oneshot(sandbox->http, 429);
http_session_close(sandbox->http);
}
} /* while true */

@ -1,6 +1,5 @@
#include <threads.h>
#include "client_socket.h"
#include "current_sandbox.h"
#include "global_request_scheduler.h"
#include "local_runqueue_list.h"

@ -2,7 +2,6 @@
#include <threads.h>
#include "arch/context.h"
#include "client_socket.h"
#include "current_sandbox.h"
#include "debuglog.h"
#include "global_request_scheduler.h"

@ -12,7 +12,6 @@
#include "admissions_control.h"
#include "arch/context.h"
#include "client_socket.h"
#include "debuglog.h"
#include "global_request_scheduler_deque.h"
#include "global_request_scheduler_minheap.h"

@ -80,28 +80,6 @@ sandbox_free_stack(struct sandbox *sandbox)
return module_free_stack(sandbox->module, sandbox->stack);
}
/**
* Allocate http request and response buffers for a sandbox
* @param sandbox sandbox that we want to allocate HTTP buffers for
* @returns 0 on success, -1 on error
*/
static inline int
sandbox_allocate_http_buffers(struct sandbox *sandbox)
{
int rc;
rc = vec_u8_init(&sandbox->http->request, sandbox->module->max_request_size);
if (rc < 0) return -1;
rc = vec_u8_init(&sandbox->http->response, sandbox->module->max_response_size);
if (rc < 0) {
vec_u8_deinit(&sandbox->http->request);
return -1;
}
return 0;
}
/**
* Allocates HTTP buffers and performs our approximation of "WebAssembly instantiation"
* @param sandbox
@ -116,11 +94,6 @@ sandbox_prepare_execution_environment(struct sandbox *sandbox)
int rc;
if (sandbox_allocate_http_buffers(sandbox)) {
error_message = "failed to allocate http buffers";
goto err_http_allocation_failed;
}
rc = sandbox_allocate_globals(sandbox);
if (rc < 0) {
error_message = "failed to allocate globals";
@ -150,9 +123,8 @@ err_stack_allocation_failed:
err_memory_allocation_failed:
err_globals_allocation_failed:
err_http_allocation_failed:
client_socket_send_oneshot(sandbox->http->client_socket_descriptor, http_header_build(503),
http_header_len(503));
client_socket_close(sandbox->http->client_socket_descriptor, &sandbox->http->client_address);
http_session_send_err_oneshot(sandbox->http, 503);
http_session_close(sandbox->http);
sandbox_set_as_error(sandbox, SANDBOX_ALLOCATED);
perror(error_message);
rc = -1;
@ -172,11 +144,10 @@ sandbox_init(struct sandbox *sandbox, struct module *module, int socket_descript
ps_list_init_d(sandbox);
/* Allocate HTTP session structure */
sandbox->http = calloc(sizeof(struct http_session), 1);
sandbox->http = http_session_alloc(sandbox->module->max_request_size, sandbox->module->max_response_size,
socket_descriptor, socket_address);
assert(sandbox->http);
sandbox->http->client_socket_descriptor = socket_descriptor;
memcpy(&sandbox->http->client_address, socket_address, sizeof(struct sockaddr));
sandbox->timestamp_of.request_arrival = request_arrival_timestamp;
sandbox->absolute_deadline = request_arrival_timestamp + module->relative_deadline;
@ -227,9 +198,7 @@ sandbox_deinit(struct sandbox *sandbox)
module_release(sandbox->module);
/* TODO: Validate lifetime and cleanup of pointer members in this struct */
free(sandbox->http);
/* HTTP Session was already deinited, freed, and set to NULL */
/* Linear Memory and Guard Page should already have been munmaped and set to NULL */
assert(sandbox->memory == NULL);

Loading…
Cancel
Save