chore: cleanup sandbox logic

master
Sean McBride 5 years ago
parent ebfe8856bc
commit b8a0e28d11

@ -6,18 +6,10 @@
void current_sandbox_close_file_descriptor(int io_handle_index);
struct sandbox * current_sandbox_get(void);
char * current_sandbox_get_arguments(void);
int current_sandbox_get_file_descriptor(int io_handle_index);
int current_sandbox_get_http_request_body(char **body);
union uv_any_handle *current_sandbox_get_libuv_handle(int io_handle_index);
int current_sandbox_initialize_io_handle(void);
int current_sandbox_initialize_io_handle_and_set_file_descriptor(int file_descriptor);
int current_sandbox_parse_http_request(size_t length);
void current_sandbox_set(struct sandbox *sandbox);
int current_sandbox_set_file_descriptor(int io_handle_index, int file_descriptor);
int current_sandbox_set_http_response_header(char *header, int length);
int current_sandbox_set_http_response_body(char *body, int length);
int current_sandbox_set_http_response_status(char *status, int length);
int current_sandbox_vectorize_http_response(void);
#endif /* SFRT_CURRENT_SANDBOX_H */

@ -31,7 +31,6 @@ typedef enum
RETURNED
} sandbox_state_t;
struct sandbox {
sandbox_state_t state;
@ -87,7 +86,7 @@ typedef struct sandbox sandbox_t;
extern __thread arch_context_t *worker_thread_next_context;
extern void worker_thread_block_current_sandbox(void);
extern void worker_thread_exit_current_sandbox(void);
extern void worker_thread_on_sandbox_exit(sandbox_t *sandbox);
extern void worker_thread_process_io(void);
extern void __attribute__((noreturn)) worker_thread_sandbox_switch_preempt(void);
extern void worker_thread_wakeup_sandbox(sandbox_t *sandbox);
@ -98,6 +97,7 @@ extern void worker_thread_wakeup_sandbox(sandbox_t *sandbox);
struct sandbox *sandbox_allocate(sandbox_request_t *sandbox_request);
void sandbox_free(struct sandbox *sandbox);
void sandbox_main(struct sandbox *sandbox);
int sandbox_parse_http_request(struct sandbox *sandbox, size_t length);

@ -34,17 +34,6 @@ current_sandbox_set(struct sandbox *sandbox)
}
}
/**
* Getter for the arguments of the current sandbox
* @return the arguments of the current sandbox
*/
char *
current_sandbox_get_arguments(void)
{
struct sandbox *sandbox = current_sandbox_get();
return sandbox_get_arguments(sandbox);
}
/**
* Initializes and returns an IO handle on the current sandbox ready for use
* @return index of handle we preopened or -1 if all io_handles are exhausted
@ -56,31 +45,8 @@ current_sandbox_initialize_io_handle(void)
return sandbox_initialize_io_handle(sandbox);
}
/**
* Initializes and returns an IO handle on the current sandbox ready for use
* @param file_descriptor what we'll set on the IO handle after initialization
* @return index of handle we preopened or -1 if all io_handles are exhausted
**/
int
current_sandbox_initialize_io_handle_and_set_file_descriptor(int file_descriptor)
{
struct sandbox *sandbox = current_sandbox_get();
return sandbox_initialize_io_handle_and_set_file_descriptor(sandbox, file_descriptor);
}
int sandbox_parse_http_request(struct sandbox *sandbox, size_t l);
/**
* Parse the current sandbox's request_response_data up to length
* @param length
* @returns 0
**/
int
current_sandbox_parse_http_request(size_t length)
{
return sandbox_parse_http_request(current_sandbox_get(), length);
}
/**
* Sets the file descriptor of the sandbox's ith io_handle
* Returns error condition if the file_descriptor to set does not contain sandbox preopen magin
@ -129,61 +95,3 @@ current_sandbox_get_libuv_handle(int io_handle_index)
struct sandbox *sandbox = current_sandbox_get();
return sandbox_get_libuv_handle(sandbox, io_handle_index);
}
/**
* Gets the HTTP Request body from the current sandbox
* @param body pointer that we'll assign to the http_request body
* @returns the length of the http_request's body
**/
int
current_sandbox_get_http_request_body(char **body)
{
return http_request_get_body(&current_sandbox_get()->http_request, body);
}
/**
* Set an HTTP Response Header on the current sandbox
* @param header string of the header that we want to set
* @param length the length of the header string
* @returns 0 (abends program in case of error)
**/
int
current_sandbox_set_http_response_header(char *header, int length)
{
return http_response_set_header(&current_sandbox_get()->http_response, header, length);
}
/**
* Set an HTTP Response Body on the current sandbox
* @param body string of the body that we want to set
* @param length the length of the body string
* @returns 0 (abends program in case of error)
**/
int
current_sandbox_set_http_response_body(char *body, int length)
{
return http_response_set_body(&current_sandbox_get()->http_response, body, length);
}
/**
* Set an HTTP Response Status on the current sandbox
* @param status string of the status we want to set
* @param length the length of the status
* @returns 0 (abends program in case of error)
**/
int
current_sandbox_set_http_response_status(char *status, int length)
{
return http_response_set_status(&current_sandbox_get()->http_response, status, length);
}
/**
* Encode the current sandbox's HTTP Response as an array of buffers
* @returns the number of buffers used to store the HTTP Response
**/
int
current_sandbox_vectorize_http_response(void)
{
return http_response_encode_as_vector(&current_sandbox_get()->http_response);
}

@ -12,22 +12,21 @@
/**
* Takes the arguments from the sandbox struct and writes them into the WebAssembly linear memory
* TODO: why do we have to pass argument count explicitly? Can't we just get this off the sandbox?
* @param argument_count
**/
static inline void
current_sandbox_setup_arguments(i32 argument_count)
sandbox_setup_arguments(struct sandbox *sandbox)
{
struct sandbox *curr = current_sandbox_get();
char * arguments = current_sandbox_get_arguments();
assert(sandbox != NULL);
char *arguments = sandbox_get_arguments(sandbox);
i32 argument_count = module_get_argument_count(sandbox->module);
// whatever gregor has, to be able to pass arguments to a module!
curr->arguments_offset = sandbox_lmbound;
assert(sandbox_lmbase == curr->linear_memory_start);
sandbox->arguments_offset = sandbox_lmbound;
assert(sandbox_lmbase == sandbox->linear_memory_start);
expand_memory();
i32 *array_ptr = worker_thread_get_memory_ptr_void(curr->arguments_offset, argument_count * sizeof(i32));
i32 string_off = curr->arguments_offset + (argument_count * sizeof(i32));
i32 *array_ptr = worker_thread_get_memory_ptr_void(sandbox->arguments_offset, argument_count * sizeof(i32));
i32 string_off = sandbox->arguments_offset + (argument_count * sizeof(i32));
for (int i = 0; i < argument_count; i++) {
char * arg = arguments + (i * MODULE_MAX_ARGUMENT_SIZE);
@ -52,6 +51,8 @@ current_sandbox_setup_arguments(i32 argument_count)
int
sandbox_parse_http_request(struct sandbox *sandbox, size_t length)
{
assert(sandbox != NULL);
assert(length > 0);
// Why is our start address sandbox->request_response_data + sandbox->request_response_data_length?
// it's like a cursor to keep track of what we've read so far
http_parser_execute(&sandbox->http_parser, http_parser_settings_get(),
@ -59,43 +60,44 @@ sandbox_parse_http_request(struct sandbox *sandbox, size_t length)
return 0;
}
/**
* Receive and Parse the Request for the current sandbox
* @return 1 on success, 0 if no context, < 0 on failure.
**/
static inline int
current_sandbox_receive_and_parse_client_request(void)
sandbox_receive_and_parse_client_request(struct sandbox *sandbox)
{
struct sandbox *curr = current_sandbox_get();
curr->request_response_data_length = 0;
assert(sandbox != NULL);
sandbox->request_response_data_length = 0;
#ifndef USE_HTTP_UVIO
int r = 0;
r = recv(curr->client_socket_descriptor, (curr->request_response_data), curr->module->max_request_size, 0);
r = recv(sandbox->client_socket_descriptor, (sandbox->request_response_data), sandbox->module->max_request_size,
0);
if (r <= 0) {
if (r < 0) perror("recv1");
return r;
}
while (r > 0) {
if (current_sandbox_parse_http_request(r) != 0) return -1;
curr->request_response_data_length += r;
struct http_request *rh = &curr->http_request;
if (sandbox_parse_http_request(sandbox, r) != 0) return -1;
sandbox->request_response_data_length += r;
struct http_request *rh = &sandbox->http_request;
if (rh->message_end) break;
r = recv(curr->client_socket_descriptor,
(curr->request_response_data + curr->request_response_data_length),
curr->module->max_request_size - curr->request_response_data_length, 0);
r = recv(sandbox->client_socket_descriptor,
(sandbox->request_response_data + sandbox->request_response_data_length),
sandbox->module->max_request_size - sandbox->request_response_data_length, 0);
if (r < 0) {
perror("recv2");
return r;
}
}
#else
int r = uv_read_start((uv_stream_t *)&curr->client_libuv_stream,
int r = uv_read_start((uv_stream_t *)&sandbox->client_libuv_stream,
libuv_callbacks_on_allocate_setup_request_response_data,
libuv_callbacks_on_read_parse_http_request);
worker_thread_process_io();
if (curr->request_response_data_length == 0) return 0;
if (sandbox->request_response_data_length == 0) return 0;
#endif
return 1;
}
@ -105,54 +107,55 @@ current_sandbox_receive_and_parse_client_request(void)
* @return RC. -1 on Failure
**/
static inline int
current_sandbox_build_and_send_client_response(void)
sandbox_build_and_send_client_response(struct sandbox *sandbox)
{
int sndsz = 0;
struct sandbox *curr = current_sandbox_get();
int response_header_length = strlen(HTTP_RESPONSE_200_OK) + strlen(HTTP_RESPONSE_CONTENT_TYPE)
assert(sandbox != NULL);
int sndsz = 0;
int response_header_length = strlen(HTTP_RESPONSE_200_OK) + strlen(HTTP_RESPONSE_CONTENT_TYPE)
+ strlen(HTTP_RESPONSE_CONTENT_LENGTH);
int body_length = curr->request_response_data_length - response_header_length;
int body_length = sandbox->request_response_data_length - response_header_length;
memset(curr->request_response_data, 0,
memset(sandbox->request_response_data, 0,
strlen(HTTP_RESPONSE_200_OK) + strlen(HTTP_RESPONSE_CONTENT_TYPE)
+ strlen(HTTP_RESPONSE_CONTENT_LENGTH));
strncpy(curr->request_response_data, HTTP_RESPONSE_200_OK, strlen(HTTP_RESPONSE_200_OK));
strncpy(sandbox->request_response_data, HTTP_RESPONSE_200_OK, strlen(HTTP_RESPONSE_200_OK));
sndsz += strlen(HTTP_RESPONSE_200_OK);
if (body_length == 0) goto done;
strncpy(curr->request_response_data + sndsz, HTTP_RESPONSE_CONTENT_TYPE, strlen(HTTP_RESPONSE_CONTENT_TYPE));
if (strlen(curr->module->response_content_type) <= 0) {
strncpy(curr->request_response_data + sndsz + strlen("Content-type: "),
strncpy(sandbox->request_response_data + sndsz, HTTP_RESPONSE_CONTENT_TYPE, strlen(HTTP_RESPONSE_CONTENT_TYPE));
if (strlen(sandbox->module->response_content_type) <= 0) {
strncpy(sandbox->request_response_data + sndsz + strlen("Content-type: "),
HTTP_RESPONSE_CONTENT_TYPE_PLAIN, strlen(HTTP_RESPONSE_CONTENT_TYPE_PLAIN));
} else {
strncpy(curr->request_response_data + sndsz + strlen("Content-type: "),
curr->module->response_content_type, strlen(curr->module->response_content_type));
strncpy(sandbox->request_response_data + sndsz + strlen("Content-type: "),
sandbox->module->response_content_type, strlen(sandbox->module->response_content_type));
}
sndsz += strlen(HTTP_RESPONSE_CONTENT_TYPE);
char len[10] = { 0 };
sprintf(len, "%d", body_length);
strncpy(curr->request_response_data + sndsz, HTTP_RESPONSE_CONTENT_LENGTH,
strncpy(sandbox->request_response_data + sndsz, HTTP_RESPONSE_CONTENT_LENGTH,
strlen(HTTP_RESPONSE_CONTENT_LENGTH));
strncpy(curr->request_response_data + sndsz + strlen("Content-length: "), len, strlen(len));
strncpy(sandbox->request_response_data + sndsz + strlen("Content-length: "), len, strlen(len));
sndsz += strlen(HTTP_RESPONSE_CONTENT_LENGTH);
sndsz += body_length;
done:
assert(sndsz == curr->request_response_data_length);
curr->total_time = __getcycles() - curr->start_time;
uint64_t total_time_us = curr->total_time / runtime_processor_speed_MHz;
assert(sndsz == sandbox->request_response_data_length);
sandbox->total_time = __getcycles() - sandbox->start_time;
uint64_t total_time_us = sandbox->total_time / runtime_processor_speed_MHz;
printf("%s():%d, %d, %lu\n", curr->module->name, curr->module->port, curr->module->relative_deadline_us,
total_time_us);
printf("%s():%d, %d, %lu\n", sandbox->module->name, sandbox->module->port,
sandbox->module->relative_deadline_us, total_time_us);
#ifndef USE_HTTP_UVIO
int r = send(curr->client_socket_descriptor, curr->request_response_data, sndsz, 0);
int r = send(sandbox->client_socket_descriptor, sandbox->request_response_data, sndsz, 0);
if (r < 0) {
perror("send");
return -1;
}
while (r < sndsz) {
int s = send(curr->client_socket_descriptor, curr->request_response_data + r, sndsz - r, 0);
int s = send(sandbox->client_socket_descriptor, sandbox->request_response_data + r, sndsz - r, 0);
if (s < 0) {
perror("send");
return -1;
@ -161,101 +164,113 @@ done:
}
#else
uv_write_t req = {
.data = curr,
.data = sandbox,
};
uv_buf_t bufv = uv_buf_init(curr->request_response_data, sndsz);
int r = uv_write(&req, (uv_stream_t *)&curr->client_libuv_stream, &bufv, 1,
uv_buf_t bufv = uv_buf_init(sandbox->request_response_data, sndsz);
int r = uv_write(&req, (uv_stream_t *)&sandbox->client_libuv_stream, &bufv, 1,
libuv_callbacks_on_write_wakeup_sandbox);
worker_thread_process_io();
#endif
return 0;
}
/**
* Sandbox execution logic
* Handles setup, request parsing, WebAssembly initialization, function execution, response building and sending, and
*cleanup
**/
void
current_sandbox_main(void)
static inline void
sandbox_close_http(struct sandbox *sandbox)
{
struct sandbox *current_sandbox = current_sandbox_get();
// FIXME: is this right? this is the first time this sandbox is running.. so it wont
// return to worker_thread_switch_to_sandbox() api..
// we'd potentially do what we'd in worker_thread_switch_to_sandbox() api here for cleanup..
if (software_interrupt_is_enabled() == false) {
arch_context_init(&current_sandbox->ctxt, 0, 0);
worker_thread_next_context = NULL;
software_interrupt_enable();
}
struct module *current_module = sandbox_get_module(current_sandbox);
int argument_count = module_get_argument_count(current_module);
// for stdio
assert(sandbox != NULL);
// Try to initialize file descriptors 0, 1, and 2 as io handles 0, 1, 2
// We need to check that we get what we expect, as these IO handles may theoretically have been taken
// TODO: why do the file descriptors have to match the io handles?
int f = current_sandbox_initialize_io_handle_and_set_file_descriptor(0);
assert(f == 0);
f = current_sandbox_initialize_io_handle_and_set_file_descriptor(1);
assert(f == 1);
f = current_sandbox_initialize_io_handle_and_set_file_descriptor(2);
assert(f == 2);
#ifdef USE_HTTP_UVIO
uv_close((uv_handle_t *)&sandbox->client_libuv_stream, libuv_callbacks_on_close_wakeup_sakebox);
worker_thread_process_io();
#else
close(sandbox->client_socket_descriptor);
#endif
}
// Initialize the HTTP-Parser for a request
http_parser_init(&current_sandbox->http_parser, HTTP_REQUEST);
static inline void
sandbox_open_http(struct sandbox *sandbox)
{
assert(sandbox != NULL);
// Set the current_sandbox as the data the http-parser has access to
current_sandbox->http_parser.data = current_sandbox;
http_parser_init(&sandbox->http_parser, HTTP_REQUEST);
// NOTE: if more headers, do offset by that!
int response_header_length = strlen(HTTP_RESPONSE_200_OK) + strlen(HTTP_RESPONSE_CONTENT_TYPE)
+ strlen(HTTP_RESPONSE_CONTENT_LENGTH);
// Set the sandbox as the data the http-parser has access to
sandbox->http_parser.data = sandbox;
#ifdef USE_HTTP_UVIO
// Initialize libuv TCP stream
int r = uv_tcp_init(worker_thread_get_libuv_handle(), (uv_tcp_t *)&current_sandbox->client_libuv_stream);
int r = uv_tcp_init(worker_thread_get_libuv_handle(), (uv_tcp_t *)&sandbox->client_libuv_stream);
assert(r == 0);
// Set the current sandbox as the data the libuv callbacks have access to
current_sandbox->client_libuv_stream.data = current_sandbox;
sandbox->client_libuv_stream.data = sandbox;
// Open the libuv TCP stream
r = uv_tcp_open((uv_tcp_t *)&current_sandbox->client_libuv_stream, current_sandbox->client_socket_descriptor);
r = uv_tcp_open((uv_tcp_t *)&sandbox->client_libuv_stream, sandbox->client_socket_descriptor);
assert(r == 0);
#endif
}
// If the HTTP Request returns 1, we've successfully received and parsed the HTTP request, so execute it!
if (current_sandbox_receive_and_parse_client_request() > 0) {
//
current_sandbox->request_response_data_length = response_header_length;
// Initialize file descriptors 0, 1, and 2 as io handles 0, 1, 2
static inline void
sandbox_initialize_io_handles_and_file_descriptors(struct sandbox *sandbox)
{
int f = sandbox_initialize_io_handle_and_set_file_descriptor(sandbox, 0);
assert(f == 0);
f = sandbox_initialize_io_handle_and_set_file_descriptor(sandbox, 1);
assert(f == 1);
f = sandbox_initialize_io_handle_and_set_file_descriptor(sandbox, 2);
assert(f == 2);
}
// Allocate the WebAssembly Sandbox
alloc_linear_memory();
module_initialize_globals(current_module);
module_initialize_memory(current_module);
/**
* Sandbox execution logic
* Handles setup, request parsing, WebAssembly initialization, function execution, response building and sending, and
*cleanup
**/
void
current_sandbox_main(void)
{
struct sandbox *sandbox = current_sandbox_get();
// assert(sandbox != NULL);
assert(sandbox->state == RUNNABLE);
// Copy the arguments into the WebAssembly sandbox
current_sandbox_setup_arguments(argument_count);
assert(!software_interrupt_is_enabled());
arch_context_init(&sandbox->ctxt, 0, 0);
worker_thread_next_context = NULL;
software_interrupt_enable();
// Executing the function within the WebAssembly sandbox
current_sandbox->return_value = module_main(current_module, argument_count,
current_sandbox->arguments_offset);
sandbox_initialize_io_handles_and_file_descriptors(sandbox);
// Retrieve the result from the WebAssembly sandbox, construct the HTTP response, and send to client
current_sandbox_build_and_send_client_response();
}
sandbox_open_http(sandbox);
// Cleanup connection and exit sandbox
// Parse the request. 1 = Success
int rc = sandbox_receive_and_parse_client_request(sandbox);
if (rc != 1) goto err;
#ifdef USE_HTTP_UVIO
uv_close((uv_handle_t *)&current_sandbox->client_libuv_stream, libuv_callbacks_on_close_wakeup_sakebox);
worker_thread_process_io();
#else
close(current_sandbox->client_socket_descriptor);
#endif
worker_thread_exit_current_sandbox();
// Initialize the module
struct module *current_module = sandbox_get_module(sandbox);
int argument_count = module_get_argument_count(current_module);
// alloc_linear_memory();
module_initialize_globals(current_module);
module_initialize_memory(current_module);
// Copy the arguments into the WebAssembly sandbox
sandbox_setup_arguments(sandbox);
// Executing the function
sandbox->return_value = module_main(current_module, argument_count, sandbox->arguments_offset);
// Retrieve the result, construct the HTTP response, and send to client
sandbox_build_and_send_client_response(sandbox);
done:
// Cleanup connection and exit sandbox
sandbox_close_http(sandbox);
worker_thread_on_sandbox_exit(sandbox);
err:
goto done;
}
/**

@ -220,9 +220,8 @@ worker_thread_main(void *return_code)
* TODO: Consider moving this to a future current_sandbox file. This has thus far proven difficult to move
**/
void
worker_thread_exit_current_sandbox(void)
worker_thread_on_sandbox_exit(sandbox_t *exiting_sandbox)
{
struct sandbox *exiting_sandbox = current_sandbox_get();
assert(exiting_sandbox);
// TODO: I do not understand when software interrupts must be disabled?
@ -235,7 +234,7 @@ worker_thread_exit_current_sandbox(void)
// function execution"
int rc = munmap(exiting_sandbox->linear_memory_start, SBOX_MAX_MEM + PAGE_SIZE);
if (rc == -1) {
perror("worker_thread_exit_current_sandbox - munmap failed");
perror("worker_thread_on_sandbox_exit - munmap failed");
assert(0);
}

Loading…
Cancel
Save