chore: assorted refactors

sledge_graph
Sean McBride 5 years ago
parent c1c307c390
commit 9762477902

@ -16,7 +16,7 @@ int http_request_body_get_sb(struct sandbox *sandbox, char **body);
static inline int
http_request_body_get(char **body)
{
return http_request_body_get_sb(sandbox_current(), body);
return http_request_body_get_sb(get_current_sandbox(), body);
}
/***************************************************
@ -36,7 +36,7 @@ int http_response_vector_sb(struct sandbox *sandbox);
static inline int
http_response_header_set(char *header, int length)
{
return http_response_header_set_sb(sandbox_current(), header, length);
return http_response_header_set_sb(get_current_sandbox(), header, length);
}
/**
@ -48,7 +48,7 @@ http_response_header_set(char *header, int length)
static inline int
http_response_body_set(char *body, int length)
{
return http_response_body_set_sb(sandbox_current(), body, length);
return http_response_body_set_sb(get_current_sandbox(), body, length);
}
/**
@ -60,7 +60,7 @@ http_response_body_set(char *body, int length)
static inline int
http_response_status_set(char *status, int length)
{
return http_response_status_set_sb(sandbox_current(), status, length);
return http_response_status_set_sb(get_current_sandbox(), status, length);
}
/**
@ -70,7 +70,7 @@ http_response_status_set(char *status, int length)
static inline int
http_response_vector(void)
{
return http_response_vector_sb(sandbox_current());
return http_response_vector_sb(get_current_sandbox());
}
/***********************************************************************
@ -80,14 +80,14 @@ void http_init(void);
int http_request_parse_sb(struct sandbox *sandbox, size_t l);
/**
* Parse the current sandbox's req_resp_data up to length
* Parse the current sandbox's request_response_data up to length
* @param length
* @returns 0
**/
static inline int
http_request_parse(size_t length)
{
return http_request_parse_sb(sandbox_current(), length);
return http_request_parse_sb(get_current_sandbox(), length);
}
#endif /* SRFT_HTTP_API_H */

@ -50,7 +50,7 @@ struct module {
};
struct module *module_find_by_name(char *name);
struct module *module_find_by_socket_descriptor(int sock);
struct module *module_find_by_socket_descriptor(int socket_descriptor);
struct module *module_alloc(char *mod_name, char *mod_path, i32 argument_count, u32 stack_sz, u32 max_heap, u32 timeout, int port, int req_sz, int resp_sz);
void module_free(struct module *module);
@ -120,10 +120,10 @@ module_table_init(struct module *module)
* @param module
**/
static inline void
module_libc_init(struct module *module, i32 env, i32 args)
module_libc_init(struct module *module, i32 env, i32 arguments)
{
// called in a sandbox.
module->initialize_libc(env, args);
module->initialize_libc(env, arguments);
}
/**

@ -11,15 +11,15 @@
extern int epoll_file_descriptor;
extern struct deque_sandbox *global_deque;
extern pthread_mutex_t global_deque_mutex;
extern __thread uv_loop_t uvio;
extern __thread uv_loop_t uvio_handle;
void alloc_linear_memory(void);
void expand_memory(void);
void free_linear_memory(void *base, u32 bound, u32 max);
INLINE char *get_function_from_table(u32 idx, u32 type_id);
INLINE char *get_memory_ptr_for_runtime(u32 offset, u32 bounds_check);
void runtime_init(void);
void runtime_thd_init(void);
void initialize_runtime(void);
void initialize_listener_thread(void);
void stub_init(i32 offset);
/**
@ -61,7 +61,7 @@ get_memory_string(u32 offset)
static inline uv_loop_t *
runtime_uvio(void)
{
return &uvio;
return &uvio_handle;
}
/**

@ -11,18 +11,15 @@
#include <http.h>
struct io_handle {
int fd;
struct stat s_cache;
union uv_any_handle uvh;
int file_descriptor;
union uv_any_handle libuv_handle;
};
typedef enum
{
SANDBOX_FREE,
SANDBOX_RUNNABLE,
SANDBOX_BLOCKED,
SANDBOX_WOKEN, // for race in block()/wakeup()
SANDBOX_RETURNED, // waiting for parent to read status?
RUNNABLE,
BLOCKED,
RETURNED
} sandbox_state_t;
/*
@ -31,67 +28,72 @@ typedef enum
*/
extern void __attribute__((noreturn)) sandbox_switch_preempt(void);
// TODO: linear_memory_max_size is not really used
struct sandbox {
sandbox_state_t state;
void *linear_start; // after sandbox struct
u32 linear_size; // from after sandbox struct
u32 linear_max_size;
u32 sandbox_size;
u32 sandbox_size; // The struct plus enough buffer to hold the request or response (sized off largest)
void *linear_memory_start; // after sandbox struct
u32 linear_memory_size; // from after sandbox struct
u32 linear_memory_max_size;
void *stack_start; // guess we need a mechanism for stack allocation.
u32 stack_size; // and to set the size of it.
arch_context_t ctxt; // register context for context switch.
// TODO: are all these necessary?
// TODO: Refactor to usefully track across scheduler
u64 actual_deadline;
u64 expected_deadline;
u64 total_time;
u64 remaining_time;
u64 start_time;
struct module *module; // which module is this an instance of?
struct module *module; // the module this is an instance of
i32 args_offset; // actual placement of args in the sandbox.
void *args; // args from request, must be of module->argument_count size.
i32 retval;
i32 arguments_offset; // actual placement of arguments in the sandbox.
void *arguments; // arguments from request, must be of module->argument_count size.
i32 return_value;
struct io_handle handles[SBOX_MAX_OPEN];
struct sockaddr client; // client requesting connection!
int csock;
uv_tcp_t cuv;
uv_shutdown_t cuvsr;
struct sockaddr client_address; // client requesting connection!
int client_socket_descriptor;
uv_tcp_t client_libuv_stream;
uv_shutdown_t client_libuv_shutdown_request;
http_parser http_parser;
struct http_request http_request;
struct http_response http_response;
char * read_buf;
ssize_t read_len, read_size;
char * read_buffer;
ssize_t read_length, read_size;
// TODO: Is this used?
struct ps_list list;
ssize_t rr_data_len; // <= max(module->max_request_or_response_size)
char req_resp_data[1]; // of rr_data_sz, following sandbox mem..
ssize_t request_response_data_length; // <= max(module->max_request_or_response_size)
char request_response_data[1]; // of rr_data_sz, following sandbox mem..
} PAGE_ALIGNED;
struct sandbox_request {
struct module * module;
char * args;
int sock;
struct sockaddr *addr;
char * arguments;
int socket_descriptor;
struct sockaddr *socket_address;
u64 start_time; // cycles
};
typedef struct sandbox_request sbox_request_t;
typedef struct sandbox_request sandbox_request_t;
DEQUE_PROTOTYPE(sandbox, sbox_request_t *);
DEQUE_PROTOTYPE(sandbox, sandbox_request_t *);
static inline int sandbox_deque_push(sbox_request_t *sandbox_request);
static inline int add_sandbox_request_to_global_dequeue(sandbox_request_t *sandbox_request);
// a runtime resource, malloc on this!
struct sandbox *sandbox_alloc(struct module *module, char *args, int sock, const struct sockaddr *addr, u64 start_time);
struct sandbox *allocate_sandbox(struct module *module, char *arguments, int socket_descriptor, const struct sockaddr *socket_address, u64 start_time);
// should free stack and heap resources.. also any I/O handles.
void sandbox_free(struct sandbox *sandbox);
void free_sandbox(struct sandbox *sandbox);
extern __thread struct sandbox *current_sandbox;
// next_sandbox only used in SIGUSR1
@ -102,25 +104,25 @@ typedef struct sandbox sandbox_t;
/**
* Allocates a new Sandbox Request and places it on the Global Deque
* @param module the module we want to request
* @param args the arguments that we'll pass to the serverless function
* @param sock
* @param addr
* @param arguments the arguments that we'll pass to the serverless function
* @param socket_descriptor
* @param socket_address
* @param start_time the timestamp of when we receives the request from the network (in cycles)
* @return the new sandbox request
**/
static inline sbox_request_t *
sbox_request_alloc(struct module *module, char *args, int sock, const struct sockaddr *addr, u64 start_time)
static inline sandbox_request_t *
allocate_sandbox_request(struct module *module, char *arguments, int socket_descriptor, const struct sockaddr *socket_address, u64 start_time)
{
sbox_request_t *sandbox_request = malloc(sizeof(sbox_request_t));
sandbox_request_t *sandbox_request = malloc(sizeof(sandbox_request_t));
assert(sandbox_request);
sandbox_request->module = module;
sandbox_request->args = args;
sandbox_request->sock = sock;
sandbox_request->addr = (struct sockaddr *)addr;
sandbox_request->arguments = arguments;
sandbox_request->socket_descriptor = socket_descriptor;
sandbox_request->socket_address = (struct sockaddr *)socket_address;
sandbox_request->start_time = start_time;
debuglog("[%p: %s]\n", sandbox_request, sandbox_request->module->name);
sandbox_deque_push(sandbox_request);
add_sandbox_request_to_global_dequeue(sandbox_request);
return sandbox_request;
}
@ -129,7 +131,7 @@ sbox_request_alloc(struct module *module, char *args, int sock, const struct soc
* @returns the current sandbox executing on this thread
**/
static inline struct sandbox *
sandbox_current(void)
get_current_sandbox(void)
{
return current_sandbox;
}
@ -139,15 +141,15 @@ sandbox_current(void)
* @param sandbox the sandbox we are setting this thread to run
**/
static inline void
sandbox_current_set(struct sandbox *sandbox)
set_current_sandbox(struct sandbox *sandbox)
{
// FIXME: critical-section.
current_sandbox = sandbox;
if (sandbox == NULL) return;
// Thread Local State about the Current Sandbox
sandbox_lmbase = sandbox->linear_start;
sandbox_lmbound = sandbox->linear_size;
sandbox_lmbase = sandbox->linear_memory_start;
sandbox_lmbound = sandbox->linear_memory_size;
// TODO: module table or sandbox table?
module_indirect_table = sandbox->module->indirect_table;
}
@ -157,10 +159,10 @@ sandbox_current_set(struct sandbox *sandbox)
* This includes lmbase, lmbound, and module_indirect_table
*/
static inline void
sandbox_current_check(void)
check_current_sandbox(void)
{
struct sandbox *sandbox = sandbox_current();
assert(sandbox && sandbox->linear_start == sandbox_lmbase && sandbox->linear_size == sandbox_lmbound);
struct sandbox *sandbox = get_current_sandbox();
assert(sandbox && sandbox->linear_memory_start == sandbox_lmbase && sandbox->linear_memory_size == sandbox_lmbound);
assert(sandbox->module->indirect_table == module_indirect_table);
}
@ -170,13 +172,13 @@ sandbox_current_check(void)
* @return the module of the provided sandbox
*/
static inline struct module *
sandbox_module(struct sandbox *sandbox)
get_sandbox_module(struct sandbox *sandbox)
{
if (!sandbox) return NULL;
return sandbox->module;
}
extern void sandbox_local_end(struct sandbox *sandbox);
extern void add_sandbox_to_completion_queue(struct sandbox *sandbox);
/**
* @brief Switches to the next sandbox, placing the current sandbox of the completion queue if in RETURNED state
@ -184,15 +186,15 @@ extern void sandbox_local_end(struct sandbox *sandbox);
* @return void
*/
static inline void
sandbox_switch(struct sandbox *next_sandbox)
switch_to_sandbox(struct sandbox *next_sandbox)
{
arch_context_t *next_register_context = next_sandbox == NULL ? NULL : &next_sandbox->ctxt;
softint_disable();
struct sandbox *current_sandbox = sandbox_current();
struct sandbox *current_sandbox = get_current_sandbox();
arch_context_t *current_register_context = current_sandbox == NULL ? NULL : &current_sandbox->ctxt;
sandbox_current_set(next_sandbox);
set_current_sandbox(next_sandbox);
// If the current sandbox we're switching from is in a RETURNED state, add to completion queue
if (current_sandbox && current_sandbox->state == SANDBOX_RETURNED) sandbox_local_end(current_sandbox);
if (current_sandbox && current_sandbox->state == RETURNED) add_sandbox_to_completion_queue(current_sandbox);
next_context = next_register_context;
arch_context_switch(current_register_context, next_register_context);
softint_enable();
@ -203,35 +205,35 @@ sandbox_switch(struct sandbox *next_sandbox)
* @return the arguments of the current sandbox
*/
static inline char *
sandbox_args(void)
get_current_sandbox_arguments(void)
{
struct sandbox *sandbox = sandbox_current();
return (char *)sandbox->args;
struct sandbox *sandbox = get_current_sandbox();
return (char *)sandbox->arguments;
}
void * sandbox_run_func(void *data);
struct sandbox *sandbox_schedule(int interrupt);
void sandbox_block(void);
void sandbox_wakeup(sandbox_t *sb);
// called in sandbox_entry() before and after fn() execution
void * sandbox_worker_main(void *data);
struct sandbox *get_next_sandbox_from_local_run_queue(int interrupt);
void block_current_sandbox(void);
void wakeup_sandbox(sandbox_t *sb);
// called in sandbox_main() before and after fn() execution
// for http request/response processing using uvio
void sandbox_block_http(void);
void sandbox_response(void);
// should be the entry-point for each sandbox so it can do per-sandbox mem/etc init.
// should have been called with stack allocated and sandbox_current() set!
void sandbox_entry(void);
void sandbox_exit(void);
// should have been called with stack allocated and get_current_sandbox() set!
void sandbox_main(void);
void exit_current_sandbox(void);
extern struct deque_sandbox *global_deque;
extern pthread_mutex_t global_deque_mutex;
/**
* Pushes a sandbox request to the global deque
* @para
* @param sandbox_request
**/
static inline int
sandbox_deque_push(sbox_request_t *sandbox_request)
add_sandbox_request_to_global_dequeue(sandbox_request_t *sandbox_request)
{
int return_code;
@ -246,8 +248,12 @@ sandbox_deque_push(sbox_request_t *sandbox_request)
return return_code;
}
/**
* Pops a sandbox request from the global deque
* @param sandbox_request the pointer which we want to set to the sandbox request
**/
static inline int
sandbox_deque_pop(sbox_request_t **sandbox_request)
pop_sandbox_request_from_global_dequeue(sandbox_request_t **sandbox_request)
{
int return_code;
@ -258,20 +264,20 @@ sandbox_deque_pop(sbox_request_t **sandbox_request)
#if NCORES == 1
pthread_mutex_unlock(&global_deque_mutex);
#endif
return return_code;
}
/**
* TODO: What does this do?
* @returns A Sandbox Request or NULL
**/
static inline sbox_request_t *
sandbox_deque_steal(void)
static inline sandbox_request_t *
steal_sandbox_request_from_global_dequeue(void)
{
sbox_request_t *sandbox_request = NULL;
sandbox_request_t *sandbox_request = NULL;
#if NCORES == 1
sandbox_deque_pop(&sandbox_request);
pop_sandbox_request_from_global_dequeue(&sandbox_request);
#else
// TODO: check! is there a sandboxing thread on same core as udp-server thread?
int r = deque_steal_sandbox(global_deque, &sandbox_request);
@ -281,83 +287,93 @@ sandbox_deque_steal(void)
return sandbox_request;
}
/**
* Initializes and returns an IO handle on the current sandbox ready for use
* @return index of handle we preopened or -1 if all handles are exhausted
**/
static inline int
io_handle_preopen(void)
initialize_io_handle_in_current_sandbox(void)
{
struct sandbox *sandbox = sandbox_current();
int i;
for (i = 0; i < SBOX_MAX_OPEN; i++) {
if (sandbox->handles[i].fd < 0) break;
struct sandbox *sandbox = get_current_sandbox();
int handle_index;
for (handle_index = 0; handle_index < SBOX_MAX_OPEN; handle_index++) {
if (sandbox->handles[handle_index].file_descriptor < 0) break;
}
if (i == SBOX_MAX_OPEN) return -1;
sandbox->handles[i].fd = SBOX_PREOPEN_MAGIC;
memset(&sandbox->handles[i].uvh, 0, sizeof(union uv_any_handle));
return i;
if (handle_index == SBOX_MAX_OPEN) return -1;
sandbox->handles[handle_index].file_descriptor = SBOX_PREOPEN_MAGIC;
memset(&sandbox->handles[handle_index].libuv_handle, 0, sizeof(union uv_any_handle));
return handle_index;
}
/**
* 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 handles are exhausted
**/
static inline int
io_handle_open(int fd)
initialize_io_handle_and_set_file_descriptor_in_current_sandbox(int file_descriptor)
{
struct sandbox *sandbox = sandbox_current();
if (fd < 0) return fd;
int i = io_handle_preopen();
sandbox->handles[i].fd = fd; // well, per sandbox.. so synchronization necessary!
return i;
struct sandbox *sandbox = get_current_sandbox();
if (file_descriptor < 0) return file_descriptor;
int handle_index = initialize_io_handle_in_current_sandbox();
if (handle_index != -1) sandbox->handles[handle_index].file_descriptor = file_descriptor; // well, per sandbox.. so synchronization necessary!
return handle_index;
}
/**
* Sets the file descriptor of the sandbox's ith io_handle
* Returns error condition if the fd to set does not contain sandbox preopen magin
* @param idx index of the sandbox handles we want to set
* @param fd the file descripter we want to set it to
* @returns the idx that was set or -1 in case of error
* Returns error condition if the file_descriptor to set does not contain sandbox preopen magin
* @param handle_index index of the sandbox handles we want to set
* @param file_descriptor the file descripter we want to set it to
* @returns the index that was set or -1 in case of error
**/
static inline int
io_handle_preopen_set(int idx, int fd)
set_current_sandbox_file_descriptor(int handle_index, int file_descriptor)
{
struct sandbox *sandbox = sandbox_current();
if (idx >= SBOX_MAX_OPEN || idx < 0) return -1;
if (fd < 0 || sandbox->handles[idx].fd != SBOX_PREOPEN_MAGIC) return -1;
sandbox->handles[idx].fd = fd;
return idx;
struct sandbox *sandbox = get_current_sandbox();
if (handle_index >= SBOX_MAX_OPEN || handle_index < 0) return -1;
if (file_descriptor < 0 || sandbox->handles[handle_index].file_descriptor != SBOX_PREOPEN_MAGIC) return -1;
sandbox->handles[handle_index].file_descriptor = file_descriptor;
return handle_index;
}
/**
* Get the file descriptor of the sandbox's ith io_handle
* @param idx index into the sandbox's handles table
* @returns any libuv handle
* @param handle_index index into the sandbox's handles table
* @returns file descriptor
**/
static inline int
io_handle_fd(int idx)
get_current_sandbox_file_descriptor(int handle_index)
{
struct sandbox *sandbox = sandbox_current();
if (idx >= SBOX_MAX_OPEN || idx < 0) return -1;
return sandbox->handles[idx].fd;
struct sandbox *sandbox = get_current_sandbox();
if (handle_index >= SBOX_MAX_OPEN || handle_index < 0) return -1;
return sandbox->handles[handle_index].file_descriptor;
}
/**
* Close the sandbox's ith io_handle
* @param idx index of the handle to close
* @param handle_index index of the handle to close
**/
static inline void
io_handle_close(int idx)
close_current_sandbox_file_descriptor(int handle_index)
{
struct sandbox *sandbox = sandbox_current();
if (idx >= SBOX_MAX_OPEN || idx < 0) return;
sandbox->handles[idx].fd = -1;
struct sandbox *sandbox = get_current_sandbox();
if (handle_index >= SBOX_MAX_OPEN || handle_index < 0) return;
// TODO: Do we actually need to call some sort of close function here?
sandbox->handles[handle_index].file_descriptor = -1;
}
/**
* Get the Libuv handle located at idx of the sandbox ith io_handle
* @param idx index of the handle containing uvh???
* @param handle_index index of the handle containing libuv_handle???
* @returns any libuv handle
**/
static inline union uv_any_handle *
io_handle_uv_get(int idx)
get_current_sandbox_libuv_handle(int handle_index)
{
struct sandbox *sandbox = sandbox_current();
if (idx >= SBOX_MAX_OPEN || idx < 0) return NULL;
return &sandbox->handles[idx].uvh;
struct sandbox *sandbox = get_current_sandbox();
if (handle_index >= SBOX_MAX_OPEN || handle_index < 0) return NULL;
return &sandbox->handles[handle_index].libuv_handle;
}
#endif /* SFRT_SANDBOX_H */

@ -38,7 +38,7 @@ http_request_body_get_sb(struct sandbox *sandbox, char **body)
int
http_response_header_set_sb(struct sandbox *sandbox, char *header, int length)
{
// by now, req_resp_data should only be containing response!
// by now, request_response_data should only be containing response!
struct http_response *http_response = &sandbox->http_response;
assert(http_response->header_count < HTTP_HEADERS_MAX);
@ -197,7 +197,7 @@ http_on_header_field(http_parser *parser, const char *at, size_t length)
assert(length < HTTP_HEADER_MAXSZ);
http_request->last_was_value = 0;
http_request->headers[http_request->header_count - 1].key = (char *)at; // it is from the sandbox's req_resp_data, should persist.
http_request->headers[http_request->header_count - 1].key = (char *)at; // it is from the sandbox's request_response_data, should persist.
return 0;
}
@ -220,7 +220,7 @@ http_on_header_value(http_parser *parser, const char *at, size_t length)
assert(http_request->header_count <= HTTP_HEADERS_MAX);
assert(length < HTTP_HEADERVAL_MAXSZ);
http_request->headers[http_request->header_count - 1].value = (char *)at; // it is from the sandbox's req_resp_data, should persist.
http_request->headers[http_request->header_count - 1].value = (char *)at; // it is from the sandbox's request_response_data, should persist.
return 0;
}
@ -300,9 +300,9 @@ http_init(void)
}
/**
* Run the http-parser on the sandbox's req_resp_data using the configured settings global
* Run the http-parser on the sandbox's request_response_data using the configured settings global
* @param sandbox the sandbox containing the req_resp data that we want to parse
* @param length The size of the req_resp_data that we want to parse
* @param length The size of the request_response_data that we want to parse
* @returns 0
*
* Global State: settings
@ -310,7 +310,7 @@ http_init(void)
int
http_request_parse_sb(struct sandbox *sandbox, size_t length)
{
// TODO: Why is our start address sandbox->req_resp_data + sandbox->rr_data_len?
http_parser_execute(&sandbox->http_parser, &settings, sandbox->req_resp_data + sandbox->rr_data_len, length);
// TODO: Why is our start address sandbox->request_response_data + sandbox->request_response_data_length?
http_parser_execute(&sandbox->http_parser, &settings, sandbox->request_response_data + sandbox->request_response_data_length, length);
return 0;
}

@ -33,7 +33,7 @@ void
stub_init(i32 offset)
{
// What program name will we put in the auxiliary vectors
char *program_name = sandbox_current()->module->name;
char *program_name = get_current_sandbox()->module->name;
// Copy the program name into WASM accessible memory
i32 program_name_offset = offset;
strcpy(get_memory_ptr_for_runtime(offset, sizeof(program_name)), program_name);
@ -64,7 +64,7 @@ stub_init(i32 offset)
i32 env_vec_offset = offset;
memcpy(get_memory_ptr_for_runtime(env_vec_offset, sizeof(env_vec)), env_vec, sizeof(env_vec));
module_libc_init(sandbox_current()->module, env_vec_offset, program_name_offset);
module_libc_init(get_current_sandbox()->module, env_vec_offset, program_name_offset);
}
// Emulated syscall implementations
@ -88,14 +88,14 @@ uv_fs_get_type(uv_fs_t *req)
#define UV_FS_REQ_INIT() \
{ \
.data = sandbox_current(), .result = 0 \
.data = get_current_sandbox(), .result = 0 \
}
static void
wasm_fs_callback(uv_fs_t *req)
{
debuglog("[%p]\n", req->data);
sandbox_wakeup((sandbox_t *)req->data);
wakeup_sandbox((sandbox_t *)req->data);
}
// We define our own syscall numbers, because WASM uses x86_64 values even on systems that are not x86_64
@ -105,7 +105,7 @@ wasm_read(i32 filedes, i32 buf_offset, i32 nbyte)
{
if (filedes == 0) {
char * buffer = get_memory_ptr_void(buf_offset, nbyte);
struct sandbox * s = sandbox_current();
struct sandbox * s = get_current_sandbox();
struct http_request *r = &s->http_request;
if (r->body_length <= 0) return 0;
int l = nbyte > r->body_length ? r->body_length : nbyte;
@ -114,7 +114,7 @@ wasm_read(i32 filedes, i32 buf_offset, i32 nbyte)
r->body_length -= l;
return l;
}
int f = io_handle_fd(filedes);
int f = get_current_sandbox_file_descriptor(filedes);
// TODO: read on other file types
uv_fs_t req = UV_FS_REQ_INIT();
char * buffer = get_memory_ptr_void(buf_offset, nbyte);
@ -122,7 +122,7 @@ wasm_read(i32 filedes, i32 buf_offset, i32 nbyte)
debuglog("[%p] start[%d:%d, n%d]\n", uv_fs_get_data(&req), filedes, f, nbyte);
uv_buf_t bufv = uv_buf_init(buffer, nbyte);
uv_fs_read(runtime_uvio(), &req, f, &bufv, 1, -1, wasm_fs_callback);
sandbox_block();
block_current_sandbox();
int ret = uv_fs_get_result(&req);
debuglog("[%p] end[%d]\n", uv_fs_get_data(&req), ret);
@ -133,27 +133,27 @@ wasm_read(i32 filedes, i32 buf_offset, i32 nbyte)
#define SYS_WRITE 1
i32
wasm_write(i32 fd, i32 buf_offset, i32 buf_size)
wasm_write(i32 file_descriptor, i32 buf_offset, i32 buf_size)
{
if (fd == 1 || fd == 2) {
if (file_descriptor == 1 || file_descriptor == 2) {
char * buffer = get_memory_ptr_void(buf_offset, buf_size);
struct sandbox *s = sandbox_current();
int l = s->module->max_response_size - s->rr_data_len;
struct sandbox *s = get_current_sandbox();
int l = s->module->max_response_size - s->request_response_data_length;
l = l > buf_size ? buf_size : l;
if (l == 0) return 0;
memcpy(s->req_resp_data + s->rr_data_len, buffer, l);
s->rr_data_len += l;
memcpy(s->request_response_data + s->request_response_data_length, buffer, l);
s->request_response_data_length += l;
return l;
}
int f = io_handle_fd(fd);
int f = get_current_sandbox_file_descriptor(file_descriptor);
// TODO: read on other file types
uv_fs_t req = UV_FS_REQ_INIT();
char * buffer = get_memory_ptr_void(buf_offset, buf_size);
uv_buf_t bufv = uv_buf_init(buffer, buf_size);
uv_fs_write(runtime_uvio(), &req, f, &bufv, 1, -1, wasm_fs_callback);
sandbox_block();
block_current_sandbox();
int ret = uv_fs_get_result(&req);
uv_fs_req_cleanup(&req);
@ -184,7 +184,7 @@ wasm_open(i32 path_off, i32 flags, i32 mode)
uv_fs_t req = UV_FS_REQ_INIT();
char * path = get_memory_string(path_off);
int iofd = io_handle_preopen();
int iofd = initialize_io_handle_in_current_sandbox();
if (iofd < 0) return -1;
i32 modified_flags = 0;
if (flags & WO_RDONLY) modified_flags |= O_RDONLY;
@ -196,29 +196,29 @@ wasm_open(i32 path_off, i32 flags, i32 mode)
debuglog("[%p] start[%s:%d:%d]\n", uv_fs_get_data(&req), path, flags, modified_flags);
uv_fs_open(runtime_uvio(), &req, path, modified_flags, mode, wasm_fs_callback);
sandbox_block();
block_current_sandbox();
int ret = uv_fs_get_result(&req);
debuglog("[%p] end[%d]\n", uv_fs_get_data(&req), ret);
uv_fs_req_cleanup(&req);
if (ret < 0)
io_handle_close(iofd);
close_current_sandbox_file_descriptor(iofd);
else
io_handle_preopen_set(iofd, ret);
set_current_sandbox_file_descriptor(iofd, ret);
return iofd;
}
#define SYS_CLOSE 3
i32
wasm_close(i32 fd)
wasm_close(i32 file_descriptor)
{
if (fd >= 0 && fd <= 2) { return 0; }
struct sandbox * c = sandbox_current();
int d = io_handle_fd(fd);
union uv_any_handle *h = io_handle_uv_get(fd);
if (file_descriptor >= 0 && file_descriptor <= 2) { return 0; }
struct sandbox * c = get_current_sandbox();
int d = get_current_sandbox_file_descriptor(file_descriptor);
union uv_any_handle *h = get_current_sandbox_libuv_handle(file_descriptor);
uv_handle_type type = ((uv_handle_t *)h)->type;
debuglog("[%p] [%d,%d]\n", c, fd, d);
debuglog("[%p] [%d,%d]\n", c, file_descriptor, d);
if (type == UV_TCP) {
debuglog("[%p] close tcp\n", c);
@ -231,14 +231,14 @@ wasm_close(i32 fd)
}
uv_fs_t req = UV_FS_REQ_INIT();
debuglog("[%p] file[%d,%d]\n", uv_fs_get_data(&req), fd, d);
debuglog("[%p] file[%d,%d]\n", uv_fs_get_data(&req), file_descriptor, d);
uv_fs_close(runtime_uvio(), &req, d, wasm_fs_callback);
sandbox_block();
block_current_sandbox();
int ret = uv_fs_get_result(&req);
debuglog("[%p] end[%d]\n", uv_fs_get_data(&req), ret);
uv_fs_req_cleanup(&req);
if (ret == 0) io_handle_close(fd);
if (ret == 0) close_current_sandbox_file_descriptor(file_descriptor);
return ret;
}
@ -344,7 +344,7 @@ wasm_fstat(i32 filedes, i32 stat_offset)
struct wasm_stat *stat_ptr = get_memory_ptr_void(stat_offset, sizeof(struct wasm_stat));
struct stat stat;
int d = io_handle_fd(filedes);
int d = get_current_sandbox_file_descriptor(filedes);
i32 res = fstat(d, &stat);
if (res == -1) return -errno;
@ -434,7 +434,7 @@ wasm_lstat(i32 path_str_offset, i32 stat_offset)
i32
wasm_lseek(i32 filedes, i32 file_offset, i32 whence)
{
int d = io_handle_fd(filedes);
int d = get_current_sandbox_file_descriptor(filedes);
i32 res = (i32)lseek(d, file_offset, whence);
if (res == -1) return -errno;
@ -444,10 +444,10 @@ wasm_lseek(i32 filedes, i32 file_offset, i32 whence)
#define SYS_MMAP 9
u32
wasm_mmap(i32 addr, i32 len, i32 prot, i32 flags, i32 fd, i32 offset)
wasm_mmap(i32 addr, i32 len, i32 prot, i32 flags, i32 file_descriptor, i32 offset)
{
int d = io_handle_fd(fd);
if (fd >= 0) assert(d >= 0);
int d = get_current_sandbox_file_descriptor(file_descriptor);
if (file_descriptor >= 0) assert(d >= 0);
if (addr != 0) {
printf("parameter void *addr is not supported!\n");
assert(0);
@ -476,9 +476,9 @@ wasm_mmap(i32 addr, i32 len, i32 prot, i32 flags, i32 fd, i32 offset)
#define SYS_IOCTL 16
i32
wasm_ioctl(i32 fd, i32 request, i32 data_offet)
wasm_ioctl(i32 file_descriptor, i32 request, i32 data_offet)
{
// int d = io_handle_fd(fd);
// int d = get_current_sandbox_file_descriptor(file_descriptor);
// musl libc does some ioctls to stdout, so just allow these to silently go through
// FIXME: The above is idiotic
// assert(d == 1);
@ -492,13 +492,13 @@ struct wasm_iovec {
};
i32
wasm_readv(i32 fd, i32 iov_offset, i32 iovcnt)
wasm_readv(i32 file_descriptor, i32 iov_offset, i32 iovcnt)
{
if (fd == 0) {
if (file_descriptor == 0) {
// both 1 and 2 go to client.
int len = 0;
struct wasm_iovec * iov = get_memory_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec));
struct sandbox * s = sandbox_current();
struct sandbox * s = get_current_sandbox();
struct http_request *r = &s->http_request;
if (r->body_length <= 0) return 0;
for (int i = 0; i < iovcnt; i++) {
@ -516,7 +516,7 @@ wasm_readv(i32 fd, i32 iov_offset, i32 iovcnt)
}
// TODO: read on other file types
int gret = 0;
int d = io_handle_fd(fd);
int d = get_current_sandbox_file_descriptor(file_descriptor);
struct wasm_iovec *iov = get_memory_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec));
for (int i = 0; i < iovcnt; i += RDWR_VEC_MAX) {
@ -528,9 +528,9 @@ wasm_readv(i32 fd, i32 iov_offset, i32 iovcnt)
bufs[j] = uv_buf_init(get_memory_ptr_void(iov[i + j].base_offset, iov[i + j].len),
iov[i + j].len);
}
debuglog("[%p] start[%d,%d, n%d:%d]\n", uv_fs_get_data(&req), fd, d, i, j);
debuglog("[%p] start[%d,%d, n%d:%d]\n", uv_fs_get_data(&req), file_descriptor, d, i, j);
uv_fs_read(runtime_uvio(), &req, d, bufs, j, -1, wasm_fs_callback);
sandbox_block();
block_current_sandbox();
int ret = uv_fs_get_result(&req);
debuglog("[%p] end[%d]\n", uv_fs_get_data(&req), ret);
@ -545,24 +545,24 @@ wasm_readv(i32 fd, i32 iov_offset, i32 iovcnt)
#define SYS_WRITEV 20
i32
wasm_writev(i32 fd, i32 iov_offset, i32 iovcnt)
wasm_writev(i32 file_descriptor, i32 iov_offset, i32 iovcnt)
{
struct sandbox *c = sandbox_current();
if (fd == 1 || fd == 2) {
struct sandbox *c = get_current_sandbox();
if (file_descriptor == 1 || file_descriptor == 2) {
// both 1 and 2 go to client.
int len = 0;
struct wasm_iovec *iov = get_memory_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec));
for (int i = 0; i < iovcnt; i++) {
char *b = get_memory_ptr_void(iov[i].base_offset, iov[i].len);
memcpy(c->req_resp_data + c->rr_data_len, b, iov[i].len);
c->rr_data_len += iov[i].len;
memcpy(c->request_response_data + c->request_response_data_length, b, iov[i].len);
c->request_response_data_length += iov[i].len;
len += iov[i].len;
}
return len;
}
// TODO: read on other file types
int d = io_handle_fd(fd);
int d = get_current_sandbox_file_descriptor(file_descriptor);
int gret = 0;
struct wasm_iovec *iov = get_memory_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec));
@ -575,9 +575,9 @@ wasm_writev(i32 fd, i32 iov_offset, i32 iovcnt)
bufs[j] = uv_buf_init(get_memory_ptr_void(iov[i + j].base_offset, iov[i + j].len),
iov[i + j].len);
}
debuglog("[%p] start[%d,%d, n%d:%d]\n", uv_fs_get_data(&req), fd, d, i, j);
debuglog("[%p] start[%d,%d, n%d:%d]\n", uv_fs_get_data(&req), file_descriptor, d, i, j);
uv_fs_write(runtime_uvio(), &req, d, bufs, j, -1, wasm_fs_callback);
sandbox_block();
block_current_sandbox();
int ret = uv_fs_get_result(&req);
debuglog("[%p] end[%d]\n", uv_fs_get_data(&req), ret);
@ -617,9 +617,9 @@ wasm_getpid()
#define SYS_FCNTL 72
u32
wasm_fcntl(u32 fd, u32 cmd, u32 arg_or_lock_ptr)
wasm_fcntl(u32 file_descriptor, u32 cmd, u32 arg_or_lock_ptr)
{
int d = io_handle_fd(fd);
int d = get_current_sandbox_file_descriptor(file_descriptor);
switch (cmd) {
case WF_SETFD:
// return fcntl(d, F_SETFD, arg_or_lock_ptr);
@ -633,13 +633,13 @@ wasm_fcntl(u32 fd, u32 cmd, u32 arg_or_lock_ptr)
#define SYS_FSYNC 74
u32
wasm_fsync(u32 fd)
wasm_fsync(u32 file_descriptor)
{
int d = io_handle_fd(fd);
int d = get_current_sandbox_file_descriptor(file_descriptor);
uv_fs_t req = UV_FS_REQ_INIT();
debuglog("[%p] start[%d,%d]\n", uv_fs_get_data(&req), fd, d);
debuglog("[%p] start[%d,%d]\n", uv_fs_get_data(&req), file_descriptor, d);
uv_fs_fsync(runtime_uvio(), &req, d, wasm_fs_callback);
sandbox_block();
block_current_sandbox();
int ret = uv_fs_get_result(&req);
debuglog("[%p] end[%d]\n", uv_fs_get_data(&req), ret);
@ -667,7 +667,7 @@ wasm_unlink(u32 path_str_offset)
uv_fs_t req = UV_FS_REQ_INIT();
debuglog("[%p] start[%s]\n", uv_fs_get_data(&req), str);
uv_fs_unlink(runtime_uvio(), &req, str, wasm_fs_callback);
sandbox_block();
block_current_sandbox();
int ret = uv_fs_get_result(&req);
debuglog("[%p] end[%d]\n", uv_fs_get_data(&req), ret);
@ -733,13 +733,13 @@ wasm_exit_group(i32 status)
#define SYS_FCHOWN 93
i32
wasm_fchown(i32 fd, u32 owner, u32 group)
wasm_fchown(i32 file_descriptor, u32 owner, u32 group)
{
int d = io_handle_fd(fd);
int d = get_current_sandbox_file_descriptor(file_descriptor);
uv_fs_t req = UV_FS_REQ_INIT();
debuglog("[%p] start[%d,%d]\n", uv_fs_get_data(&req), fd, d);
debuglog("[%p] start[%d,%d]\n", uv_fs_get_data(&req), file_descriptor, d);
uv_fs_fchown(runtime_uvio(), &req, d, owner, group, wasm_fs_callback);
sandbox_block();
block_current_sandbox();
int ret = uv_fs_get_result(&req);
debuglog("[%p] end[%d]\n", uv_fs_get_data(&req), ret);
@ -760,8 +760,8 @@ wasm_connection_callback(uv_stream_t *srv, int status)
{
sandbox_t *s = srv->data;
debuglog(" [%p]\n", s);
s->retval = status;
sandbox_wakeup(s);
s->return_value = status;
wakeup_sandbox(s);
}
static void
@ -770,19 +770,19 @@ wasm_connect_callback(uv_connect_t *req, int status)
// TODO: how do we use the handle in uv_connect_t ??
sandbox_t *s = req->data;
debuglog(" [%p]\n", s);
s->retval = status;
sandbox_wakeup(s);
s->return_value = status;
wakeup_sandbox(s);
}
i32
wasm_socket(i32 domain, i32 type, i32 protocol)
{
struct sandbox *c = sandbox_current();
int pfd = io_handle_preopen(), fd = -1;
struct sandbox *c = get_current_sandbox();
int pfd = initialize_io_handle_in_current_sandbox(), file_descriptor = -1;
// TODO: use domain, type and protocol in libuv?
debuglog("[%p] => %d %d %d\n", c, domain, type, protocol);
if (pfd < 0) return pfd;
union uv_any_handle *h = io_handle_uv_get(pfd);
union uv_any_handle *h = get_current_sandbox_libuv_handle(pfd);
if (type & SOCK_DGRAM) {
uv_udp_t *uh = (uv_udp_t *)h;
@ -804,10 +804,10 @@ wasm_socket(i32 domain, i32 type, i32 protocol)
i32
wasm_connect(i32 sockfd, i32 sockaddr_offset, i32 addrlen)
{
struct sandbox *c = sandbox_current();
int fd = io_handle_fd(sockfd);
debuglog("[%p] [%d, %d]\n", c, sockfd, fd);
union uv_any_handle *h = io_handle_uv_get(sockfd);
struct sandbox *c = get_current_sandbox();
int file_descriptor = get_current_sandbox_file_descriptor(sockfd);
debuglog("[%p] [%d, %d]\n", c, sockfd, file_descriptor);
union uv_any_handle *h = get_current_sandbox_libuv_handle(sockfd);
uv_handle_type t = ((uv_handle_t *)h)->type;
if (t == UV_TCP) {
@ -815,10 +815,10 @@ wasm_connect(i32 sockfd, i32 sockaddr_offset, i32 addrlen)
debuglog("[%p] connect\n", c);
int r = uv_tcp_connect(&req, (uv_tcp_t *)h, get_memory_ptr_void(sockaddr_offset, addrlen),
wasm_connect_callback);
sandbox_block();
block_current_sandbox();
debuglog("[%p] %d\n", c, c->retval);
return c->retval;
debuglog("[%p] %d\n", c, c->return_value);
return c->return_value;
} else if (t == UV_UDP) {
debuglog(" UDP connect not implemented!\n");
// TODO: this api is in the doc online but not in the libuv installed.. perhaps update??
@ -834,28 +834,28 @@ wasm_accept(i32 sockfd, i32 sockaddr_offset, i32 addrlen_offset)
{
// what do we do with the sockaddr ????
socklen_t * addrlen = get_memory_ptr_void(addrlen_offset, sizeof(socklen_t));
struct sockaddr * addr = get_memory_ptr_void(sockaddr_offset, *addrlen);
union uv_any_handle *s = io_handle_uv_get(sockfd);
int cfd = io_handle_preopen();
struct sockaddr * socket_address = get_memory_ptr_void(sockaddr_offset, *addrlen);
union uv_any_handle *s = get_current_sandbox_libuv_handle(sockfd);
int cfd = initialize_io_handle_in_current_sandbox();
if (cfd < 0) return -1;
struct sandbox *c = sandbox_current();
debuglog("[%p] [%d, %d]\n", c, sockfd, io_handle_fd(sockfd));
struct sandbox *c = get_current_sandbox();
debuglog("[%p] [%d, %d]\n", c, sockfd, get_current_sandbox_file_descriptor(sockfd));
// assert so we can look into whether we need to implement UDP or others..
assert(((uv_handle_t *)s)->type == UV_TCP);
union uv_any_handle *h = io_handle_uv_get(cfd);
union uv_any_handle *h = get_current_sandbox_libuv_handle(cfd);
uv_tcp_init(runtime_uvio(), (uv_tcp_t *)h);
debuglog("[%p] tcp init %d\n", c, cfd);
int r = uv_accept((uv_stream_t *)s, (uv_stream_t *)h);
if (r < 0) return r;
// TODO: if accept fails, what do we do with the preopened handle?
// if (r < 0) io_handle_close(cfd);
// if (r < 0) close_current_sandbox_file_descriptor(cfd);
// we've to also remove it from the runtime loop??
int r2 = -1, f = -1;
r2 = uv_fileno((uv_handle_t *)h, &f);
if (r2 < 0 || f < 0) assert(0);
io_handle_preopen_set(cfd, f);
set_current_sandbox_file_descriptor(cfd, f);
debuglog("[%p] done[%d,%d]\n", c, cfd, f);
return cfd;
@ -864,30 +864,30 @@ wasm_accept(i32 sockfd, i32 sockaddr_offset, i32 addrlen_offset)
i32
wasm_bind(i32 sockfd, i32 sockaddr_offset, i32 addrlen)
{
struct sandbox *c = sandbox_current();
int fd = io_handle_fd(sockfd);
debuglog("[%p] [%d,%d]\n", c, sockfd, fd);
union uv_any_handle *h = io_handle_uv_get(sockfd);
struct sandbox *c = get_current_sandbox();
int file_descriptor = get_current_sandbox_file_descriptor(sockfd);
debuglog("[%p] [%d,%d]\n", c, sockfd, file_descriptor);
union uv_any_handle *h = get_current_sandbox_libuv_handle(sockfd);
uv_handle_type t = ((uv_handle_t *)h)->type;
if (t == UV_TCP) {
debuglog("[%p] tcp\n", c);
int r1 = uv_tcp_bind((uv_tcp_t *)h, get_memory_ptr_void(sockaddr_offset, addrlen), 0 /* TODO: flags */);
if (fd == SBOX_PREOPEN_MAGIC) {
if (file_descriptor == SBOX_PREOPEN_MAGIC) {
int r2 = -1, f = -1;
r2 = uv_fileno((uv_handle_t *)h, &f);
debuglog("[%p] [%d,%d]\n", c, f, fd);
io_handle_preopen_set(sockfd, f);
debuglog("[%p] [%d,%d]\n", c, f, file_descriptor);
set_current_sandbox_file_descriptor(sockfd, f);
}
return r1;
} else if (t == UV_UDP) {
debuglog("[%p] udp\n", c);
int r1 = uv_udp_bind((uv_udp_t *)h, get_memory_ptr_void(sockaddr_offset, addrlen), 0 /* TODO: flags */);
if (fd == SBOX_PREOPEN_MAGIC) {
if (file_descriptor == SBOX_PREOPEN_MAGIC) {
int r2 = -1, f = -1;
r2 = uv_fileno((uv_handle_t *)h, &f);
debuglog("[%p] [%d,%d]\n", c, f, fd);
io_handle_preopen_set(sockfd, f);
debuglog("[%p] [%d,%d]\n", c, f, file_descriptor);
set_current_sandbox_file_descriptor(sockfd, f);
}
return r1;
}
@ -899,20 +899,20 @@ wasm_bind(i32 sockfd, i32 sockaddr_offset, i32 addrlen)
i32
wasm_listen(i32 sockfd, i32 backlog)
{
struct sandbox * c = sandbox_current();
union uv_any_handle *h = io_handle_uv_get(sockfd);
struct sandbox * c = get_current_sandbox();
union uv_any_handle *h = get_current_sandbox_libuv_handle(sockfd);
assert(c == (struct sandbox *)(((uv_tcp_t *)h)->data));
debuglog("[%p] [%d,%d]\n", c, sockfd, io_handle_fd(sockfd));
debuglog("[%p] [%d,%d]\n", c, sockfd, get_current_sandbox_file_descriptor(sockfd));
uv_handle_type t = ((uv_handle_t *)h)->type;
// assert so we can look into whether we need to implement UDP or others..
assert(t == UV_TCP);
int r = uv_listen((uv_stream_t *)h, backlog, wasm_connection_callback);
sandbox_block();
block_current_sandbox();
debuglog("[%p] %d\n", c, c->retval);
return c->retval;
debuglog("[%p] %d\n", c, c->return_value);
return c->return_value;
}
#define SYS_SENDTO 44
@ -924,56 +924,56 @@ wasm_read_callback(uv_stream_t *s, ssize_t nread, const uv_buf_t *buffer)
struct sandbox *c = s->data;
debuglog("[%p] %ld %p\n", c, nread, buffer);
if (nread < 0) c->retval = -EIO;
c->read_len = nread;
debuglog("[%p] %ld\n", c, c->read_len);
if (nread < 0) c->return_value = -EIO;
c->read_length = nread;
debuglog("[%p] %ld\n", c, c->read_length);
uv_read_stop(s);
sandbox_wakeup(c);
wakeup_sandbox(c);
}
void
wasm_write_callback(uv_write_t *req, int status)
{
struct sandbox *c = req->data;
c->retval = status;
c->return_value = status;
debuglog("[%p] %d\n", c, status);
sandbox_wakeup(c);
wakeup_sandbox(c);
}
void
wasm_udp_recv_callback(uv_udp_t *h, ssize_t nread, const uv_buf_t *buffer, const struct sockaddr *addr, unsigned flags)
wasm_udp_recv_callback(uv_udp_t *h, ssize_t nread, const uv_buf_t *buffer, const struct sockaddr *socket_address, unsigned flags)
{
struct sandbox *c = h->data;
debuglog("[%p] %ld %p\n", c, nread, buffer);
if (nread < 0) c->retval = -EIO;
c->read_len = nread;
debuglog("[%p] %ld\n", c, c->read_len);
if (nread < 0) c->return_value = -EIO;
c->read_length = nread;
debuglog("[%p] %ld\n", c, c->read_length);
uv_udp_recv_stop(h);
sandbox_wakeup(c);
wakeup_sandbox(c);
}
void
wasm_udp_send_callback(uv_udp_send_t *req, int status)
{
struct sandbox *c = req->data;
c->retval = status;
c->return_value = status;
debuglog("[%p] %d\n", c, status);
sandbox_wakeup(c);
wakeup_sandbox(c);
}
i32
wasm_sendto(i32 fd, i32 buff_offset, i32 len, i32 flags, i32 sockaddr_offset, i32 sockaddr_len)
wasm_sendto(i32 file_descriptor, i32 buff_offset, i32 len, i32 flags, i32 sockaddr_offset, i32 sockaddr_len)
{
char *buffer = get_memory_ptr_void(buff_offset, len);
// TODO: only support "send" api for now
assert(sockaddr_len == 0);
struct sandbox * c = sandbox_current();
union uv_any_handle *h = io_handle_uv_get(fd);
struct sandbox * c = get_current_sandbox();
union uv_any_handle *h = get_current_sandbox_libuv_handle(file_descriptor);
uv_handle_type t = ((uv_handle_t *)h)->type;
debuglog("[%p] [%d,%d]\n", c, fd, io_handle_fd(fd));
debuglog("[%p] [%d,%d]\n", c, file_descriptor, get_current_sandbox_file_descriptor(file_descriptor));
if (t == UV_TCP) {
uv_write_t req = {
@ -982,10 +982,10 @@ wasm_sendto(i32 fd, i32 buff_offset, i32 len, i32 flags, i32 sockaddr_offset, i3
uv_buf_t b = uv_buf_init(buffer, len);
debuglog("[%p] tcp\n", c);
int ret = uv_write(&req, (uv_stream_t *)h, &b, 1, wasm_write_callback);
sandbox_block();
block_current_sandbox();
debuglog("[%p] %d\n", c, c->retval);
return c->retval;
debuglog("[%p] %d\n", c, c->return_value);
return c->return_value;
} else if (t == UV_UDP) {
uv_udp_send_t req = {
.data = c,
@ -994,10 +994,10 @@ wasm_sendto(i32 fd, i32 buff_offset, i32 len, i32 flags, i32 sockaddr_offset, i3
debuglog("[%p] udp\n", c);
// TODO: sockaddr!
int r = uv_udp_send(&req, (uv_udp_t *)h, &b, 1, NULL, wasm_udp_send_callback);
sandbox_block();
block_current_sandbox();
debuglog("[%p] %d\n", c, c->retval);
return c->retval;
debuglog("[%p] %d\n", c, c->return_value);
return c->return_value;
}
debuglog("[%p] unimplemented\n", c);
assert(0);
@ -1010,53 +1010,53 @@ wasm_alloc_callback(uv_handle_t *h, size_t suggested, uv_buf_t *buffer)
struct sandbox *s = h->data;
// just let it use what is passed from caller!
buffer->base = s->read_buf;
buffer->base = s->read_buffer;
buffer->len = s->read_size;
}
i32
wasm_recvfrom(i32 fd, i32 buff_offset, i32 size, i32 flags, i32 sockaddr_offset, i32 socklen_offset)
wasm_recvfrom(i32 file_descriptor, i32 buff_offset, i32 size, i32 flags, i32 sockaddr_offset, i32 socklen_offset)
{
char * buffer = get_memory_ptr_void(buff_offset, size);
socklen_t *len = get_memory_ptr_void(socklen_offset, sizeof(socklen_t));
// TODO: only support "recv" api for now
assert(*len == 0);
struct sandbox * c = sandbox_current();
union uv_any_handle *h = io_handle_uv_get(fd);
struct sandbox * c = get_current_sandbox();
union uv_any_handle *h = get_current_sandbox_libuv_handle(file_descriptor);
uv_handle_type t = ((uv_handle_t *)h)->type;
debuglog("[%p] [%d,%d]\n", c, fd, io_handle_fd(fd));
debuglog("[%p] [%d,%d]\n", c, file_descriptor, get_current_sandbox_file_descriptor(file_descriptor));
// uv stream API are not simple wrappers on read/write..
// and there will only be one system call pending..
// so we keep the read buffer pointers in sandbox structure..
// for use in the callbacks..
c->read_buf = buffer;
c->read_buffer = buffer;
c->read_size = size;
c->read_len = 0;
c->retval = 0;
c->read_length = 0;
c->return_value = 0;
// TODO: what if stream read more than what "size" is here??
if (t == UV_TCP) {
((uv_stream_t *)h)->data = c;
debuglog("[%p] tcp\n", c);
int r = uv_read_start((uv_stream_t *)h, wasm_alloc_callback, wasm_read_callback);
sandbox_block();
debuglog("[%p] %d\n", c, c->retval);
if (c->retval == -EIO) {
block_current_sandbox();
debuglog("[%p] %d\n", c, c->return_value);
if (c->return_value == -EIO) {
// TODO: buffer errors??
}
if (r >= 0 && c->retval == 0) { return c->read_len; }
if (r >= 0 && c->return_value == 0) { return c->read_length; }
return -EIO;
} else if (t == UV_UDP) {
((uv_udp_t *)h)->data = c;
debuglog("[%p] udp\n", c);
int r = uv_udp_recv_start((uv_udp_t *)h, wasm_alloc_callback, wasm_udp_recv_callback);
sandbox_block();
debuglog("[%p] %d\n", c, c->retval);
if (c->retval == -EIO) {
block_current_sandbox();
debuglog("[%p] %d\n", c, c->return_value);
if (c->return_value == -EIO) {
// TODO: buffer errors??
}
if (r >= 0 && c->retval == 0) { return c->read_len; }
if (r >= 0 && c->return_value == 0) { return c->read_length; }
return -EIO;
}
debuglog("[%p] unimplemented\n", c);

@ -125,7 +125,7 @@ void
start_worker_threads()
{
for (int i = 0; i < total_worker_processors; i++) {
int ret = pthread_create(&worker_threads[i], NULL, sandbox_run_func,
int ret = pthread_create(&worker_threads[i], NULL, sandbox_worker_main,
(void *)&worker_threads_argument[i]);
if (ret) {
errno = ret;
@ -168,7 +168,7 @@ main(int argc, char **argv)
set_resource_limits_to_max();
allocate_available_cores();
process_nostio();
runtime_init();
initialize_runtime();
debuglog("Parsing modules file [%s]\n", argv[1]);
if (util_parse_modules_file_json(argv[1])) {
@ -176,6 +176,6 @@ main(int argc, char **argv)
exit(-1);
}
runtime_thd_init();
initialize_listener_thread();
start_worker_threads();
}

@ -11,19 +11,19 @@
void
alloc_linear_memory(void)
{
// mmaped memory in sandbox_alloc.
// mmaped memory in allocate_sandbox.
}
void
free_linear_memory(void *base, u32 bound, u32 max)
{
// frees on sandbox_free
// frees on free_sandbox
}
void
expand_memory(void)
{
struct sandbox *sandbox = sandbox_current();
struct sandbox *sandbox = get_current_sandbox();
// max_pages = 0 => no limit: FIXME
assert((sandbox->sandbox_size + sandbox_lmbound) / WASM_PAGE_SIZE < WASM_MAX_PAGES);
@ -38,9 +38,9 @@ expand_memory(void)
exit(1);
}
// TODO: check sandbox->linear_max_size
// TODO: check sandbox->linear_memory_max_size
sandbox_lmbound += WASM_PAGE_SIZE;
sandbox->linear_size = sandbox_lmbound;
sandbox->linear_memory_size = sandbox_lmbound;
}
INLINE char *

@ -37,23 +37,12 @@ __thread arch_context_t *next_context = NULL;
__thread arch_context_t base_context;
// libuv i/o loop handle per sandboxing thread!
__thread uv_loop_t uvio;
__thread uv_loop_t uvio_handle;
// Flag to signify if the thread is currently running callbacks in the libuv event loop
static __thread unsigned int in_callback;
/**
* Append the sandbox to the local_run_queue
* @param sandbox sandbox to add
*/
static inline void
sandbox_local_run(struct sandbox *sandbox)
{
assert(ps_list_singleton_d(sandbox));
// fprintf(stderr, "(%d,%lu) %s: run %p, %s\n", sched_getcpu(), pthread_self(), __func__, s,
// s->module->name);
ps_list_head_append_d(&local_run_queue, sandbox);
}
static inline void add_sandbox_to_local_run_queue(struct sandbox *sandbox);
/**
* Pulls up to 1..n sandbox requests, allocates them as sandboxes, sets them as runnable and places them on the local
@ -61,22 +50,22 @@ sandbox_local_run(struct sandbox *sandbox)
* @return the number of sandbox requests pulled
*/
static inline int
sandbox_pull(void)
pull_sandbox_requests_from_global_runqueue(void)
{
int total_sandboxes_pulled = 0;
while (total_sandboxes_pulled < SBOX_PULL_MAX) {
sbox_request_t *sandbox_request;
if ((sandbox_request = sandbox_deque_steal()) == NULL) break;
sandbox_request_t *sandbox_request;
if ((sandbox_request = steal_sandbox_request_from_global_dequeue()) == NULL) break;
// Actually allocate the sandbox for the requests that we've pulled
struct sandbox *sandbox = sandbox_alloc(sandbox_request->module, sandbox_request->args,
sandbox_request->sock, sandbox_request->addr,
struct sandbox *sandbox = allocate_sandbox(sandbox_request->module, sandbox_request->arguments,
sandbox_request->socket_descriptor, sandbox_request->socket_address,
sandbox_request->start_time);
assert(sandbox);
free(sandbox_request);
// Set the sandbox as runnable and place on the local runqueue
sandbox->state = SANDBOX_RUNNABLE;
sandbox_local_run(sandbox);
sandbox->state = RUNNABLE;
add_sandbox_to_local_run_queue(sandbox);
total_sandboxes_pulled++;
}
@ -87,7 +76,7 @@ sandbox_pull(void)
* Run all outstanding events in the libuv event loop
**/
void
sandbox_io_nowait(void)
execute_libuv_event_loop(void)
{
in_callback = 1;
int n = uv_run(runtime_uvio(), UV_RUN_NOWAIT), i = 0;
@ -98,6 +87,30 @@ sandbox_io_nowait(void)
in_callback = 0;
}
/**
* Append the sandbox to the local_run_queue
* @param sandbox sandbox to add
*/
static inline void
add_sandbox_to_local_run_queue(struct sandbox *sandbox)
{
assert(ps_list_singleton_d(sandbox));
// fprintf(stderr, "(%d,%lu) %s: run %p, %s\n", sched_getcpu(), pthread_self(), __func__, s,
// s->module->name);
ps_list_head_append_d(&local_run_queue, sandbox);
}
/**
* Removes the thread from the thread-local runqueue
* TODO: is this correct?
* @param sandbox sandbox
**/
static inline void
remove_sandbox_from_local_run_queue(struct sandbox *sandbox)
{
ps_list_rem_d(sandbox);
}
/**
* Execute the sandbox at the head of the thread local runqueue
* If the runqueue is empty, pull a fresh batch of sandbox requests, instantiate them, and then execute the new head
@ -105,14 +118,14 @@ sandbox_io_nowait(void)
* @return the sandbox to execute or NULL if none are available
**/
struct sandbox *
sandbox_schedule(int in_interrupt)
get_next_sandbox_from_local_run_queue(int in_interrupt)
{
// If the thread local runqueue is empty and we're not running in the context of an interupt,
// pull a fresh batch of sandbox requests from the global queue
if (ps_list_head_empty(&local_run_queue)) {
// this is in an interrupt context, don't steal work here!
if (in_interrupt) return NULL;
if (sandbox_pull() == 0) {
if (pull_sandbox_requests_from_global_runqueue() == 0) {
// debuglog("[null: null]\n");
return NULL;
}
@ -121,68 +134,56 @@ sandbox_schedule(int in_interrupt)
// Execute Round Robin Scheduling Logic
// Grab the sandbox at the head of the thread local runqueue, add it to the end, and return it
struct sandbox *sandbox = ps_list_head_first_d(&local_run_queue, struct sandbox);
// We are assuming that any sandboxed in the SANDBOX_RETURNED state should have been pulled from the local runqueue by now!
assert(sandbox->state != SANDBOX_RETURNED);
// We are assuming that any sandboxed in the RETURNED state should have been pulled from the local runqueue by now!
assert(sandbox->state != RETURNED);
ps_list_rem_d(sandbox);
ps_list_head_append_d(&local_run_queue, sandbox);
debuglog("[%p: %s]\n", sandbox, sandbox->module->name);
return sandbox;
}
/**
* Adds sandbox to the completion queue
* @param sandbox
**/
void
add_sandbox_to_completion_queue(struct sandbox *sandbox)
{
assert(ps_list_singleton_d(sandbox));
ps_list_head_append_d(&local_completion_queue, sandbox);
}
/**
* @brief Remove and free n sandboxes from the thread local completion queue
* @param number_to_free The number of sandboxes to free
* @return void
*/
static inline void
sandbox_local_free(unsigned int number_to_free)
free_sandboxes_from_completion_queue(unsigned int number_to_free)
{
for (int i = 0; i < number_to_free; i++) {
if (ps_list_head_empty(&local_completion_queue)) break;
struct sandbox *sandbox = ps_list_head_first_d(&local_completion_queue, struct sandbox);
if (!sandbox) break;
ps_list_rem_d(sandbox);
sandbox_free(sandbox);
free_sandbox(sandbox);
}
}
/**
* Tries to free a completed request, executes libuv callbacks, and then gets
* and returns the standbox at the head of the thread-local runqueue
* @return sandbox or NULL
**/
struct sandbox *
sandbox_schedule_io(void)
{
assert(sandbox_current() == NULL);
// Try to free one sandbox from the completion queue
sandbox_local_free(1);
// Execute libuv callbacks
if (!in_callback) sandbox_io_nowait();
// Get and return the sandbox at the head of the thread local runqueue
softint_disable();
struct sandbox *sandbox = sandbox_schedule(0);
softint_enable();
assert(sandbox == NULL || sandbox->state == SANDBOX_RUNNABLE);
return sandbox;
}
/**
* If this sandbox is blocked, mark it as runnable and add to the head of the thread-local runqueue
* @param sandbox the sandbox to check and update if blocked
**/
void
sandbox_wakeup(sandbox_t *sandbox)
wakeup_sandbox(sandbox_t *sandbox)
{
softint_disable();
debuglog("[%p: %s]\n", sandbox, sandbox->module->name);
if (sandbox->state != SANDBOX_BLOCKED) goto done;
assert(sandbox->state == SANDBOX_BLOCKED);
if (sandbox->state != BLOCKED) goto done;
assert(sandbox->state == BLOCKED);
assert(ps_list_singleton_d(sandbox));
sandbox->state = SANDBOX_RUNNABLE;
sandbox->state = RUNNABLE;
ps_list_head_append_d(&local_run_queue, sandbox);
done:
softint_enable();
@ -193,18 +194,18 @@ done:
* Mark the currently executing sandbox as blocked, remove it from the local runqueue, and pull the sandbox at the head of the runqueue
**/
void
sandbox_block(void)
block_current_sandbox(void)
{
assert(in_callback == 0);
softint_disable();
struct sandbox *current_sandbox = sandbox_current();
struct sandbox *current_sandbox = get_current_sandbox();
// TODO: What is this getting removed from again? the thread-local runqueue?
ps_list_rem_d(current_sandbox);
current_sandbox->state = SANDBOX_BLOCKED;
struct sandbox *next_sandbox = sandbox_schedule(0);
current_sandbox->state = BLOCKED;
struct sandbox *next_sandbox = get_next_sandbox_from_local_run_queue(0);
debuglog("[%p: %next_sandbox, %p: %next_sandbox]\n", current_sandbox, current_sandbox->module->name, next_sandbox, next_sandbox ? next_sandbox->module->name : "");
softint_enable();
sandbox_switch(next_sandbox);
switch_to_sandbox(next_sandbox);
}
@ -221,7 +222,7 @@ sandbox_block_http(void)
// async block!
uv_run(runtime_uvio(), UV_RUN_DEFAULT);
#else /* USE_HTTP_SYNC */
sandbox_block();
block_current_sandbox();
#endif /* USE_HTTP_UVIO */
#else
assert(0);
@ -243,25 +244,25 @@ void __attribute__((noinline)) __attribute__((noreturn)) sandbox_switch_preempt(
}
/**
* Removes the thread from the thread-local runqueue
* TODO: is this correct?
* @param sandbox sandbox
* Tries to free a completed request, executes libuv callbacks, and then gets
* and returns the standbox at the head of the thread-local runqueue
* @return sandbox or NULL
**/
static inline void
sandbox_local_stop(struct sandbox *sandbox)
struct sandbox *
sandbox_worker_single_loop(void)
{
ps_list_rem_d(sandbox);
}
assert(get_current_sandbox() == NULL);
// Try to free one sandbox from the completion queue
free_sandboxes_from_completion_queue(1);
// Execute libuv callbacks
if (!in_callback) execute_libuv_event_loop();
/**
* Adds sandbox to the completion queue
* @param sandbox
**/
void
sandbox_local_end(struct sandbox *sandbox)
{
assert(ps_list_singleton_d(sandbox));
ps_list_head_append_d(&local_completion_queue, sandbox);
// Get and return the sandbox at the head of the thread local runqueue
softint_disable();
struct sandbox *sandbox = get_next_sandbox_from_local_run_queue(0);
softint_enable();
assert(sandbox == NULL || sandbox->state == RUNNABLE);
return sandbox;
}
/**
@ -270,7 +271,7 @@ sandbox_local_end(struct sandbox *sandbox)
* @param return_code - argument provided by pthread API. We set to -1 on error
**/
void *
sandbox_run_func(void *return_code)
sandbox_worker_main(void *return_code)
{
arch_context_init(&base_context, 0, 0);
@ -282,14 +283,14 @@ sandbox_run_func(void *return_code)
softint_unmask(SIGALRM);
softint_unmask(SIGUSR1);
#endif
uv_loop_init(&uvio);
uv_loop_init(&uvio_handle);
in_callback = 0;
while (true) {
struct sandbox *sandbox = sandbox_schedule_io();
struct sandbox *sandbox = sandbox_worker_single_loop();
while (sandbox) {
sandbox_switch(sandbox);
sandbox = sandbox_schedule_io();
switch_to_sandbox(sandbox);
sandbox = sandbox_worker_single_loop();
}
}
@ -304,22 +305,22 @@ sandbox_run_func(void *return_code)
* TODO: Why are we not adding to the completion queue here? That logic is commented out.
**/
void
sandbox_exit(void)
exit_current_sandbox(void)
{
struct sandbox *current_sandbox = sandbox_current();
struct sandbox *current_sandbox = get_current_sandbox();
assert(current_sandbox);
softint_disable();
// Remove from the runqueue
sandbox_local_stop(current_sandbox);
current_sandbox->state = SANDBOX_RETURNED;
// free resources from "main function execution", as stack still in use.
struct sandbox *next_sandbox = sandbox_schedule(0);
remove_sandbox_from_local_run_queue(current_sandbox);
current_sandbox->state = RETURNED;
struct sandbox *next_sandbox = get_next_sandbox_from_local_run_queue(0);
assert(next_sandbox != current_sandbox);
softint_enable();
// free resources from "main function execution", as stack still in use.
// unmap linear memory only!
munmap(current_sandbox->linear_start, SBOX_MAX_MEM + PAGE_SIZE);
// sandbox_local_end(current_sandbox);
sandbox_switch(next_sandbox);
munmap(current_sandbox->linear_memory_start, SBOX_MAX_MEM + PAGE_SIZE);
// add_sandbox_to_completion_queue(current_sandbox);
switch_to_sandbox(next_sandbox);
}
/**
@ -333,7 +334,7 @@ sandbox_exit(void)
*
*/
void *
runtime_accept_thdfn(void *dummy)
listener_thread_main(void *dummy)
{
struct epoll_event *epoll_events = (struct epoll_event *)malloc(EPOLL_MAX * sizeof(struct epoll_event));
int total_requests = 0;
@ -347,12 +348,12 @@ runtime_accept_thdfn(void *dummy)
assert(0);
}
struct sockaddr_in client;
socklen_t client_length = sizeof(client);
struct sockaddr_in client_address;
socklen_t client_length = sizeof(client_address);
struct module * module = (struct module *)epoll_events[i].data.ptr;
assert(module);
int es = module->socket_descriptor;
int socket_descriptor = accept(es, (struct sockaddr *)&client, &client_length);
int socket_descriptor = accept(es, (struct sockaddr *)&client_address, &client_length);
if (socket_descriptor < 0) {
perror("accept");
assert(0);
@ -360,15 +361,15 @@ runtime_accept_thdfn(void *dummy)
total_requests++;
printf("Received Request %d at %lu\n", total_requests, start_time);
sbox_request_t *sandbox_request = sbox_request_alloc(
sandbox_request_t *sandbox_request = allocate_sandbox_request(
module,
module->name,
socket_descriptor,
(const struct sockaddr *)&client,
(const struct sockaddr *)&client_address,
start_time);
assert(sandbox_request);
// TODO: Refactor sbox_request_alloc to not add to global request queue and do this here
// TODO: Refactor allocate_sandbox_request to not add to global request queue and do this here
}
}
@ -378,10 +379,10 @@ runtime_accept_thdfn(void *dummy)
}
/**
* Initialize runtime global state, mask signals, and init http server
* Initialize runtime global state, mask signals, and init http parser
*/
void
runtime_init(void)
initialize_runtime(void)
{
epoll_file_descriptor = epoll_create1(0);
assert(epoll_file_descriptor >= 0);
@ -396,6 +397,7 @@ runtime_init(void)
softint_mask(SIGUSR1);
softint_mask(SIGALRM);
// Initialize http-parser
http_init();
}
@ -403,17 +405,17 @@ runtime_init(void)
* Initializes the listener thread, pinned to core 0, and starts to listen for requests
*/
void
runtime_thd_init(void)
initialize_listener_thread(void)
{
cpu_set_t cs;
CPU_ZERO(&cs);
CPU_SET(MOD_REQ_CORE, &cs);
pthread_t iothd;
int ret = pthread_create(&iothd, NULL, runtime_accept_thdfn, NULL);
pthread_t listener_thread;
int ret = pthread_create(&listener_thread, NULL, listener_thread_main, NULL);
assert(ret == 0);
ret = pthread_setaffinity_np(iothd, sizeof(cpu_set_t), &cs);
ret = pthread_setaffinity_np(listener_thread, sizeof(cpu_set_t), &cs);
assert(ret == 0);
ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cs);
assert(ret == 0);

@ -7,13 +7,98 @@
#include <uv.h>
#include <http_api.h>
/***********************************
* Libuv Callbacks
***********************************/
/**
* TODO: is there some weird edge case where a UNICODE character might be split between reads? Do we care?
* Called after libuv has read a chunk of data
* Parses data read by the libuv stream chunk-by-chunk until the message is complete
* Then stops the stream and wakes up the sandbox
* @param stream
* @param number_read bytes read
* @param buffer unused
**/
static inline void
on_libuv_read_parse_http_request(uv_stream_t *stream, ssize_t number_read, const uv_buf_t *buffer)
{
struct sandbox *sandbox = stream->data;
// Parse the chunks libuv has read on our behalf until we've parse to message end
if (number_read > 0) {
if (http_request_parse_sb(sandbox, number_read) != 0) return;
sandbox->request_response_data_length += number_read;
struct http_request *rh = &sandbox->http_request;
if (!rh->message_end) return;
}
// When the entire message has been read, stop the stream and wakeup the sandbox
uv_read_stop(stream);
wakeup_sandbox(sandbox);
}
/**
* On libuv close, executes this callback to wake the blocked sandbox back up
* @param stream
**/
static inline void
on_libuv_close_wakeup_sakebox(uv_handle_t *stream)
{
struct sandbox *sandbox = stream->data;
wakeup_sandbox(sandbox);
}
/**
* On libuv shutdown, executes this callback to wake the blocked sandbox back up
* @param req shutdown request
* @param status unused in callback
**/
static inline void
on_libuv_shutdown_wakeup_sakebox(uv_shutdown_t *req, int status)
{
struct sandbox *sandbox = req->data;
wakeup_sandbox(sandbox);
}
/**
* On libuv write, executes this callback to wake the blocked sandbox back up
* In case of error, shutdown the sandbox
* @param write shutdown request
* @param status status code
**/
static inline void
on_libuv_write_wakeup_sandbox(uv_write_t *write, int status)
{
struct sandbox *sandbox = write->data;
if (status < 0) {
sandbox->client_libuv_shutdown_request.data = sandbox;
uv_shutdown(&sandbox->client_libuv_shutdown_request, (uv_stream_t *)&sandbox->client_libuv_stream, on_libuv_shutdown_wakeup_sakebox);
return;
}
wakeup_sandbox(sandbox);
}
static inline void
on_libuv_allocate_setup_request_response_data(uv_handle_t *h, size_t suggested, uv_buf_t *buf)
{
struct sandbox *sandbox = h->data;
size_t l = (sandbox->module->max_request_or_response_size - sandbox->request_response_data_length);
buf->base = (sandbox->request_response_data + sandbox->request_response_data_length);
buf->len = l > suggested ? suggested : l;
}
/***********************************
* End of Libuv Callbacks
***********************************/
/**
* Allocates the memory for a sandbox to run a module
* @param module the module that we want to run
* @returns the resulting sandbox or NULL if mmap failed
**/
static inline struct sandbox *
sandbox_memory_map(struct module *module)
allocate_sandbox_memory(struct module *module)
{
unsigned long memory_size = SBOX_MAX_MEM; // 4GB
@ -24,7 +109,7 @@ sandbox_memory_map(struct module *module)
if (linear_memory_size + sandbox_size > memory_size) return NULL;
assert(round_up_to_page(sandbox_size) == sandbox_size);
// What does mmap do exactly with fd -1?
// What does mmap do exactly with file_descriptor -1?
void *addr = mmap(NULL, sandbox_size + memory_size + /* guard page */ PAGE_SIZE, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED) return NULL;
@ -38,8 +123,8 @@ sandbox_memory_map(struct module *module)
struct sandbox *sandbox = (struct sandbox *)addr;
// can it include sandbox as well?
sandbox->linear_start = (char *)addr + sandbox_size;
sandbox->linear_size = linear_memory_size;
sandbox->linear_memory_start = (char *)addr + sandbox_size;
sandbox->linear_memory_size = linear_memory_size;
sandbox->module = module;
sandbox->sandbox_size = sandbox_size;
module_acquire(module);
@ -47,22 +132,27 @@ sandbox_memory_map(struct module *module)
return sandbox;
}
/**
* 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
sandbox_args_setup(i32 argument_count)
setup_sandbox_arguments(i32 argument_count)
{
struct sandbox *curr = sandbox_current();
char * args = sandbox_args();
struct sandbox *curr = get_current_sandbox();
char * arguments = get_current_sandbox_arguments();
// whatever gregor has, to be able to pass args to a module!
curr->args_offset = sandbox_lmbound;
assert(sandbox_lmbase == curr->linear_start);
// whatever gregor has, to be able to pass arguments to a module!
curr->arguments_offset = sandbox_lmbound;
assert(sandbox_lmbase == curr->linear_memory_start);
expand_memory();
i32 *array_ptr = get_memory_ptr_void(curr->args_offset, argument_count * sizeof(i32));
i32 string_off = curr->args_offset + (argument_count * sizeof(i32));
i32 *array_ptr = get_memory_ptr_void(curr->arguments_offset, argument_count * sizeof(i32));
i32 string_off = curr->arguments_offset + (argument_count * sizeof(i32));
for (int i = 0; i < argument_count; i++) {
char * arg = args + (i * MOD_ARG_MAX_SZ);
char * arg = arguments + (i * MOD_ARG_MAX_SZ);
size_t str_sz = strlen(arg) + 1;
array_ptr[i] = string_off;
@ -74,86 +164,40 @@ sandbox_args_setup(i32 argument_count)
stub_init(string_off);
}
static inline void
sb_read_callback(uv_stream_t *s, ssize_t nr, const uv_buf_t *b)
{
struct sandbox *sandbox = s->data;
if (nr > 0) {
if (http_request_parse_sb(sandbox, nr) != 0) return;
sandbox->rr_data_len += nr;
struct http_request *rh = &sandbox->http_request;
if (!rh->message_end) return;
}
uv_read_stop(s);
sandbox_wakeup(sandbox);
}
static inline void
sb_close_callback(uv_handle_t *s)
{
struct sandbox *sandbox = s->data;
sandbox_wakeup(sandbox);
}
static inline void
sb_shutdown_callback(uv_shutdown_t *req, int status)
{
struct sandbox *sandbox = req->data;
sandbox_wakeup(sandbox);
}
static inline void
sb_write_callback(uv_write_t *w, int status)
{
struct sandbox *sandbox = w->data;
if (status < 0) {
sandbox->cuvsr.data = sandbox;
uv_shutdown(&sandbox->cuvsr, (uv_stream_t *)&sandbox->cuv, sb_shutdown_callback);
return;
}
sandbox_wakeup(sandbox);
}
static inline void
sb_alloc_callback(uv_handle_t *h, size_t suggested, uv_buf_t *buf)
{
struct sandbox *sandbox = h->data;
size_t l = (sandbox->module->max_request_or_response_size - sandbox->rr_data_len);
buf->base = (sandbox->req_resp_data + sandbox->rr_data_len);
buf->len = l > suggested ? suggested : l;
}
/**
* Receive and Parse the Request for the current sandbox
* @return 1 on success, < 0 on failure.
* TODO: What does 0 mean?
**/
static inline int
sandbox_client_request_get(void)
receive_and_parse_current_sandbox_client_request(void)
{
struct sandbox *curr = sandbox_current();
curr->rr_data_len = 0;
struct sandbox *curr = get_current_sandbox();
curr->request_response_data_length = 0;
#ifndef USE_HTTP_UVIO
int r = 0;
r = recv(curr->csock, (curr->req_resp_data), curr->module->max_request_size, 0);
r = recv(curr->client_socket_descriptor, (curr->request_response_data), curr->module->max_request_size, 0);
if (r <= 0) {
if (r < 0) perror("recv1");
return r;
}
while (r > 0) {
if (http_request_parse(r) != 0) return -1;
curr->rr_data_len += r;
curr->request_response_data_length += r;
struct http_request *rh = &curr->http_request;
if (rh->message_end) break;
r = recv(curr->csock, (curr->req_resp_data + curr->rr_data_len),
curr->module->max_request_size - curr->rr_data_len, 0);
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);
if (r < 0) {
perror("recv2");
return r;
}
}
#else
int r = uv_read_start((uv_stream_t *)&curr->cuv, sb_alloc_callback, sb_read_callback);
int r = uv_read_start((uv_stream_t *)&curr->client_libuv_stream, on_libuv_allocate_setup_request_response_data, on_libuv_read_parse_http_request);
sandbox_block_http();
if (curr->rr_data_len == 0) return 0;
if (curr->request_response_data_length == 0) return 0;
#endif
return 1;
}
@ -163,49 +207,49 @@ sandbox_client_request_get(void)
* @return RC. -1 on Failure
**/
static inline int
sandbox_client_response_set(void)
build_and_send_current_sandbox_client_response(void)
{
int sndsz = 0;
struct sandbox *curr = sandbox_current();
int rsp_hdr_len = strlen(HTTP_RESP_200OK) + strlen(HTTP_RESP_CONTTYPE) + strlen(HTTP_RESP_CONTLEN);
int body_length = curr->rr_data_len - rsp_hdr_len;
struct sandbox *curr = get_current_sandbox();
int response_header_length = strlen(HTTP_RESP_200OK) + strlen(HTTP_RESP_CONTTYPE) + strlen(HTTP_RESP_CONTLEN);
int body_length = curr->request_response_data_length - response_header_length;
memset(curr->req_resp_data, 0,
memset(curr->request_response_data, 0,
strlen(HTTP_RESP_200OK) + strlen(HTTP_RESP_CONTTYPE) + strlen(HTTP_RESP_CONTLEN));
strncpy(curr->req_resp_data, HTTP_RESP_200OK, strlen(HTTP_RESP_200OK));
strncpy(curr->request_response_data, HTTP_RESP_200OK, strlen(HTTP_RESP_200OK));
sndsz += strlen(HTTP_RESP_200OK);
if (body_length == 0) goto done;
strncpy(curr->req_resp_data + sndsz, HTTP_RESP_CONTTYPE, strlen(HTTP_RESP_CONTTYPE));
strncpy(curr->request_response_data + sndsz, HTTP_RESP_CONTTYPE, strlen(HTTP_RESP_CONTTYPE));
if (strlen(curr->module->response_content_type) <= 0) {
strncpy(curr->req_resp_data + sndsz + strlen("Content-type: "), HTTP_RESP_CONTTYPE_PLAIN,
strncpy(curr->request_response_data + sndsz + strlen("Content-type: "), HTTP_RESP_CONTTYPE_PLAIN,
strlen(HTTP_RESP_CONTTYPE_PLAIN));
} else {
strncpy(curr->req_resp_data + sndsz + strlen("Content-type: "), curr->module->response_content_type,
strncpy(curr->request_response_data + sndsz + strlen("Content-type: "), curr->module->response_content_type,
strlen(curr->module->response_content_type));
}
sndsz += strlen(HTTP_RESP_CONTTYPE);
char len[10] = { 0 };
sprintf(len, "%d", body_length);
strncpy(curr->req_resp_data + sndsz, HTTP_RESP_CONTLEN, strlen(HTTP_RESP_CONTLEN));
strncpy(curr->req_resp_data + sndsz + strlen("Content-length: "), len, strlen(len));
strncpy(curr->request_response_data + sndsz, HTTP_RESP_CONTLEN, strlen(HTTP_RESP_CONTLEN));
strncpy(curr->request_response_data + sndsz + strlen("Content-length: "), len, strlen(len));
sndsz += strlen(HTTP_RESP_CONTLEN);
sndsz += body_length;
done:
assert(sndsz == curr->rr_data_len);
assert(sndsz == curr->request_response_data_length);
// Get End Timestamp
curr->total_time = rdtsc() - curr->start_time;
printf("Function returned in %lu cycles\n", curr->total_time);
#ifndef USE_HTTP_UVIO
int r = send(curr->csock, curr->req_resp_data, sndsz, 0);
int r = send(curr->client_socket_descriptor, curr->request_response_data, sndsz, 0);
if (r < 0) {
perror("send");
return -1;
}
while (r < sndsz) {
int s = send(curr->csock, curr->req_resp_data + r, sndsz - r, 0);
int s = send(curr->client_socket_descriptor, curr->request_response_data + r, sndsz - r, 0);
if (s < 0) {
perror("send");
return -1;
@ -216,84 +260,115 @@ done:
uv_write_t req = {
.data = curr,
};
uv_buf_t bufv = uv_buf_init(curr->req_resp_data, sndsz);
int r = uv_write(&req, (uv_stream_t *)&curr->cuv, &bufv, 1, sb_write_callback);
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, on_libuv_write_wakeup_sandbox);
sandbox_block_http();
#endif
return 0;
}
/**
* Sandbox execution logic
* Handles setup, request parsing, WebAssembly initialization, function execution, response building and sending, and cleanup
**/
void
sandbox_entry(void)
sandbox_main(void)
{
struct sandbox *curr = sandbox_current();
struct sandbox *current_sandbox = get_current_sandbox();
// FIXME: is this right? this is the first time this sandbox is running.. so it wont
// return to sandbox_switch() api..
// we'd potentially do what we'd in sandbox_switch() api here for cleanup..
// return to switch_to_sandbox() api..
// we'd potentially do what we'd in switch_to_sandbox() api here for cleanup..
if (!softint_enabled()) {
arch_context_init(&curr->ctxt, 0, 0);
arch_context_init(&current_sandbox->ctxt, 0, 0);
next_context = NULL;
softint_enable();
}
struct module *curr_mod = sandbox_module(curr);
int argument_count = module_argument_count(curr_mod);
struct module *current_module = get_sandbox_module(current_sandbox);
int argument_count = module_argument_count(current_module);
// for stdio
int f = io_handle_open(0);
// 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 = initialize_io_handle_and_set_file_descriptor_in_current_sandbox(0);
assert(f == 0);
f = io_handle_open(1);
f = initialize_io_handle_and_set_file_descriptor_in_current_sandbox(1);
assert(f == 1);
f = io_handle_open(2);
f = initialize_io_handle_and_set_file_descriptor_in_current_sandbox(2);
assert(f == 2);
http_parser_init(&curr->http_parser, HTTP_REQUEST);
curr->http_parser.data = curr;
// Initialize the HTTP-Parser for a request
http_parser_init(&current_sandbox->http_parser, HTTP_REQUEST);
// Set the current_sandbox as the data the http-parser has access to
current_sandbox->http_parser.data = current_sandbox;
// NOTE: if more headers, do offset by that!
int rsp_hdr_len = strlen(HTTP_RESP_200OK) + strlen(HTTP_RESP_CONTTYPE) + strlen(HTTP_RESP_CONTLEN);
int response_header_length = strlen(HTTP_RESP_200OK) + strlen(HTTP_RESP_CONTTYPE) + strlen(HTTP_RESP_CONTLEN);
#ifdef USE_HTTP_UVIO
int r = uv_tcp_init(runtime_uvio(), (uv_tcp_t *)&curr->cuv);
// Initialize libuv TCP stream
int r = uv_tcp_init(runtime_uvio(), (uv_tcp_t *)&current_sandbox->client_libuv_stream);
assert(r == 0);
curr->cuv.data = curr;
r = uv_tcp_open((uv_tcp_t *)&curr->cuv, curr->csock);
// Set the current sandbox as the data the libuv callbacks have access to
current_sandbox->client_libuv_stream.data = current_sandbox;
// Open the libuv TCP stream
r = uv_tcp_open((uv_tcp_t *)&current_sandbox->client_libuv_stream, current_sandbox->client_socket_descriptor);
assert(r == 0);
#endif
if (sandbox_client_request_get() > 0) {
curr->rr_data_len = rsp_hdr_len; // TODO: do this on first write to body.
// If the HTTP Request returns 1, we've successfully received and parsed the HTTP request, so execute it!
if (receive_and_parse_current_sandbox_client_request() > 0) {
//
current_sandbox->request_response_data_length = response_header_length; // TODO: do this on first write to body.
// Allocate the WebAssembly Sandbox
alloc_linear_memory();
// perhaps only initialized for the first instance? or TODO!
// module_table_init(curr_mod);
module_globals_init(curr_mod);
module_memory_init(curr_mod);
sandbox_args_setup(argument_count);
// module_table_init(current_module);
module_globals_init(current_module);
module_memory_init(current_module);
curr->retval = module_entry(curr_mod, argument_count, curr->args_offset);
// Copy the arguments into the WebAssembly sandbox
setup_sandbox_arguments(argument_count);
sandbox_client_response_set();
// Executing the function within the WebAssembly sandbox
current_sandbox->return_value = module_entry(current_module, argument_count, current_sandbox->arguments_offset);
// Retrieve the result from the WebAssembly sandbox, construct the HTTP response, and send to client
build_and_send_current_sandbox_client_response();
}
// Cleanup connection and exit sandbox
#ifdef USE_HTTP_UVIO
uv_close((uv_handle_t *)&curr->cuv, sb_close_callback);
uv_close((uv_handle_t *)&current_sandbox->client_libuv_stream, on_libuv_close_wakeup_sakebox);
sandbox_block_http();
#else
close(curr->csock);
close(current_sandbox->client_socket_descriptor);
#endif
sandbox_exit();
exit_current_sandbox();
}
struct sandbox *
sandbox_alloc(struct module *module, char *args, int sock, const struct sockaddr *addr, u64 start_time)
allocate_sandbox(struct module *module, char *arguments, int socket_descriptor, const struct sockaddr *socket_address, u64 start_time)
{
if (!module_is_valid(module)) return NULL;
// FIXME: don't use malloc. huge security problem!
// perhaps, main should be in its own sandbox, when it is not running any sandbox.
struct sandbox *sandbox = (struct sandbox *)sandbox_memory_map(module);
struct sandbox *sandbox = (struct sandbox *)allocate_sandbox_memory(module);
if (!sandbox) return NULL;
// Assign the start time from the request
sandbox->start_time = start_time;
// actual module instantiation!
sandbox->args = (void *)args;
sandbox->arguments = (void *)arguments;
sandbox->stack_size = module->stack_size;
sandbox->stack_start = mmap(NULL, sandbox->stack_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
@ -301,38 +376,39 @@ sandbox_alloc(struct module *module, char *args, int sock, const struct sockaddr
perror("mmap");
assert(0);
}
sandbox->csock = sock;
if (addr) memcpy(&sandbox->client, addr, sizeof(struct sockaddr));
for (int i = 0; i < SBOX_MAX_OPEN; i++) sandbox->handles[i].fd = -1;
sandbox->client_socket_descriptor = socket_descriptor;
if (socket_address) memcpy(&sandbox->client_address, socket_address, sizeof(struct sockaddr));
for (int i = 0; i < SBOX_MAX_OPEN; i++) sandbox->handles[i].file_descriptor = -1;
ps_list_init_d(sandbox);
arch_context_init(&sandbox->ctxt, (reg_t)sandbox_entry, (reg_t)(sandbox->stack_start + sandbox->stack_size));
// Setup the sandbox's context, stack, and instruction pointer
arch_context_init(&sandbox->ctxt, (reg_t)sandbox_main, (reg_t)(sandbox->stack_start + sandbox->stack_size));
return sandbox;
}
void
sandbox_free(struct sandbox *sandbox)
free_sandbox(struct sandbox *sandbox)
{
int ret;
// you have to context switch away to free a sandbox.
if (!sandbox || sandbox == sandbox_current()) return;
if (!sandbox || sandbox == get_current_sandbox()) return;
// again sandbox should be done and waiting for the parent.
// TODO: this needs to be enhanced. you may be killing a sandbox when its in any other execution states.
if (sandbox->state != SANDBOX_RETURNED) return;
if (sandbox->state != RETURNED) return;
int sz = sizeof(struct sandbox);
sz += sandbox->module->max_request_or_response_size;
module_release(sandbox->module);
// TODO free(sandbox->args);
// TODO free(sandbox->arguments);
void * stkaddr = sandbox->stack_start;
size_t stksz = sandbox->stack_size;
// depending on the memory type
// free_linear_memory(sandbox->linear_start, sandbox->linear_size, sandbox->linear_max_size);
// free_linear_memory(sandbox->linear_memory_start, sandbox->linear_memory_size, sandbox->linear_memory_max_size);
// mmaped memory includes sandbox structure in there.
ret = munmap(sandbox, sz);

@ -69,21 +69,21 @@ softint_alarm_schedule(void *user_context_raw)
{
softint_disable(); // no nesting!
struct sandbox *curr = sandbox_current();
struct sandbox *curr = get_current_sandbox();
ucontext_t * user_context = (ucontext_t *)user_context_raw;
// no sandboxes running..so nothing to preempt..let the "main" scheduler run its course.
if (curr == NULL) goto done;
// find a next sandbox to run..
struct sandbox *next = sandbox_schedule(1);
struct sandbox *next = get_next_sandbox_from_local_run_queue(1);
if (next == NULL) goto done;
if (next == curr) goto done; // only this sandbox to schedule.. return to it!
// save the current sandbox, state from user_context!
arch_mcontext_save(&curr->ctxt, &user_context->uc_mcontext);
// sandbox_current_set on it. restore through *user_context..
sandbox_current_set(next);
// set_current_sandbox on it. restore through *user_context..
set_current_sandbox(next);
if (arch_mcontext_restore(&user_context->uc_mcontext, &next->ctxt)) goto skip;
// reset if SIGALRM happens before SIGUSR1 and if don't preempt..OR
@ -113,7 +113,7 @@ softint_handler(int signal_type, siginfo_t *signal_info, void *user_context_raw)
#ifdef PREEMPT_DISABLE
assert(0);
#else
struct sandbox *curr = sandbox_current();
struct sandbox *curr = get_current_sandbox();
ucontext_t * user_context = (ucontext_t *)user_context_raw;
switch (signal_type) {
@ -137,7 +137,7 @@ softint_handler(int signal_type, siginfo_t *signal_info, void *user_context_raw)
SIGALRM_count++;
// softints per-core..
if (curr && curr->state == SANDBOX_RETURNED) return;
if (curr && curr->state == RETURNED) return;
if (next_context) return;
if (!softint_enabled()) return;
softint_alarm_schedule(user_context_raw);

@ -167,9 +167,9 @@ char img[] = {
int
connect_n_send(void)
{
int sock;
int socket_descriptor;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
if ((socket_descriptor = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return -1;
}
@ -179,13 +179,13 @@ connect_n_send(void)
socket_address.sin_port = htons(SERVER_PORT);
if (inet_aton(SERVER_ADDR, &socket_address.sin_addr) == 0) {
perror("inet_addr");
close(sock);
close(socket_descriptor);
return -1;
}
if (connect(sock, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) {
if (connect(socket_descriptor, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) {
perror("connect");
close(sock);
close(socket_descriptor);
return -1;
}
@ -205,29 +205,29 @@ connect_n_send(void)
assert(resp);
memset(resp, 0, RESP_MAX);
// int fd = open("tmp_cli.png", O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXO | S_IRWXG);
// if (fd < 0) {
// int file_descriptor = open("tmp_cli.png", O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXO | S_IRWXG);
// if (file_descriptor < 0) {
// perror("open");
// goto skip;
// }
//
// int sz = write(fd, img, sizeof(img));
// int sz = write(file_descriptor, img, sizeof(img));
// if (sz < 0) {
// perror("write");
// }
// close(fd);
// close(file_descriptor);
skip:
printf("Sending..\n");
if (send(sock, req, len, 0) < 0) {
if (send(socket_descriptor, req, len, 0) < 0) {
perror("send");
close(sock);
close(socket_descriptor);
return -1;
}
printf("Receiving..\n");
int r = 0, rcvd = 0;
while ((r = recv(sock, resp + rcvd, RESP_MAX, 0)) > 0) {
while ((r = recv(socket_descriptor, resp + rcvd, RESP_MAX, 0)) > 0) {
rcvd += r;
if (r < RESP_MAX) break;
resp = (char *)realloc(resp, rcvd + RESP_MAX);
@ -238,7 +238,7 @@ skip:
printf("Response: %s\n", resp);
free(resp);
free(req);
close(sock);
close(socket_descriptor);
return 0;
}

@ -43,27 +43,27 @@ send_fn(void *d)
struct request *r = (struct request *)d;
char resp[STR_MAX] = { 0 };
int fd = -1;
int file_descriptor = -1;
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(atoi(r->port));
sa.sin_addr.s_addr = inet_addr(r->ip);
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
if ((file_descriptor = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Establishing socket");
return NULL;
}
if (sendto(fd, r->msg, strlen(r->msg), 0, (struct sockaddr *)&sa, sizeof(sa)) < 0 && errno != EINTR) {
if (sendto(file_descriptor, r->msg, strlen(r->msg), 0, (struct sockaddr *)&sa, sizeof(sa)) < 0 && errno != EINTR) {
perror("sendto");
return NULL;
}
// todo: select rcv from!
int sa_len = sizeof(sa);
if (recvfrom(fd, resp, STR_MAX, 0, (struct sockaddr *)&sa, &sa_len) < 0) { perror("recvfrom"); }
if (recvfrom(file_descriptor, resp, STR_MAX, 0, (struct sockaddr *)&sa, &sa_len) < 0) { perror("recvfrom"); }
printf("Done[%s]!\n", resp);
close(fd);
close(file_descriptor);
free(r);
return NULL;

Loading…
Cancel
Save