diff --git a/runtime/include/current_sandbox.h b/runtime/include/current_sandbox.h index 44a0a65..e1bd43c 100644 --- a/runtime/include/current_sandbox.h +++ b/runtime/include/current_sandbox.h @@ -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 */ diff --git a/runtime/include/sandbox.h b/runtime/include/sandbox.h index 049f4ee..566ff9b 100644 --- a/runtime/include/sandbox.h +++ b/runtime/include/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); diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index 683a484..b438121 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -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(¤t_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(¤t_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(¤t_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(¤t_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(¤t_sandbox_get()->http_response); -} diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index edd913d..a95d67f 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -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(¤t_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(¤t_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 *)¤t_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 *)¤t_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 *)¤t_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; } /** diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 72692da..04fb352 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -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); }