From bbd6baba45c9ec6e0f41f9ebd73abe0d0c7afaac Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Mon, 30 Nov 2020 17:05:37 -0500 Subject: [PATCH 01/13] Improved bindings Changed the ordering of the C/Rust binding generation to make it more reliable. Renamed the `cbindings` module to `cshadow` since the contents of `cbindings` are actually Rust bindings for C code. Added some addtional documentation. --- .github/workflows/lint.yml | 2 +- docs/5-Developer-Guide.md | 4 ++++ src/main/bindings/CMakeLists.txt | 9 ++++++++- src/main/host/memory_manager.rs | 2 +- src/main/host/syscall_types.rs | 2 +- src/main/host/thread.rs | 2 +- src/main/lib.rs | 5 +++-- 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 29c474adee..e1486da01f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -59,7 +59,7 @@ jobs: run: | rustup component add rustfmt cargo install --force --version 0.15.0 cbindgen - cargo install --force --version 0.55.1 bindgen + cargo install --force --version 0.56.0 bindgen - name: Check bindings run: | mkdir build diff --git a/docs/5-Developer-Guide.md b/docs/5-Developer-Guide.md index d9a5c2e6f0..3aa20c9d7a 100644 --- a/docs/5-Developer-Guide.md +++ b/docs/5-Developer-Guide.md @@ -6,6 +6,10 @@ When required, you can rebuild all of the C-Rust bindings by running: cd build && cmake --target bindings .. && make bindings ``` +To see the specific options/flags provided to bindgen and cbindgen, you can use `make VERBOSE=1 bindings`. + +Since the C bindings and Rust bindings rely on each other, you may sometimes need to build the bindings in a specific order. Instead of `make bindings`, you can be more specific using for example `make bindings_main_rust` to make the Rust bindings for `src/main`. + You may need to install bindgen, cbindgen, and clang: ```bash diff --git a/src/main/bindings/CMakeLists.txt b/src/main/bindings/CMakeLists.txt index 9bbba97d44..989f218a00 100644 --- a/src/main/bindings/CMakeLists.txt +++ b/src/main/bindings/CMakeLists.txt @@ -3,8 +3,15 @@ add_subdirectory(rust) # A fake target that depends on the wrapper. add_custom_target(bindings_main) -add_dependencies(bindings_main bindings_main_rust) add_dependencies(bindings_main bindings_main_c) +add_dependencies(bindings_main bindings_main_rust) + +# The C bindings should be generated first since cbindgen doesn't require the Rust code +# to be valid, whereas bindgen does require the C code to be valid. If the C bindings +# are no longer correct, but the Rust bindings are generated first, then there will be +# no way to correct the C bindings since the Rust binding generation will always fail +# before the C bindings can be corrected. +add_dependencies(bindings_main_rust bindings_main_c) # Only re-generate bindings when explicititly requested, so that # our CI doesn't need to install the heavy bindgen dependency. diff --git a/src/main/host/memory_manager.rs b/src/main/host/memory_manager.rs index 7c0877ab1b..5e7cea581e 100644 --- a/src/main/host/memory_manager.rs +++ b/src/main/host/memory_manager.rs @@ -1,6 +1,6 @@ use super::syscall_types::{PluginPtr, SysCallReg}; use super::thread::{CThread, Thread}; -use crate::cbindings as c; +use crate::cshadow as c; use crate::utility::interval_map::{Interval, IntervalMap, Mutation}; use crate::utility::proc_maps; use crate::utility::proc_maps::{MappingPath, Sharing}; diff --git a/src/main/host/syscall_types.rs b/src/main/host/syscall_types.rs index 09590fc8c0..3ad6166054 100644 --- a/src/main/host/syscall_types.rs +++ b/src/main/host/syscall_types.rs @@ -1,4 +1,4 @@ -use crate::cbindings as c; +use crate::cshadow as c; use std::convert::From; #[derive(Copy, Clone)] diff --git a/src/main/host/thread.rs b/src/main/host/thread.rs index d0725ac10b..120a2afe0d 100644 --- a/src/main/host/thread.rs +++ b/src/main/host/thread.rs @@ -1,5 +1,5 @@ use super::syscall_types::{PluginPtr, SysCallReg}; -use crate::cbindings as c; +use crate::cshadow as c; use crate::utility::syscall; use nix::errno::Errno; diff --git a/src/main/lib.rs b/src/main/lib.rs index 1e2a0298c8..1cd4c99419 100644 --- a/src/main/lib.rs +++ b/src/main/lib.rs @@ -2,8 +2,9 @@ * The Shadow Simulator * See LICENSE for licensing information */ -mod cbindings { - // Inline the bindgen-generated bindings, suppressing warnings. + +mod cshadow { + // Inline the bindgen-generated Rust bindings, suppressing warnings. #![allow(unused)] #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] From 5c3fd5d896305cd5e15e371723fd855d817235b5 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Tue, 1 Dec 2020 12:20:46 -0500 Subject: [PATCH 02/13] Move opaque types in C bindings into their own header file This helps to prevent circular dependencies between C headers. --- src/main/bindings/c/CMakeLists.txt | 10 +++++-- src/main/bindings/c/bindings-opaque.h | 33 ++++++++++++++++++++++++ src/main/bindings/c/bindings.h | 21 +-------------- src/main/bindings/c/cbindgen-opaque.toml | 18 +++++++++++++ src/main/bindings/c/cbindgen.toml | 4 ++- 5 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 src/main/bindings/c/bindings-opaque.h create mode 100644 src/main/bindings/c/cbindgen-opaque.toml diff --git a/src/main/bindings/c/CMakeLists.txt b/src/main/bindings/c/CMakeLists.txt index e270c6dc33..1ff8b334e1 100644 --- a/src/main/bindings/c/CMakeLists.txt +++ b/src/main/bindings/c/CMakeLists.txt @@ -17,14 +17,20 @@ foreach(COMPILE_DEFINITION IN LISTS COMPILE_DEFINITIONS) list(APPEND LLVM_FLAGS "-D${COMPILE_DEFINITION}") endforeach(COMPILE_DEFINITION) -# Generate wrapper.rs in the source tree. +# Generate bindings.h in the source tree. add_custom_command(OUTPUT bindings.h COMMAND cbindgen ${CMAKE_SOURCE_DIR}/src/main --config ${CMAKE_CURRENT_SOURCE_DIR}/cbindgen.toml --output ${CMAKE_CURRENT_SOURCE_DIR}/bindings.h) +# Generate bindings-opaque.h in the source tree. +add_custom_command(OUTPUT bindings-opaque.h + COMMAND cbindgen ${CMAKE_SOURCE_DIR}/src/main + --config ${CMAKE_CURRENT_SOURCE_DIR}/cbindgen-opaque.toml + --output ${CMAKE_CURRENT_SOURCE_DIR}/bindings-opaque.h) + # A fake target that depends on the wrapper. -add_custom_target(bindings_main_c DEPENDS bindings.h) +add_custom_target(bindings_main_c DEPENDS bindings.h bindings-opaque.h) # Only re-generate bindings when explicititly requested, so that # our CI doesn't need to install the heavy bindgen dependency. diff --git a/src/main/bindings/c/bindings-opaque.h b/src/main/bindings/c/bindings-opaque.h new file mode 100644 index 0000000000..345669559c --- /dev/null +++ b/src/main/bindings/c/bindings-opaque.h @@ -0,0 +1,33 @@ +/* + * The Shadow Simulator + * See LICENSE for licensing information + */ +// clang-format off + + +#ifndef main_opaque_bindings_h +#define main_opaque_bindings_h + +/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ + +// A queue of byte chunks. +typedef struct ByteQueue ByteQueue; + +// Manages the address-space for a plugin process. +// +// The MemoryManager's primary purpose is to make plugin process's memory directly accessible to +// Shadow. It does this by tracking what regions of program memory in the plugin are mapped to +// what (analagous to /proc//maps), and *remapping* parts of the plugin's address space into +// a shared memory-file, which is also mapped into Shadow. +// +// Shadow provides several methods for allowing Shadow to access the plugin's memory, such as +// `get_readable_ptr`. If the corresponding region of plugin memory is mapped into the shared +// memory file, the corresponding Shadow pointer is returned. If not, then, it'll fall back to +// (generally slower) Thread APIs. +// +// For the MemoryManager to maintain consistent state, and to remap regions of memory it knows how +// to remap, Shadow must delegate handling of mman-related syscalls (such as `mmap`) to the +// MemoryManager via its `handle_*` methods. +typedef struct MemoryManager MemoryManager; + +#endif /* main_opaque_bindings_h */ diff --git a/src/main/bindings/c/bindings.h b/src/main/bindings/c/bindings.h index d49dc39f68..d820885042 100644 --- a/src/main/bindings/c/bindings.h +++ b/src/main/bindings/c/bindings.h @@ -14,29 +14,10 @@ #include #include #include +#include "main/bindings/c/bindings-opaque.h" #include "main/host/syscall_types.h" #include "main/host/thread.h" -// A queue of byte chunks. -typedef struct ByteQueue ByteQueue; - -// Manages the address-space for a plugin process. -// -// The MemoryManager's primary purpose is to make plugin process's memory directly accessible to -// Shadow. It does this by tracking what regions of program memory in the plugin are mapped to -// what (analagous to /proc//maps), and *remapping* parts of the plugin's address space into -// a shared memory-file, which is also mapped into Shadow. -// -// Shadow provides several methods for allowing Shadow to access the plugin's memory, such as -// `get_readable_ptr`. If the corresponding region of plugin memory is mapped into the shared -// memory file, the corresponding Shadow pointer is returned. If not, then, it'll fall back to -// (generally slower) Thread APIs. -// -// For the MemoryManager to maintain consistent state, and to remap regions of memory it knows how -// to remap, Shadow must delegate handling of mman-related syscalls (such as `mmap`) to the -// MemoryManager via its `handle_*` methods. -typedef struct MemoryManager MemoryManager; - void rust_logging_init(void); // # Safety diff --git a/src/main/bindings/c/cbindgen-opaque.toml b/src/main/bindings/c/cbindgen-opaque.toml new file mode 100644 index 0000000000..0188e46d06 --- /dev/null +++ b/src/main/bindings/c/cbindgen-opaque.toml @@ -0,0 +1,18 @@ +language = 'C' +include_guard = "main_opaque_bindings_h" +line_length = 100 +documentation_style = "c99" +header = '''/* + * The Shadow Simulator + * See LICENSE for licensing information + */ +// clang-format off +''' +autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" +no_includes = true + +[export] +# Avoid exporting C types back through again. +exclude = ["PluginPtr", "SysCallReg"] +# Generate only opaque types +item_types = ["opaque"] diff --git a/src/main/bindings/c/cbindgen.toml b/src/main/bindings/c/cbindgen.toml index cd818970ad..f9e77ebda0 100644 --- a/src/main/bindings/c/cbindgen.toml +++ b/src/main/bindings/c/cbindgen.toml @@ -9,8 +9,10 @@ header = '''/* // clang-format off ''' autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" -includes = ["main/host/syscall_types.h", "main/host/thread.h"] +includes = ["main/bindings/c/bindings-opaque.h", "main/host/syscall_types.h", "main/host/thread.h"] [export] # Avoid exporting C types back through again. exclude = ["PluginPtr", "SysCallReg"] +# Generate all item types, excluding opaque types +item_types = ["constants", "globals", "enums", "structs", "unions", "typedefs", "functions"] From 2cb9675ae988d69895e5548a30780002504884e0 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Wed, 23 Dec 2020 13:59:57 -0500 Subject: [PATCH 03/13] Rename the C 'Descriptor' type to 'LegacyDescriptor' --- src/main/host/descriptor/channel.c | 28 ++++----- src/main/host/descriptor/channel.h | 2 +- src/main/host/descriptor/descriptor.c | 44 ++++++------- src/main/host/descriptor/descriptor.h | 34 +++++----- src/main/host/descriptor/descriptor_table.c | 12 ++-- src/main/host/descriptor/descriptor_table.h | 8 +-- src/main/host/descriptor/descriptor_types.h | 14 ++--- src/main/host/descriptor/epoll.c | 24 +++---- src/main/host/descriptor/epoll.h | 2 +- src/main/host/descriptor/eventd.c | 14 ++--- src/main/host/descriptor/file.c | 10 +-- src/main/host/descriptor/socket.c | 40 ++++++------ src/main/host/descriptor/socket.h | 2 +- src/main/host/descriptor/tcp.c | 70 ++++++++++----------- src/main/host/descriptor/tcp_cong_reno.c | 6 +- src/main/host/descriptor/timer.c | 14 ++--- src/main/host/descriptor/transport.c | 12 ++-- src/main/host/descriptor/transport.h | 4 +- src/main/host/descriptor/udp.c | 24 +++---- src/main/host/network_interface.c | 18 +++--- src/main/host/process.c | 24 +++---- src/main/host/process.h | 6 +- src/main/host/syscall/epoll.c | 14 ++--- src/main/host/syscall/eventfd.c | 8 +-- src/main/host/syscall/fcntl.c | 2 +- src/main/host/syscall/file.c | 6 +- src/main/host/syscall/fileat.c | 6 +- src/main/host/syscall/ioctl.c | 4 +- src/main/host/syscall/mman.c | 4 +- src/main/host/syscall/protected.c | 6 +- src/main/host/syscall/protected.h | 4 +- src/main/host/syscall/socket.c | 52 +++++++-------- src/main/host/syscall/timerfd.c | 8 +-- src/main/host/syscall/uio.c | 12 ++-- src/main/host/syscall/unistd.c | 22 +++---- src/main/host/syscall_condition.c | 4 +- src/main/host/syscall_condition.h | 2 +- 37 files changed, 283 insertions(+), 283 deletions(-) diff --git a/src/main/host/descriptor/channel.c b/src/main/host/descriptor/channel.c index be28acfca3..1442421b7b 100644 --- a/src/main/host/descriptor/channel.c +++ b/src/main/host/descriptor/channel.c @@ -33,14 +33,14 @@ struct _Channel { MAGIC_DECLARE; }; -static Channel* _channel_fromDescriptor(Descriptor* descriptor) { +static Channel* _channel_fromLegacyDescriptor(LegacyDescriptor* descriptor) { utility_assert(descriptor_getType(descriptor) == DT_PIPE || descriptor_getType(descriptor) == DT_UNIXSOCKET); return (Channel*)descriptor; } -static gboolean channel_close(Descriptor* descriptor) { - Channel* channel = _channel_fromDescriptor(descriptor); +static gboolean channel_close(LegacyDescriptor* descriptor) { + Channel* channel = _channel_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(channel); /* tell our link that we are done */ if(channel->linkedChannel) { @@ -58,13 +58,13 @@ static gboolean channel_close(Descriptor* descriptor) { return TRUE; } -static void channel_free(Descriptor* descriptor) { - Channel* channel = _channel_fromDescriptor(descriptor); +static void channel_free(LegacyDescriptor* descriptor) { + Channel* channel = _channel_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(channel); bytequeue_free(channel->buffer); - descriptor_clear((Descriptor*)channel); + descriptor_clear((LegacyDescriptor*)channel); MAGIC_CLEAR(channel); g_free(channel); @@ -88,14 +88,14 @@ static gssize channel_linkedWrite(Channel* channel, gconstpointer buffer, gsize channel->bufferLength += copyLength; /* we just got some data in our buffer */ - descriptor_adjustStatus((Descriptor*)channel, STATUS_DESCRIPTOR_READABLE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)channel, STATUS_DESCRIPTOR_READABLE, TRUE); return copyLength; } static gssize channel_sendUserData(Transport* transport, gconstpointer buffer, gsize nBytes, in_addr_t ip, in_port_t port) { - Channel* channel = _channel_fromDescriptor((Descriptor*)transport); + Channel* channel = _channel_fromLegacyDescriptor((LegacyDescriptor*)transport); MAGIC_ASSERT(channel); /* the read end of a unidirectional pipe can not write! */ utility_assert(channel->type != CT_READONLY); @@ -113,7 +113,7 @@ static gssize channel_sendUserData(Transport* transport, gconstpointer buffer, /* our end cant write anymore if they returned error */ if(result <= (gssize)0) { - descriptor_adjustStatus((Descriptor*)channel, STATUS_DESCRIPTOR_WRITABLE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)channel, STATUS_DESCRIPTOR_WRITABLE, FALSE); } return result; @@ -122,7 +122,7 @@ static gssize channel_sendUserData(Transport* transport, gconstpointer buffer, static gssize channel_receiveUserData(Transport* transport, gpointer buffer, gsize nBytes, in_addr_t* ip, in_port_t* port) { - Channel* channel = _channel_fromDescriptor((Descriptor*)transport); + Channel* channel = _channel_fromLegacyDescriptor((LegacyDescriptor*)transport); MAGIC_ASSERT(channel); /* the write end of a unidirectional pipe can not read! */ utility_assert(channel->type != CT_WRITEONLY); @@ -146,7 +146,7 @@ static gssize channel_receiveUserData(Transport* transport, gpointer buffer, /* we are no longer readable if we have nothing left */ if(channel->bufferLength <= 0) { - descriptor_adjustStatus((Descriptor*)channel, STATUS_DESCRIPTOR_READABLE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)channel, STATUS_DESCRIPTOR_READABLE, FALSE); } return (gssize)numCopied; @@ -156,7 +156,7 @@ TransportFunctionTable channel_functions = { channel_close, channel_free, channel_sendUserData, channel_receiveUserData, MAGIC_VALUE}; -Channel* channel_new(ChannelType type, DescriptorType dtype) { +Channel* channel_new(ChannelType type, LegacyDescriptorType dtype) { Channel* channel = g_new0(Channel, 1); MAGIC_INIT(channel); @@ -166,9 +166,9 @@ Channel* channel_new(ChannelType type, DescriptorType dtype) { channel->buffer = bytequeue_new(8192); channel->bufferSize = CONFIG_PIPE_BUFFER_SIZE; - descriptor_adjustStatus((Descriptor*)channel, STATUS_DESCRIPTOR_ACTIVE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)channel, STATUS_DESCRIPTOR_ACTIVE, TRUE); if(!(type & CT_READONLY)) { - descriptor_adjustStatus((Descriptor*)channel, STATUS_DESCRIPTOR_WRITABLE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)channel, STATUS_DESCRIPTOR_WRITABLE, TRUE); } worker_countObject(OBJECT_TYPE_CHANNEL, COUNTER_TYPE_NEW); diff --git a/src/main/host/descriptor/channel.h b/src/main/host/descriptor/channel.h index adbe40fe4c..c9297cc679 100644 --- a/src/main/host/descriptor/channel.h +++ b/src/main/host/descriptor/channel.h @@ -18,7 +18,7 @@ enum _ChannelType { typedef struct _Channel Channel; -Channel* channel_new(ChannelType type, DescriptorType dtype); +Channel* channel_new(ChannelType type, LegacyDescriptorType dtype); void channel_setLinkedChannel(Channel* channel, Channel* linkedChannel); Channel* channel_getLinkedChannel(Channel* channel); diff --git a/src/main/host/descriptor/descriptor.c b/src/main/host/descriptor/descriptor.c index c756f0acd5..90a836d66a 100644 --- a/src/main/host/descriptor/descriptor.c +++ b/src/main/host/descriptor/descriptor.c @@ -16,7 +16,7 @@ #include "main/utility/utility.h" #include "support/logger/logger.h" -void descriptor_init(Descriptor* descriptor, DescriptorType type, +void descriptor_init(LegacyDescriptor* descriptor, LegacyDescriptorType type, DescriptorFunctionTable* funcTable) { utility_assert(descriptor && funcTable); @@ -33,7 +33,7 @@ void descriptor_init(Descriptor* descriptor, DescriptorType type, worker_countObject(OBJECT_TYPE_DESCRIPTOR, COUNTER_TYPE_NEW); } -void descriptor_clear(Descriptor* descriptor) { +void descriptor_clear(LegacyDescriptor* descriptor) { MAGIC_ASSERT(descriptor); if (descriptor->listeners) { g_hash_table_destroy(descriptor->listeners); @@ -41,7 +41,7 @@ void descriptor_clear(Descriptor* descriptor) { MAGIC_CLEAR(descriptor); } -static void _descriptor_free(Descriptor* descriptor) { +static void _descriptor_free(LegacyDescriptor* descriptor) { MAGIC_ASSERT(descriptor); MAGIC_ASSERT(descriptor->funcTable); @@ -52,7 +52,7 @@ static void _descriptor_free(Descriptor* descriptor) { } void descriptor_ref(gpointer data) { - Descriptor* descriptor = data; + LegacyDescriptor* descriptor = data; MAGIC_ASSERT(descriptor); (descriptor->referenceCount)++; @@ -61,7 +61,7 @@ void descriptor_ref(gpointer data) { } void descriptor_unref(gpointer data) { - Descriptor* descriptor = data; + LegacyDescriptor* descriptor = data; MAGIC_ASSERT(descriptor); (descriptor->referenceCount)--; @@ -75,48 +75,48 @@ void descriptor_unref(gpointer data) { } } -void descriptor_close(Descriptor* descriptor) { +void descriptor_close(LegacyDescriptor* descriptor) { MAGIC_ASSERT(descriptor); MAGIC_ASSERT(descriptor->funcTable); debug("Descriptor %i calling vtable close now", descriptor->handle); descriptor_adjustStatus(descriptor, STATUS_DESCRIPTOR_CLOSED, TRUE); if (descriptor->funcTable->close(descriptor) && descriptor->ownerProcess) { - process_deregisterDescriptor(descriptor->ownerProcess, descriptor); + process_deregisterLegacyDescriptor(descriptor->ownerProcess, descriptor); } } -gint descriptor_compare(const Descriptor* foo, const Descriptor* bar, gpointer user_data) { +gint descriptor_compare(const LegacyDescriptor* foo, const LegacyDescriptor* bar, gpointer user_data) { MAGIC_ASSERT(foo); MAGIC_ASSERT(bar); return foo->handle > bar->handle ? +1 : foo->handle == bar->handle ? 0 : -1; } -DescriptorType descriptor_getType(Descriptor* descriptor) { +LegacyDescriptorType descriptor_getType(LegacyDescriptor* descriptor) { MAGIC_ASSERT(descriptor); return descriptor->type; } -void descriptor_setHandle(Descriptor* descriptor, gint handle) { +void descriptor_setHandle(LegacyDescriptor* descriptor, gint handle) { MAGIC_ASSERT(descriptor); descriptor->handle = handle; } -gint descriptor_getHandle(Descriptor* descriptor) { +gint descriptor_getHandle(LegacyDescriptor* descriptor) { MAGIC_ASSERT(descriptor); return descriptor->handle; } -void descriptor_setOwnerProcess(Descriptor* descriptor, Process* ownerProcess) { +void descriptor_setOwnerProcess(LegacyDescriptor* descriptor, Process* ownerProcess) { MAGIC_ASSERT(descriptor); descriptor->ownerProcess = ownerProcess; } -Process* descriptor_getOwnerProcess(Descriptor* descriptor) { +Process* descriptor_getOwnerProcess(LegacyDescriptor* descriptor) { MAGIC_ASSERT(descriptor); return descriptor->ownerProcess; } -gint* descriptor_getHandleReference(Descriptor* descriptor) { +gint* descriptor_getHandleReference(LegacyDescriptor* descriptor) { MAGIC_ASSERT(descriptor); return &(descriptor->handle); } @@ -144,7 +144,7 @@ static gchar* _descriptor_statusToString(Status ds) { } #endif -static void _descriptor_handleStatusChange(Descriptor* descriptor, Status oldStatus) { +static void _descriptor_handleStatusChange(LegacyDescriptor* descriptor, Status oldStatus) { MAGIC_ASSERT(descriptor); /* Identify which bits changed, if any. */ @@ -187,7 +187,7 @@ static void _descriptor_handleStatusChange(Descriptor* descriptor, Status oldSta g_list_free(listenerList); } -void descriptor_adjustStatus(Descriptor* descriptor, Status status, gboolean doSetBits) { +void descriptor_adjustStatus(LegacyDescriptor* descriptor, Status status, gboolean doSetBits) { MAGIC_ASSERT(descriptor); Status oldStatus = descriptor->status; @@ -205,35 +205,35 @@ void descriptor_adjustStatus(Descriptor* descriptor, Status status, gboolean doS _descriptor_handleStatusChange(descriptor, oldStatus); } -Status descriptor_getStatus(Descriptor* descriptor) { +Status descriptor_getStatus(LegacyDescriptor* descriptor) { MAGIC_ASSERT(descriptor); return descriptor->status; } -void descriptor_addListener(Descriptor* descriptor, StatusListener* listener) { +void descriptor_addListener(LegacyDescriptor* descriptor, StatusListener* listener) { MAGIC_ASSERT(descriptor); /* We are storing a listener instance, so count the ref. */ statuslistener_ref(listener); g_hash_table_insert(descriptor->listeners, listener, listener); } -void descriptor_removeListener(Descriptor* descriptor, StatusListener* listener) { +void descriptor_removeListener(LegacyDescriptor* descriptor, StatusListener* listener) { MAGIC_ASSERT(descriptor); /* This will automatically call descriptorlistener_unref on the instance. */ g_hash_table_remove(descriptor->listeners, listener); } -gint descriptor_getFlags(Descriptor* descriptor) { +gint descriptor_getFlags(LegacyDescriptor* descriptor) { MAGIC_ASSERT(descriptor); return descriptor->flags; } -void descriptor_setFlags(Descriptor* descriptor, gint flags) { +void descriptor_setFlags(LegacyDescriptor* descriptor, gint flags) { MAGIC_ASSERT(descriptor); descriptor->flags = flags; } -void descriptor_addFlags(Descriptor* descriptor, gint flags) { +void descriptor_addFlags(LegacyDescriptor* descriptor, gint flags) { MAGIC_ASSERT(descriptor); descriptor->flags |= flags; } diff --git a/src/main/host/descriptor/descriptor.h b/src/main/host/descriptor/descriptor.h index 61196fe756..947ead671f 100644 --- a/src/main/host/descriptor/descriptor.h +++ b/src/main/host/descriptor/descriptor.h @@ -15,27 +15,27 @@ /* Initialize the parent parts of a new descriptor subclass. This call should * be paired with a call to clear() before freeing the subclass object. */ -void descriptor_init(Descriptor* descriptor, DescriptorType type, +void descriptor_init(LegacyDescriptor* descriptor, LegacyDescriptorType type, DescriptorFunctionTable* funcTable); /* Clear the bits that were initialized in init(). Following this call, the * descriptor becomes invalid and the subclass should be freed. */ -void descriptor_clear(Descriptor* descriptor); +void descriptor_clear(LegacyDescriptor* descriptor); void descriptor_ref(gpointer data); void descriptor_unref(gpointer data); -void descriptor_close(Descriptor* descriptor); -gint descriptor_compare(const Descriptor* foo, const Descriptor* bar, gpointer user_data); +void descriptor_close(LegacyDescriptor* descriptor); +gint descriptor_compare(const LegacyDescriptor* foo, const LegacyDescriptor* bar, gpointer user_data); -void descriptor_setHandle(Descriptor* descriptor, gint handle); -gint descriptor_getHandle(Descriptor* descriptor); -void descriptor_setOwnerProcess(Descriptor* descriptor, Process* ownerProcess); -Process* descriptor_getOwnerProcess(Descriptor* descriptor); -DescriptorType descriptor_getType(Descriptor* descriptor); -gint* descriptor_getHandleReference(Descriptor* descriptor); +void descriptor_setHandle(LegacyDescriptor* descriptor, gint handle); +gint descriptor_getHandle(LegacyDescriptor* descriptor); +void descriptor_setOwnerProcess(LegacyDescriptor* descriptor, Process* ownerProcess); +Process* descriptor_getOwnerProcess(LegacyDescriptor* descriptor); +LegacyDescriptorType descriptor_getType(LegacyDescriptor* descriptor); +gint* descriptor_getHandleReference(LegacyDescriptor* descriptor); -gint descriptor_getFlags(Descriptor* descriptor); -void descriptor_setFlags(Descriptor* descriptor, gint flags); -void descriptor_addFlags(Descriptor* descriptor, gint flags); +gint descriptor_getFlags(LegacyDescriptor* descriptor); +void descriptor_setFlags(LegacyDescriptor* descriptor, gint flags); +void descriptor_addFlags(LegacyDescriptor* descriptor, gint flags); /* * One of the main functions of the descriptor is to track its poll status, @@ -61,18 +61,18 @@ void descriptor_addFlags(Descriptor* descriptor, gint flags); * listener will trigger notifications via callback functions if the listener is * configured to monitor a bit that flipped. */ -void descriptor_adjustStatus(Descriptor* descriptor, Status status, gboolean doSetBits); +void descriptor_adjustStatus(LegacyDescriptor* descriptor, Status status, gboolean doSetBits); /* Gets the current status of the descriptor. */ -Status descriptor_getStatus(Descriptor* descriptor); +Status descriptor_getStatus(LegacyDescriptor* descriptor); /* Adds a listener that will get notified via descriptorlistener_onStatusChanged * on status transitions (bit flips). */ -void descriptor_addListener(Descriptor* descriptor, StatusListener* listener); +void descriptor_addListener(LegacyDescriptor* descriptor, StatusListener* listener); /* Remove the listener for our set of listeners that get notified on status * transitions (bit flips). */ -void descriptor_removeListener(Descriptor* descriptor, StatusListener* listener); +void descriptor_removeListener(LegacyDescriptor* descriptor, StatusListener* listener); #endif /* SHD_DESCRIPTOR_H_ */ diff --git a/src/main/host/descriptor/descriptor_table.c b/src/main/host/descriptor/descriptor_table.c index a74a51d9c4..1e3efdea90 100644 --- a/src/main/host/descriptor/descriptor_table.c +++ b/src/main/host/descriptor/descriptor_table.c @@ -82,7 +82,7 @@ void descriptortable_unref(DescriptorTable* table) { } } -int descriptortable_add(DescriptorTable* table, Descriptor* descriptor) { +int descriptortable_add(DescriptorTable* table, LegacyDescriptor* descriptor) { MAGIC_ASSERT(table); int index = 0; @@ -121,7 +121,7 @@ static void _descriptortable_trimIndicesTail(DescriptorTable* table) { } } -bool descriptortable_remove(DescriptorTable* table, Descriptor* descriptor) { +bool descriptortable_remove(DescriptorTable* table, LegacyDescriptor* descriptor) { MAGIC_ASSERT(table); int index = descriptor_getHandle(descriptor); @@ -140,17 +140,17 @@ bool descriptortable_remove(DescriptorTable* table, Descriptor* descriptor) { } } -Descriptor* descriptortable_get(DescriptorTable* table, int index) { +LegacyDescriptor* descriptortable_get(DescriptorTable* table, int index) { MAGIC_ASSERT(table); return g_hash_table_lookup(table->descriptors, GINT_TO_POINTER(index)); } void descriptortable_set(DescriptorTable* table, int index, - Descriptor* descriptor) { + LegacyDescriptor* descriptor) { MAGIC_ASSERT(table); /* We may be replacing a descriptor that is already set at index. */ - Descriptor* existing = descriptortable_get(table, index); + LegacyDescriptor* existing = descriptortable_get(table, index); if (existing) { descriptor_setHandle(existing, 0); } @@ -172,7 +172,7 @@ void descriptortable_shutdownHelper(DescriptorTable* table) { gpointer key, value; g_hash_table_iter_init(&iter, table->descriptors); while (g_hash_table_iter_next(&iter, &key, &value)) { - Descriptor* desc = value; + LegacyDescriptor* desc = value; if (desc && desc->type == DT_TCPSOCKET) { /* tcp servers and their children holds refs to each other. make * sure they all get freed by removing the refs in one direction */ diff --git a/src/main/host/descriptor/descriptor_table.h b/src/main/host/descriptor/descriptor_table.h index f96f510640..dbe31dc39a 100644 --- a/src/main/host/descriptor/descriptor_table.h +++ b/src/main/host/descriptor/descriptor_table.h @@ -31,7 +31,7 @@ void descriptortable_unref(DescriptorTable* table); * NOTE: that this consumes a reference to the descriptor, so if you are storing * it outside of the descriptor table you will need to ref it after calling * this function. */ -int descriptortable_add(DescriptorTable* table, Descriptor* descriptor); +int descriptortable_add(DescriptorTable* table, LegacyDescriptor* descriptor); /* Stop storing the descriptor so that it can no longer be referenced. The table * index that was used to store the descriptor is cleared from the descriptor @@ -41,18 +41,18 @@ int descriptortable_add(DescriptorTable* table, Descriptor* descriptor); * * NOTE: this will unref the descriptor which may cause it to be freed. If you * still need access to it, you should ref it before calling this function. */ -bool descriptortable_remove(DescriptorTable* table, Descriptor* descriptor); +bool descriptortable_remove(DescriptorTable* table, LegacyDescriptor* descriptor); /* Returns the descriptor at the given table index, or NULL if we are not * storing a descriptor at the given index. */ -Descriptor* descriptortable_get(DescriptorTable* table, int index); +LegacyDescriptor* descriptortable_get(DescriptorTable* table, int index); /* Store the given descriptor at given index. Any previous descriptor that was * stored there will be removed and its table index will be cleared. This * unrefs any existing descriptor stored at index as in remove(), and consumes * a ref to the existing descriptor as in add(). */ void descriptortable_set(DescriptorTable* table, int index, - Descriptor* descriptor); + LegacyDescriptor* descriptor); /* This is a helper function that handles some corner cases where some * descriptors are linked to each other and we must remove that link in diff --git a/src/main/host/descriptor/descriptor_types.h b/src/main/host/descriptor/descriptor_types.h index ceada6917d..1d1da85c7a 100644 --- a/src/main/host/descriptor/descriptor_types.h +++ b/src/main/host/descriptor/descriptor_types.h @@ -11,8 +11,8 @@ #include "main/host/status.h" #include "main/utility/utility.h" -typedef enum _DescriptorType DescriptorType; -enum _DescriptorType { +typedef enum _LegacyDescriptorType LegacyDescriptorType; +enum _LegacyDescriptorType { DT_NONE, DT_TCPSOCKET, DT_UDPSOCKET, @@ -24,7 +24,7 @@ enum _DescriptorType { DT_FILE, }; -typedef struct _Descriptor Descriptor; +typedef struct _LegacyDescriptor LegacyDescriptor; typedef struct _DescriptorFunctionTable DescriptorFunctionTable; /* required functions */ @@ -32,8 +32,8 @@ typedef struct _DescriptorFunctionTable DescriptorFunctionTable; /* Returns TRUE if the descriptor should be deregistered from the owning * process upon return from the function, FALSE if the child will handle * deregistration on its own. */ -typedef gboolean (*DescriptorCloseFunc)(Descriptor* descriptor); -typedef void (*DescriptorFreeFunc)(Descriptor* descriptor); +typedef gboolean (*DescriptorCloseFunc)(LegacyDescriptor* descriptor); +typedef void (*DescriptorFreeFunc)(LegacyDescriptor* descriptor); /* * Virtual function table for base descriptor, storing pointers to required @@ -45,11 +45,11 @@ struct _DescriptorFunctionTable { MAGIC_DECLARE; }; -struct _Descriptor { +struct _LegacyDescriptor { DescriptorFunctionTable* funcTable; Process* ownerProcess; gint handle; - DescriptorType type; + LegacyDescriptorType type; Status status; GHashTable* listeners; gint referenceCount; diff --git a/src/main/host/descriptor/epoll.c b/src/main/host/descriptor/epoll.c index 61edb14c69..8b150edbd1 100644 --- a/src/main/host/descriptor/epoll.c +++ b/src/main/host/descriptor/epoll.c @@ -58,7 +58,7 @@ enum _EpollWatchFlags { typedef struct _EpollWatch EpollWatch; struct _EpollWatch { /* the shadow descriptor we are watching for events */ - Descriptor* descriptor; + LegacyDescriptor* descriptor; /* The listener that notifies us when status changes. */ StatusListener* listener; /* holds the actual event info */ @@ -71,7 +71,7 @@ struct _EpollWatch { struct _Epoll { /* epoll itself is also a descriptor */ - Descriptor super; + LegacyDescriptor super; /* holds the wrappers for the descriptors we are watching for events */ GHashTable* watching; @@ -84,9 +84,9 @@ struct _Epoll { /* forward declaration */ static void _epoll_descriptorStatusChanged(Epoll* epoll, - Descriptor* descriptor); + LegacyDescriptor* descriptor); -static EpollWatch* _epollwatch_new(Epoll* epoll, Descriptor* descriptor, +static EpollWatch* _epollwatch_new(Epoll* epoll, LegacyDescriptor* descriptor, const struct epoll_event* event) { EpollWatch* watch = g_new0(EpollWatch, 1); MAGIC_INIT(watch); @@ -132,21 +132,21 @@ static void _epollwatch_unref(EpollWatch* watch) { } } -static Epoll* _epoll_fromDescriptor(Descriptor* descriptor) { +static Epoll* _epoll_fromLegacyDescriptor(LegacyDescriptor* descriptor) { utility_assert(descriptor_getType(descriptor) == DT_EPOLL); return (Epoll*)descriptor; } /* should only be called from descriptor dereferencing the functionTable */ -static void _epoll_free(Descriptor* descriptor) { - Epoll* epoll = _epoll_fromDescriptor(descriptor); +static void _epoll_free(LegacyDescriptor* descriptor) { + Epoll* epoll = _epoll_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(epoll); /* this unrefs all of the remaining watches */ g_hash_table_destroy(epoll->watching); g_hash_table_destroy(epoll->ready); - descriptor_clear((Descriptor*)epoll); + descriptor_clear((LegacyDescriptor*)epoll); MAGIC_CLEAR(epoll); g_free(epoll); @@ -168,8 +168,8 @@ void epoll_clearWatchListeners(Epoll* epoll) { } } -static gboolean _epoll_close(Descriptor* descriptor) { - Epoll* epoll = _epoll_fromDescriptor(descriptor); +static gboolean _epoll_close(LegacyDescriptor* descriptor) { + Epoll* epoll = _epoll_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(epoll); epoll_clearWatchListeners(epoll); return TRUE; @@ -285,7 +285,7 @@ static const gchar* _epoll_operationToStr(gint op) { } } -gint epoll_control(Epoll* epoll, gint operation, Descriptor* descriptor, +gint epoll_control(Epoll* epoll, gint operation, LegacyDescriptor* descriptor, const struct epoll_event* event) { MAGIC_ASSERT(epoll); @@ -442,7 +442,7 @@ gint epoll_getEvents(Epoll* epoll, struct epoll_event* eventArray, gint eventArr } static void _epoll_descriptorStatusChanged(Epoll* epoll, - Descriptor* descriptor) { + LegacyDescriptor* descriptor) { MAGIC_ASSERT(epoll); /* make sure we are actually watching the descriptor */ diff --git a/src/main/host/descriptor/epoll.h b/src/main/host/descriptor/epoll.h index f2c900a337..80911340c9 100644 --- a/src/main/host/descriptor/epoll.h +++ b/src/main/host/descriptor/epoll.h @@ -17,7 +17,7 @@ typedef struct _Epoll Epoll; /* free this with descriptor_free() */ Epoll* epoll_new(); -gint epoll_control(Epoll* epoll, gint operation, Descriptor* descriptor, +gint epoll_control(Epoll* epoll, gint operation, LegacyDescriptor* descriptor, const struct epoll_event* event); gint epoll_getEvents(Epoll* epoll, struct epoll_event* eventArray, gint eventArrayLength, gint* nEvents); diff --git a/src/main/host/descriptor/eventd.c b/src/main/host/descriptor/eventd.c index 76d34acfab..3bf9b989de 100644 --- a/src/main/host/descriptor/eventd.c +++ b/src/main/host/descriptor/eventd.c @@ -17,7 +17,7 @@ #include "support/logger/logger.h" struct _EventD { - Descriptor super; + LegacyDescriptor super; uint64_t counter; bool is_closed; @@ -26,13 +26,13 @@ struct _EventD { MAGIC_DECLARE; }; -static EventD* _eventfd_fromDescriptor(Descriptor* descriptor) { +static EventD* _eventfd_fromLegacyDescriptor(LegacyDescriptor* descriptor) { utility_assert(descriptor_getType(descriptor) == DT_EVENTD); return (EventD*)descriptor; } -static gboolean _eventd_close(Descriptor* descriptor) { - EventD* eventd = _eventfd_fromDescriptor(descriptor); +static gboolean _eventd_close(LegacyDescriptor* descriptor) { + EventD* eventd = _eventfd_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(eventd); debug("event fd %i closing now", eventd->super.handle); @@ -47,11 +47,11 @@ static gboolean _eventd_close(Descriptor* descriptor) { } } -static void _eventd_free(Descriptor* descriptor) { - EventD* eventd = _eventfd_fromDescriptor(descriptor); +static void _eventd_free(LegacyDescriptor* descriptor) { + EventD* eventd = _eventfd_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(eventd); - descriptor_clear((Descriptor*)eventd); + descriptor_clear((LegacyDescriptor*)eventd); MAGIC_CLEAR(eventd); free(eventd); diff --git a/src/main/host/descriptor/file.c b/src/main/host/descriptor/file.c index 072278380b..a500efe2fa 100644 --- a/src/main/host/descriptor/file.c +++ b/src/main/host/descriptor/file.c @@ -44,7 +44,7 @@ enum _FileType { struct _File { /* File is a sub-type of a descriptor. */ - Descriptor super; + LegacyDescriptor super; FileType type; /* Info related to our OS-backed file. */ struct { @@ -71,7 +71,7 @@ char* file_getAbsolutePath(File* file) { return file->osfile.abspath; } -static inline File* _file_descriptorToFile(Descriptor* desc) { +static inline File* _file_descriptorToFile(LegacyDescriptor* desc) { utility_assert(descriptor_getType(desc) == DT_FILE); File* file = (File*)desc; MAGIC_ASSERT(file); @@ -110,7 +110,7 @@ static void _file_closeHelper(File* file) { } } -static gboolean _file_close(Descriptor* desc) { +static gboolean _file_close(LegacyDescriptor* desc) { File* file = _file_descriptorToFile(desc); debug("Closing file %i with os-backed file %i", _file_getFD(file), @@ -124,7 +124,7 @@ static gboolean _file_close(Descriptor* desc) { return TRUE; } -static void _file_free(Descriptor* desc) { +static void _file_free(LegacyDescriptor* desc) { File* file = _file_descriptorToFile(desc); debug("Freeing file %i with os-backed file %i", _file_getFD(file), @@ -136,7 +136,7 @@ static void _file_free(Descriptor* desc) { free(file->osfile.abspath); } - descriptor_clear((Descriptor*)file); + descriptor_clear((LegacyDescriptor*)file); MAGIC_CLEAR(file); free(file); diff --git a/src/main/host/descriptor/socket.c b/src/main/host/descriptor/socket.c index ae27bb78b4..9c5a6e1f77 100644 --- a/src/main/host/descriptor/socket.c +++ b/src/main/host/descriptor/socket.c @@ -22,14 +22,14 @@ #include "main/routing/packet.h" #include "main/utility/utility.h" -static Socket* _socket_fromDescriptor(Descriptor* descriptor) { +static Socket* _socket_fromLegacyDescriptor(LegacyDescriptor* descriptor) { utility_assert(descriptor_getType(descriptor) == DT_TCPSOCKET || descriptor_getType(descriptor) == DT_UDPSOCKET); return (Socket*)descriptor; } -static void _socket_free(Descriptor* descriptor) { - Socket* socket = _socket_fromDescriptor(descriptor); +static void _socket_free(LegacyDescriptor* descriptor) { + Socket* socket = _socket_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(socket); MAGIC_ASSERT(socket->vtable); @@ -63,23 +63,23 @@ static void _socket_free(Descriptor* descriptor) { // during the free call. This could be fixed by making all descriptor types // a direct child of the descriptor class. MAGIC_CLEAR(socket); - socket->vtable->free((Descriptor*)socket); + socket->vtable->free((LegacyDescriptor*)socket); } -static gboolean _socket_close(Descriptor* descriptor) { - Socket* socket = _socket_fromDescriptor(descriptor); +static gboolean _socket_close(LegacyDescriptor* descriptor) { + Socket* socket = _socket_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(socket); MAGIC_ASSERT(socket->vtable); Tracker* tracker = host_getTracker(worker_getActiveHost()); tracker_removeSocket(tracker, descriptor_getHandle(descriptor)); - return socket->vtable->close((Descriptor*)socket); + return socket->vtable->close((LegacyDescriptor*)socket); } static gssize _socket_sendUserData(Transport* transport, gconstpointer buffer, gsize nBytes, in_addr_t ip, in_port_t port) { - Socket* socket = _socket_fromDescriptor((Descriptor*)transport); + Socket* socket = _socket_fromLegacyDescriptor((LegacyDescriptor*)transport); MAGIC_ASSERT(socket); MAGIC_ASSERT(socket->vtable); return socket->vtable->send((Transport*)socket, buffer, nBytes, ip, port); @@ -88,7 +88,7 @@ static gssize _socket_sendUserData(Transport* transport, gconstpointer buffer, static gssize _socket_receiveUserData(Transport* transport, gpointer buffer, gsize nBytes, in_addr_t* ip, in_port_t* port) { - Socket* socket = _socket_fromDescriptor((Descriptor*)transport); + Socket* socket = _socket_fromLegacyDescriptor((LegacyDescriptor*)transport); MAGIC_ASSERT(socket); MAGIC_ASSERT(socket->vtable); return socket->vtable->receive((Transport*)socket, buffer, nBytes, ip, port); @@ -99,7 +99,7 @@ TransportFunctionTable socket_functions = { MAGIC_VALUE}; void socket_init(Socket* socket, SocketFunctionTable* vtable, - DescriptorType type, guint receiveBufferSize, + LegacyDescriptorType type, guint receiveBufferSize, guint sendBufferSize) { utility_assert(socket && vtable); @@ -118,7 +118,7 @@ void socket_init(Socket* socket, SocketFunctionTable* vtable, socket->outputBufferSize = sendBufferSize; Tracker* tracker = host_getTracker(worker_getActiveHost()); - Descriptor* descriptor = (Descriptor *)socket; + LegacyDescriptor* descriptor = (LegacyDescriptor *)socket; tracker_addSocket(tracker, descriptor->handle, socket->protocol, socket->inputBufferSize, socket->outputBufferSize); } @@ -140,7 +140,7 @@ gint socket_connectToPeer(Socket* socket, in_addr_t ip, in_port_t port, sa_famil MAGIC_ASSERT(socket->vtable); Tracker* tracker = host_getTracker(worker_getActiveHost()); - Descriptor* descriptor = (Descriptor *)socket; + LegacyDescriptor* descriptor = (LegacyDescriptor *)socket; tracker_updateSocketPeer(tracker, descriptor->handle, ip, ntohs(port)); return socket->vtable->connectToPeer(socket, ip, port, family); @@ -345,12 +345,12 @@ gboolean socket_addToInputBuffer(Socket* socket, Packet* packet) { /* update the tracker input buffer stats */ Tracker* tracker = host_getTracker(worker_getActiveHost()); - Descriptor* descriptor = (Descriptor *)socket; + LegacyDescriptor* descriptor = (LegacyDescriptor *)socket; tracker_updateSocketInputBuffer(tracker, descriptor->handle, socket->inputBufferLength, socket->inputBufferSize); /* we just added a packet, so we are readable */ if(socket->inputBufferLength > 0) { - descriptor_adjustStatus((Descriptor*)socket, STATUS_DESCRIPTOR_READABLE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)socket, STATUS_DESCRIPTOR_READABLE, TRUE); } return TRUE; @@ -373,12 +373,12 @@ Packet* socket_removeFromInputBuffer(Socket* socket) { /* update the tracker input buffer stats */ Tracker* tracker = host_getTracker(worker_getActiveHost()); - Descriptor* descriptor = (Descriptor *)socket; + LegacyDescriptor* descriptor = (LegacyDescriptor *)socket; tracker_updateSocketInputBuffer(tracker, descriptor->handle, socket->inputBufferLength, socket->inputBufferSize); /* we are not readable if we are now empty */ if(socket->inputBufferLength <= 0) { - descriptor_adjustStatus((Descriptor*)socket, STATUS_DESCRIPTOR_READABLE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)socket, STATUS_DESCRIPTOR_READABLE, FALSE); } } @@ -420,12 +420,12 @@ gboolean socket_addToOutputBuffer(Socket* socket, Packet* packet) { /* update the tracker input buffer stats */ Tracker* tracker = host_getTracker(worker_getActiveHost()); - Descriptor* descriptor = (Descriptor *)socket; + LegacyDescriptor* descriptor = (LegacyDescriptor *)socket; tracker_updateSocketOutputBuffer(tracker, descriptor->handle, socket->outputBufferLength, socket->outputBufferSize); /* we just added a packet, we are no longer writable if full */ if(_socket_getOutputBufferSpaceIncludingTCP(socket) <= 0) { - descriptor_adjustStatus((Descriptor*)socket, STATUS_DESCRIPTOR_WRITABLE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)socket, STATUS_DESCRIPTOR_WRITABLE, FALSE); } /* tell the interface to include us when sending out to the network */ @@ -455,12 +455,12 @@ Packet* socket_removeFromOutputBuffer(Socket* socket) { /* update the tracker input buffer stats */ Tracker* tracker = host_getTracker(worker_getActiveHost()); - Descriptor* descriptor = (Descriptor *)socket; + LegacyDescriptor* descriptor = (LegacyDescriptor *)socket; tracker_updateSocketOutputBuffer(tracker, descriptor->handle, socket->outputBufferLength, socket->outputBufferSize); /* we are writable if we now have space */ if(_socket_getOutputBufferSpaceIncludingTCP(socket) > 0) { - descriptor_adjustStatus((Descriptor*)socket, STATUS_DESCRIPTOR_WRITABLE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)socket, STATUS_DESCRIPTOR_WRITABLE, TRUE); } } diff --git a/src/main/host/descriptor/socket.h b/src/main/host/descriptor/socket.h index fa5f2c44d8..5bc85ff01a 100644 --- a/src/main/host/descriptor/socket.h +++ b/src/main/host/descriptor/socket.h @@ -78,7 +78,7 @@ struct _Socket { }; void socket_init(Socket* socket, SocketFunctionTable* vtable, - DescriptorType type, guint receiveBufferSize, + LegacyDescriptorType type, guint receiveBufferSize, guint sendBufferSize); void socket_pushInPacket(Socket* socket, Packet* packet); diff --git a/src/main/host/descriptor/tcp.c b/src/main/host/descriptor/tcp.c index 85b40df406..9f66686f99 100644 --- a/src/main/host/descriptor/tcp.c +++ b/src/main/host/descriptor/tcp.c @@ -257,7 +257,7 @@ static void _rswlog(const TCP *tcp, const char *format, ...) { static void _tcp_flush(TCP* tcp); -static TCP* _tcp_fromDescriptor(Descriptor* descriptor) { +static TCP* _tcp_fromLegacyDescriptor(LegacyDescriptor* descriptor) { utility_assert(descriptor_getType(descriptor) == DT_TCPSOCKET); return (TCP*)descriptor; } @@ -621,7 +621,7 @@ static void _tcp_setState(TCP* tcp, enum TCPState state) { /* some state transitions require us to update the descriptor status */ switch (state) { case TCPS_LISTEN: { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_ACTIVE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_ACTIVE, TRUE); break; } case TCPS_SYNSENT: { @@ -633,7 +633,7 @@ static void _tcp_setState(TCP* tcp, enum TCPState state) { case TCPS_ESTABLISHED: { tcp->flags |= TCPF_WAS_ESTABLISHED; descriptor_adjustStatus( - (Descriptor*)tcp, STATUS_DESCRIPTOR_ACTIVE | STATUS_DESCRIPTOR_WRITABLE, TRUE); + (LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_ACTIVE | STATUS_DESCRIPTOR_WRITABLE, TRUE); break; } case TCPS_CLOSING: { @@ -646,7 +646,7 @@ static void _tcp_setState(TCP* tcp, enum TCPState state) { _tcp_clearRetransmit(tcp, (guint)-1); /* user can no longer use socket */ - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_ACTIVE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_ACTIVE, FALSE); /* * servers have to wait for all children to close. @@ -664,15 +664,15 @@ static void _tcp_setState(TCP* tcp, enum TCPState state) { /* if i was the server's last child and its waiting to close, close it */ if((parent->state == TCPS_CLOSED) && (g_hash_table_size(parent->server->children) <= 0)) { /* this will unbind from the network interface and free socket */ - Descriptor* parentDesc = (Descriptor*)parent; - process_deregisterDescriptor( + LegacyDescriptor* parentDesc = (LegacyDescriptor*)parent; + process_deregisterLegacyDescriptor( descriptor_getOwnerProcess(parentDesc), parentDesc); } } /* this will unbind from the network interface and free socket */ - Descriptor* desc = (Descriptor*)tcp; - process_deregisterDescriptor( + LegacyDescriptor* desc = (LegacyDescriptor*)tcp; + process_deregisterLegacyDescriptor( descriptor_getOwnerProcess(desc), desc); } break; @@ -747,7 +747,7 @@ static void _tcp_bufferPacketOut(TCP* tcp, Packet* packet) { /* the packet takes up more space */ tcp->throttledOutputLength += packet_getPayloadLength(packet); if(_tcp_getBufferSpaceOut(tcp) == 0) { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); } packet_addDeliveryStatus(packet, PDS_SND_TCP_ENQUEUE_THROTTLED); @@ -880,7 +880,7 @@ static void _tcp_addRetransmit(TCP* tcp, Packet* packet) { tcp->retransmit.queueLength += packet_getPayloadLength(packet); if(_tcp_getBufferSpaceOut(tcp) == 0) { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); } } } @@ -905,7 +905,7 @@ static void _tcp_clearRetransmit(TCP* tcp, guint sequence) { } if(_tcp_getBufferSpaceOut(tcp) > 0) { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, TRUE); } } @@ -928,7 +928,7 @@ static void _tcp_clearRetransmitRange(TCP* tcp, guint begin, guint end) { } if(_tcp_getBufferSpaceOut(tcp) > 0) { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, TRUE); } } @@ -1062,7 +1062,7 @@ static void _tcp_retransmitPacket(TCP* tcp, gint sequence) { packet_addDeliveryStatus(packet, PDS_SND_TCP_DEQUEUE_RETRANSMIT); if(_tcp_getBufferSpaceOut(tcp) > 0) { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, TRUE); } /* reset retransmit timer since we are resending it now */ @@ -1251,7 +1251,7 @@ static void _tcp_flush(TCP* tcp) { /* update the tracker input/output buffer stats */ Tracker* tracker = host_getTracker(worker_getActiveHost()); Socket* socket = (Socket* )tcp; - Descriptor* descriptor = (Descriptor *)socket; + LegacyDescriptor* descriptor = (LegacyDescriptor *)socket; gsize inSize = socket_getInputBufferSize(&(tcp->super)); gsize outSize = socket_getOutputBufferSize(&(tcp->super)); tracker_updateSocketInputBuffer(tracker, descriptor->handle, inSize - _tcp_getBufferSpaceIn(tcp), inSize); @@ -1275,18 +1275,18 @@ static void _tcp_flush(TCP* tcp) { if((tcp->receive.next >= tcp->receive.end) && !(tcp->flags & TCPF_EOF_RD_SIGNALED)) { /* user needs to read a 0 so it knows we closed */ tcp->error |= TCPE_RECEIVE_EOF; - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_READABLE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_READABLE, TRUE); } } if((tcp->error & TCPE_CONNECTION_RESET) && (tcp->flags & TCPF_RESET_SIGNALED)) { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); } else if((tcp->error & TCPE_SEND_EOF) && (tcp->flags & TCPF_EOF_WR_SIGNALED)) { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); } else if(_tcp_getBufferSpaceOut(tcp) <= 0) { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, FALSE); } else { - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, TRUE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_WRITABLE, TRUE); } } @@ -1346,7 +1346,7 @@ static void _tcp_runRetransmitTimerExpiredTask(TCP* tcp, gpointer userData) { } static gboolean _tcp_isFamilySupported(Socket* socket, sa_family_t family) { - TCP* tcp = _tcp_fromDescriptor((Descriptor*)socket); + TCP* tcp = _tcp_fromLegacyDescriptor((LegacyDescriptor*)socket); MAGIC_ASSERT(tcp); return family == AF_INET || family == AF_UNIX ? TRUE : FALSE; } @@ -1493,7 +1493,7 @@ void tcp_getInfo(TCP* tcp, struct tcp_info *tcpinfo) { static gint _tcp_connectToPeer(Socket* socket, in_addr_t ip, in_port_t port, sa_family_t family) { - TCP* tcp = _tcp_fromDescriptor((Descriptor*)socket); + TCP* tcp = _tcp_fromLegacyDescriptor((LegacyDescriptor*)socket); MAGIC_ASSERT(tcp); /* Only try to connect if we haven't already started. */ @@ -1677,7 +1677,7 @@ TCPProcessFlags _tcp_dataProcessing(TCP* tcp, Packet* packet, PacketTCPHeader *h } } - Status s = descriptor_getStatus((Descriptor*)tcp); + Status s = descriptor_getStatus((LegacyDescriptor*)tcp); gboolean waitingUserRead = (s & STATUS_DESCRIPTOR_READABLE) ? TRUE : FALSE; if((isNextPacket && !waitingUserRead) || (packetFits)) { @@ -1819,7 +1819,7 @@ static void _tcp_sendACKTaskCallback(TCP* tcp, gpointer userData) { /* return TRUE if the packet should be retransmitted */ static void _tcp_processPacket(Socket* socket, Packet* packet) { - TCP* tcp = _tcp_fromDescriptor((Descriptor*)socket); + TCP* tcp = _tcp_fromLegacyDescriptor((LegacyDescriptor*)socket); MAGIC_ASSERT(tcp); /* fetch the TCP info from the packet */ @@ -1878,9 +1878,9 @@ static void _tcp_processPacket(Socket* socket, Packet* packet) { guint64 sendBufSize = host_getConfiguredSendBufSize(node); TCP* multiplexed = tcp_new(recvBufSize, sendBufSize); - process_registerDescriptor( - descriptor_getOwnerProcess((Descriptor*)tcp), - (Descriptor*)multiplexed); + process_registerLegacyDescriptor( + descriptor_getOwnerProcess((LegacyDescriptor*)tcp), + (LegacyDescriptor*)multiplexed); multiplexed->child = _tcpchild_new(multiplexed, tcp, header->sourceIP, header->sourcePort); utility_assert(g_hash_table_lookup(tcp->server->children, &(multiplexed->child->key)) == NULL); @@ -2165,7 +2165,7 @@ static void _tcp_processPacket(Socket* socket, Packet* packet) { } static void _tcp_dropPacket(Socket* socket, Packet* packet) { - TCP* tcp = _tcp_fromDescriptor((Descriptor*)socket); + TCP* tcp = _tcp_fromLegacyDescriptor((LegacyDescriptor*)socket); MAGIC_ASSERT(tcp); /* if we run a server, the packet could be for an existing child */ @@ -2192,7 +2192,7 @@ static void _tcp_endOfFileSignalled(TCP* tcp, enum TCPFlags flags) { static gssize _tcp_sendUserData(Transport* transport, gconstpointer buffer, gsize nBytes, in_addr_t ip, in_port_t port) { - TCP* tcp = _tcp_fromDescriptor((Descriptor*)transport); + TCP* tcp = _tcp_fromLegacyDescriptor((LegacyDescriptor*)transport); MAGIC_ASSERT(tcp); /* return 0 to signal close, if necessary */ @@ -2260,7 +2260,7 @@ static void _tcp_sendWindowUpdate(TCP* tcp, gpointer data) { static gssize _tcp_receiveUserData(Transport* transport, gpointer buffer, gsize nBytes, in_addr_t* ip, in_port_t* port) { - TCP* tcp = _tcp_fromDescriptor((Descriptor*)transport); + TCP* tcp = _tcp_fromLegacyDescriptor((LegacyDescriptor*)transport); MAGIC_ASSERT(tcp); /* @@ -2417,8 +2417,8 @@ static gssize _tcp_receiveUserData(Transport* transport, gpointer buffer, return totalCopied; } -static void _tcp_free(Descriptor* descriptor) { - TCP* tcp = _tcp_fromDescriptor(descriptor); +static void _tcp_free(LegacyDescriptor* descriptor) { + TCP* tcp = _tcp_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(tcp); priorityqueue_free(tcp->throttledOutput); @@ -2446,15 +2446,15 @@ static void _tcp_free(Descriptor* descriptor) { tcp->cong.hooks->tcp_cong_delete(tcp); retransmit_tally_destroy(tcp->retransmit.tally); - descriptor_clear((Descriptor*)tcp); + descriptor_clear((LegacyDescriptor*)tcp); MAGIC_CLEAR(tcp); g_free(tcp); worker_countObject(OBJECT_TYPE_TCP, COUNTER_TYPE_FREE); } -static gboolean _tcp_close(Descriptor* descriptor) { - TCP* tcp = _tcp_fromDescriptor(descriptor); +static gboolean _tcp_close(LegacyDescriptor* descriptor) { + TCP* tcp = _tcp_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(tcp); /* We always return FALSE because we handle process deregististration @@ -2465,7 +2465,7 @@ static gboolean _tcp_close(Descriptor* descriptor) { tcp->flags |= TCPF_LOCAL_CLOSED_RD; /* the user closed the connection, so should never interact with the socket again */ - descriptor_adjustStatus((Descriptor*)tcp, STATUS_DESCRIPTOR_ACTIVE, FALSE); + descriptor_adjustStatus((LegacyDescriptor*)tcp, STATUS_DESCRIPTOR_ACTIVE, FALSE); switch (tcp->state) { case TCPS_LISTEN: diff --git a/src/main/host/descriptor/tcp_cong_reno.c b/src/main/host/descriptor/tcp_cong_reno.c index b75571b4d3..808790ff8f 100644 --- a/src/main/host/descriptor/tcp_cong_reno.c +++ b/src/main/host/descriptor/tcp_cong_reno.c @@ -41,7 +41,7 @@ static inline void transition_to_cong_avoid(TCP *tcp, CAReno *reno, guint32 n) { reno->cong_avoid_nacked = 0; reno->state_hooks = cong_avoid_hooks_(); reno->state_hooks->tcp_cong_new_ack_ev(tcp, n); - info("[CONG] fd %i transition_to_cong_avoid", ((Descriptor*)tcp)->handle); + info("[CONG] fd %i transition_to_cong_avoid", ((LegacyDescriptor*)tcp)->handle); } /* SLOW START *******************************************************/ @@ -53,7 +53,7 @@ static void ca_reno_slow_start_duplicate_ack_ev_(TCP *tcp) { if (reno->duplicate_ack_n == 3) { // transition to fast recovery debug("[CONG-AVOID] three duplicate acks"); - info("[CONG] fd %i three duplicate acks transition_to_fast_recovery", ((Descriptor*)tcp)->handle); + info("[CONG] fd %i three duplicate acks transition_to_fast_recovery", ((LegacyDescriptor*)tcp)->handle); ssthresh_halve(tcp, reno); tcp_cong(tcp)->cwnd = reno->ssthresh + 3; @@ -157,7 +157,7 @@ static void tcp_cong_reno_timeout_ev_(TCP *tcp) { // transition to slow start reno->state_hooks = slow_start_hooks_(); - info("[CONG] fd %i transition_to_slow_start", ((Descriptor*)tcp)->handle); + info("[CONG] fd %i transition_to_slow_start", ((LegacyDescriptor*)tcp)->handle); } static guint32 tcp_cong_reno_ssthresh_(TCP *tcp) { diff --git a/src/main/host/descriptor/timer.c b/src/main/host/descriptor/timer.c index 7ee2868e98..63dfc73f5e 100644 --- a/src/main/host/descriptor/timer.c +++ b/src/main/host/descriptor/timer.c @@ -22,7 +22,7 @@ #include "support/logger/logger.h" struct _Timer { - Descriptor super; + LegacyDescriptor super; /* the absolute time the timer will next expire */ SimulationTime nextExpireTime; @@ -42,13 +42,13 @@ struct _Timer { MAGIC_DECLARE; }; -static Timer* _timer_fromDescriptor(Descriptor* descriptor) { +static Timer* _timer_fromLegacyDescriptor(LegacyDescriptor* descriptor) { utility_assert(descriptor_getType(descriptor) == DT_TIMER); return (Timer*)descriptor; } -static gboolean _timer_close(Descriptor* descriptor) { - Timer* timer = _timer_fromDescriptor(descriptor); +static gboolean _timer_close(LegacyDescriptor* descriptor) { + Timer* timer = _timer_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(timer); debug("timer fd %i closing now", timer->super.handle); timer->isClosed = TRUE; @@ -60,10 +60,10 @@ static gboolean _timer_close(Descriptor* descriptor) { } } -static void _timer_free(Descriptor* descriptor) { - Timer* timer = _timer_fromDescriptor(descriptor); +static void _timer_free(LegacyDescriptor* descriptor) { + Timer* timer = _timer_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(timer); - descriptor_clear((Descriptor*)timer); + descriptor_clear((LegacyDescriptor*)timer); MAGIC_CLEAR(timer); g_free(timer); worker_countObject(OBJECT_TYPE_TIMER, COUNTER_TYPE_FREE); diff --git a/src/main/host/descriptor/transport.c b/src/main/host/descriptor/transport.c index 6960b0acb4..e082adb2cc 100644 --- a/src/main/host/descriptor/transport.c +++ b/src/main/host/descriptor/transport.c @@ -12,7 +12,7 @@ #include "main/host/descriptor/transport.h" #include "main/utility/utility.h" -static Transport* _transport_fromDescriptor(Descriptor* descriptor) { +static Transport* _transport_fromLegacyDescriptor(LegacyDescriptor* descriptor) { utility_assert(descriptor_getType(descriptor) == DT_TCPSOCKET || descriptor_getType(descriptor) == DT_UDPSOCKET || descriptor_getType(descriptor) == DT_UNIXSOCKET || @@ -20,8 +20,8 @@ static Transport* _transport_fromDescriptor(Descriptor* descriptor) { return (Transport*)descriptor; } -static void _transport_free(Descriptor* descriptor) { - Transport* transport = _transport_fromDescriptor(descriptor); +static void _transport_free(LegacyDescriptor* descriptor) { + Transport* transport = _transport_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(transport); MAGIC_ASSERT(transport->vtable); @@ -32,8 +32,8 @@ static void _transport_free(Descriptor* descriptor) { transport->vtable->free(descriptor); } -static gboolean _transport_close(Descriptor* descriptor) { - Transport* transport = _transport_fromDescriptor(descriptor); +static gboolean _transport_close(LegacyDescriptor* descriptor) { + Transport* transport = _transport_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(transport); MAGIC_ASSERT(transport->vtable); return transport->vtable->close(descriptor); @@ -43,7 +43,7 @@ DescriptorFunctionTable transport_functions = { _transport_close, _transport_free, MAGIC_VALUE}; void transport_init(Transport* transport, TransportFunctionTable* vtable, - DescriptorType type) { + LegacyDescriptorType type) { utility_assert(transport && vtable); descriptor_init(&(transport->super), type, &transport_functions); diff --git a/src/main/host/descriptor/transport.h b/src/main/host/descriptor/transport.h index 17c7eb32b8..8e11993207 100644 --- a/src/main/host/descriptor/transport.h +++ b/src/main/host/descriptor/transport.h @@ -29,14 +29,14 @@ struct _TransportFunctionTable { }; struct _Transport { - Descriptor super; + LegacyDescriptor super; TransportFunctionTable* vtable; MAGIC_DECLARE; }; void transport_init(Transport* transport, TransportFunctionTable* vtable, - DescriptorType type); + LegacyDescriptorType type); gssize transport_sendUserData(Transport* transport, gconstpointer buffer, gsize nBytes, in_addr_t ip, in_port_t port); diff --git a/src/main/host/descriptor/udp.c b/src/main/host/descriptor/udp.c index 13df32c68c..68b17fd697 100644 --- a/src/main/host/descriptor/udp.c +++ b/src/main/host/descriptor/udp.c @@ -54,20 +54,20 @@ static void _udp_setState(UDP* udp, enum UDPState state) { _udp_stateToAscii(udp->stateLast), _udp_stateToAscii(udp->state)); } -static UDP* _udp_fromDescriptor(Descriptor* descriptor) { +static UDP* _udp_fromLegacyDescriptor(LegacyDescriptor* descriptor) { utility_assert(descriptor_getType(descriptor) == DT_UDPSOCKET); return (UDP*)descriptor; } static gboolean _udp_isFamilySupported(Socket* socket, sa_family_t family) { - UDP* udp = _udp_fromDescriptor((Descriptor*)socket); + UDP* udp = _udp_fromLegacyDescriptor((LegacyDescriptor*)socket); MAGIC_ASSERT(udp); return (family == AF_INET || family == AF_UNSPEC || family == AF_UNIX) ? TRUE : FALSE; } static gint _udp_connectToPeer(Socket* socket, in_addr_t ip, in_port_t port, sa_family_t family) { - UDP* udp = _udp_fromDescriptor((Descriptor*)socket); + UDP* udp = _udp_fromLegacyDescriptor((LegacyDescriptor*)socket); MAGIC_ASSERT(udp); @@ -86,7 +86,7 @@ static gint _udp_connectToPeer(Socket* socket, in_addr_t ip, in_port_t port, } static void _udp_processPacket(Socket* socket, Packet* packet) { - UDP* udp = _udp_fromDescriptor((Descriptor*)socket); + UDP* udp = _udp_fromLegacyDescriptor((LegacyDescriptor*)socket); MAGIC_ASSERT(udp); /* UDP packet can be buffered immediately */ @@ -96,7 +96,7 @@ static void _udp_processPacket(Socket* socket, Packet* packet) { } static void _udp_dropPacket(Socket* socket, Packet* packet) { - UDP* udp = _udp_fromDescriptor((Descriptor*)socket); + UDP* udp = _udp_fromLegacyDescriptor((LegacyDescriptor*)socket); MAGIC_ASSERT(udp); /* do nothing */ @@ -109,7 +109,7 @@ static void _udp_dropPacket(Socket* socket, Packet* packet) { */ static gssize _udp_sendUserData(Transport* transport, gconstpointer buffer, gsize nBytes, in_addr_t ip, in_port_t port) { - UDP* udp = _udp_fromDescriptor((Descriptor*)transport); + UDP* udp = _udp_fromLegacyDescriptor((LegacyDescriptor*)transport); MAGIC_ASSERT(udp); const gsize maxPacketLength = CONFIG_DATAGRAM_MAX_SIZE; @@ -173,7 +173,7 @@ static gssize _udp_sendUserData(Transport* transport, gconstpointer buffer, static gssize _udp_receiveUserData(Transport* transport, gpointer buffer, gsize nBytes, in_addr_t* ip, in_port_t* port) { - UDP* udp = _udp_fromDescriptor((Descriptor*)transport); + UDP* udp = _udp_fromLegacyDescriptor((LegacyDescriptor*)transport); MAGIC_ASSERT(udp); if (socket_peekNextInPacket(&(udp->super)) == NULL) { @@ -213,8 +213,8 @@ static gssize _udp_receiveUserData(Transport* transport, gpointer buffer, return bytesCopied; } -static void _udp_free(Descriptor* descriptor) { - UDP* udp = _udp_fromDescriptor(descriptor); +static void _udp_free(LegacyDescriptor* descriptor) { + UDP* udp = _udp_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(udp); descriptor_clear(descriptor); @@ -224,8 +224,8 @@ static void _udp_free(Descriptor* descriptor) { worker_countObject(OBJECT_TYPE_UDP, COUNTER_TYPE_FREE); } -static gboolean _udp_close(Descriptor* descriptor) { - UDP* udp = _udp_fromDescriptor(descriptor); +static gboolean _udp_close(LegacyDescriptor* descriptor) { + UDP* udp = _udp_fromLegacyDescriptor(descriptor); MAGIC_ASSERT(udp); /* Deregister us from the process upon return. */ _udp_setState(udp, UDPS_CLOSED); @@ -260,7 +260,7 @@ UDP* udp_new(guint receiveBufferSize, guint sendBufferSize) { /* we are immediately active because UDP doesnt wait for accept or connect */ descriptor_adjustStatus( - (Descriptor*)udp, STATUS_DESCRIPTOR_ACTIVE | STATUS_DESCRIPTOR_WRITABLE, TRUE); + (LegacyDescriptor*)udp, STATUS_DESCRIPTOR_ACTIVE | STATUS_DESCRIPTOR_WRITABLE, TRUE); worker_countObject(OBJECT_TYPE_UDP, COUNTER_TYPE_NEW); diff --git a/src/main/host/network_interface.c b/src/main/host/network_interface.c index 44a8a6b864..0e02879d59 100644 --- a/src/main/host/network_interface.c +++ b/src/main/host/network_interface.c @@ -405,7 +405,7 @@ static void _networkinterface_receivePacket(NetworkInterface* interface, Packet* /* if the socket closed, just drop the packet */ gint socketHandle = -1; if(socket) { - socketHandle = *descriptor_getHandleReference((Descriptor*)socket); + socketHandle = *descriptor_getHandleReference((LegacyDescriptor*)socket); socket_pushInPacket(socket, packet); } else { packet_addDeliveryStatus(packet, PDS_RCV_INTERFACE_DROPPED); @@ -454,8 +454,8 @@ void networkinterface_receivePackets(NetworkInterface* interface) { } } -static void _networkinterface_updatePacketHeader(Descriptor* descriptor, Packet* packet) { - DescriptorType type = descriptor_getType(descriptor); +static void _networkinterface_updatePacketHeader(LegacyDescriptor* descriptor, Packet* packet) { + LegacyDescriptorType type = descriptor_getType(descriptor); if(type == DT_TCPSOCKET) { TCP* tcp = (TCP*)descriptor; tcp_networkInterfaceIsAboutToSendPacket(tcp, packet); @@ -470,10 +470,10 @@ static Packet* _networkinterface_selectRoundRobin(NetworkInterface* interface, g /* do round robin to get the next packet from the next socket */ Socket* socket = g_queue_pop_head(interface->rrQueue); packet = socket_pullOutPacket(socket); - *socketHandle = *descriptor_getHandleReference((Descriptor*)socket); + *socketHandle = *descriptor_getHandleReference((LegacyDescriptor*)socket); if(socket && packet) { - _networkinterface_updatePacketHeader((Descriptor*)socket, packet); + _networkinterface_updatePacketHeader((LegacyDescriptor*)socket, packet); } if(socket_peekNextOutPacket(socket)) { @@ -481,7 +481,7 @@ static Packet* _networkinterface_selectRoundRobin(NetworkInterface* interface, g g_queue_push_tail(interface->rrQueue, socket); } else { /* socket has no more packets, unref it from the sendable queue */ - descriptor_unref((Descriptor*) socket); + descriptor_unref((LegacyDescriptor*) socket); } } @@ -498,10 +498,10 @@ static Packet* _networkinterface_selectFirstInFirstOut(NetworkInterface* interfa /* do fifo to get the next packet from the next socket */ Socket* socket = priorityqueue_pop(interface->fifoQueue); packet = socket_pullOutPacket(socket); - *socketHandle = *descriptor_getHandleReference((Descriptor*)socket); + *socketHandle = *descriptor_getHandleReference((LegacyDescriptor*)socket); if(socket && packet) { - _networkinterface_updatePacketHeader((Descriptor*)socket, packet); + _networkinterface_updatePacketHeader((LegacyDescriptor*)socket, packet); } if(socket_peekNextOutPacket(socket)) { @@ -509,7 +509,7 @@ static Packet* _networkinterface_selectFirstInFirstOut(NetworkInterface* interfa priorityqueue_push(interface->fifoQueue, socket); } else { /* socket has no more packets, unref it from the sendable queue */ - descriptor_unref((Descriptor*) socket); + descriptor_unref((LegacyDescriptor*) socket); } } diff --git a/src/main/host/process.c b/src/main/host/process.c index dbcbb2ecad..cd13bee763 100644 --- a/src/main/host/process.c +++ b/src/main/host/process.c @@ -292,23 +292,23 @@ static void _process_openStdIOFileHelper(Process* proc, bool isStdOut) { if (errcode < 0) { error("Opening %s: %s", fileName, strerror(-errcode)); /* Unref and free the file object. */ - descriptor_close((Descriptor*)stdfile); + descriptor_close((LegacyDescriptor*)stdfile); } else { debug("Successfully opened %s file at %s", isStdOut ? "stdout" : "stderr", fileName); if (isStdOut) { descriptortable_set( - proc->descTable, STDOUT_FILENO, (Descriptor*)stdfile); + proc->descTable, STDOUT_FILENO, (LegacyDescriptor*)stdfile); proc->stdoutFile = stdfile; } else { descriptortable_set( - proc->descTable, STDERR_FILENO, (Descriptor*)stdfile); + proc->descTable, STDERR_FILENO, (LegacyDescriptor*)stdfile); proc->stderrFile = stdfile; } /* Ref once since both the proc class and the table are storing it. */ - descriptor_ref((Descriptor*)stdfile); + descriptor_ref((LegacyDescriptor*)stdfile); } g_free(fileName); @@ -597,12 +597,12 @@ static void _process_free(Process* proc) { * Closing the descriptors will remove them from the table and the table * will release it's ref. We also need to release our proc ref. */ if (proc->stderrFile) { - descriptor_close((Descriptor*)proc->stderrFile); - descriptor_unref((Descriptor*)proc->stderrFile); + descriptor_close((LegacyDescriptor*)proc->stderrFile); + descriptor_unref((LegacyDescriptor*)proc->stderrFile); } if (proc->stdoutFile) { - descriptor_close((Descriptor*)proc->stdoutFile); - descriptor_unref((Descriptor*)proc->stdoutFile); + descriptor_close((LegacyDescriptor*)proc->stdoutFile); + descriptor_unref((LegacyDescriptor*)proc->stdoutFile); } /* Now free all remaining descriptors stored in our table. */ @@ -729,18 +729,18 @@ void process_flushPtrs(Process* proc, Thread* thread) { // Handler the descriptors owned by this process // ****************************************************** -int process_registerDescriptor(Process* proc, Descriptor* desc) { +int process_registerLegacyDescriptor(Process* proc, LegacyDescriptor* desc) { MAGIC_ASSERT(proc); utility_assert(desc); descriptor_setOwnerProcess(desc, proc); return descriptortable_add(proc->descTable, desc); } -void process_deregisterDescriptor(Process* proc, Descriptor* desc) { +void process_deregisterLegacyDescriptor(Process* proc, LegacyDescriptor* desc) { MAGIC_ASSERT(proc); if (desc) { - DescriptorType dType = descriptor_getType(desc); + LegacyDescriptorType dType = descriptor_getType(desc); if (dType == DT_TCPSOCKET || dType == DT_UDPSOCKET) { host_disassociateInterface(proc->host, (Socket*)desc); } @@ -749,7 +749,7 @@ void process_deregisterDescriptor(Process* proc, Descriptor* desc) { } } -Descriptor* process_getRegisteredDescriptor(Process* proc, int handle) { +LegacyDescriptor* process_getRegisteredLegacyDescriptor(Process* proc, int handle) { MAGIC_ASSERT(proc); return descriptortable_get(proc->descTable, handle); } diff --git a/src/main/host/process.h b/src/main/host/process.h index 36a815c207..ddc7b21813 100644 --- a/src/main/host/process.h +++ b/src/main/host/process.h @@ -71,9 +71,9 @@ const gchar* process_getPluginName(Process* proc); /* Returns the processID that was assigned to us in process_new */ guint process_getProcessID(Process* proc); -int process_registerDescriptor(Process* proc, Descriptor* desc); -void process_deregisterDescriptor(Process* proc, Descriptor* desc); -Descriptor* process_getRegisteredDescriptor(Process* proc, int handle); +int process_registerLegacyDescriptor(Process* proc, LegacyDescriptor* desc); +void process_deregisterLegacyDescriptor(Process* proc, LegacyDescriptor* desc); +LegacyDescriptor* process_getRegisteredLegacyDescriptor(Process* proc, int handle); // Convert a virtual ptr in the plugin address space to a globally unique physical ptr PluginPhysicalPtr process_getPhysicalAddress(Process* proc, PluginVirtualPtr vPtr); diff --git a/src/main/host/syscall/epoll.c b/src/main/host/syscall/epoll.c index 2a6d3567a8..fd48d482b7 100644 --- a/src/main/host/syscall/epoll.c +++ b/src/main/host/syscall/epoll.c @@ -28,10 +28,10 @@ static int _syscallhandler_createEpollHelper(SysCallHandler* sys, int64_t size, } Epoll* epolld = epoll_new(); - int handle = process_registerDescriptor(sys->process, (Descriptor*)epolld); + int handle = process_registerLegacyDescriptor(sys->process, (LegacyDescriptor*)epolld); if (flags & EPOLL_CLOEXEC) { - descriptor_addFlags((Descriptor*)epolld, EPOLL_CLOEXEC); + descriptor_addFlags((LegacyDescriptor*)epolld, EPOLL_CLOEXEC); } return handle; @@ -80,8 +80,8 @@ SysCallReturn syscallhandler_epoll_ctl(SysCallHandler* sys, } /* Get and check the epoll descriptor. */ - Descriptor* descriptor = - process_getRegisteredDescriptor(sys->process, epfd); + LegacyDescriptor* descriptor = + process_getRegisteredLegacyDescriptor(sys->process, epfd); gint errorCode = _syscallhandler_validateDescriptor(descriptor, DT_EPOLL); if (errorCode) { @@ -95,7 +95,7 @@ SysCallReturn syscallhandler_epoll_ctl(SysCallHandler* sys, utility_assert(epoll); /* Find the child descriptor that the epoll is monitoring. */ - descriptor = process_getRegisteredDescriptor(sys->process, fd); + descriptor = process_getRegisteredLegacyDescriptor(sys->process, fd); errorCode = _syscallhandler_validateDescriptor(descriptor, DT_NONE); if (errorCode) { @@ -135,7 +135,7 @@ SysCallReturn syscallhandler_epoll_wait(SysCallHandler* sys, } /* Get and check the epoll descriptor. */ - Descriptor* desc = process_getRegisteredDescriptor(sys->process, epfd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, epfd); gint errorCode = _syscallhandler_validateDescriptor(desc, DT_EPOLL); if (errorCode) { @@ -177,7 +177,7 @@ SysCallReturn syscallhandler_epoll_wait(SysCallHandler* sys, /* Block on epoll status. An epoll descriptor is readable when it * has events. We either use our timer as a timeout, or no timeout. */ Trigger trigger = (Trigger){.type = TRIGGER_DESCRIPTOR, - .object = (Descriptor*)epoll, + .object = (LegacyDescriptor*)epoll, .status = STATUS_DESCRIPTOR_READABLE}; return (SysCallReturn){ diff --git a/src/main/host/syscall/eventfd.c b/src/main/host/syscall/eventfd.c index 03480bfe9f..c974497bb3 100644 --- a/src/main/host/syscall/eventfd.c +++ b/src/main/host/syscall/eventfd.c @@ -29,7 +29,7 @@ static int _syscallhandler_validateEventFDHelper(SysCallHandler* sys, int efd, } /* Check if this is a virtual Shadow descriptor. */ - Descriptor* desc = process_getRegisteredDescriptor(sys->process, efd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, efd); if (desc && event_desc_out) { *event_desc_out = (EventD*)desc; } @@ -56,7 +56,7 @@ static SysCallReturn _syscallhandler_eventfdHelper(SysCallHandler* sys, unsigned /* Create the eventd object and double check that it's valid. */ EventD* eventd = eventd_new(initval, flags & EFD_SEMAPHORE ? 1 : 0); - int efd = process_registerDescriptor(sys->process, (Descriptor*)eventd); + int efd = process_registerLegacyDescriptor(sys->process, (LegacyDescriptor*)eventd); #ifdef DEBUG /* This should always be a valid descriptor. */ @@ -69,10 +69,10 @@ static SysCallReturn _syscallhandler_eventfdHelper(SysCallHandler* sys, unsigned /* Set any options that were given. */ if (flags & EFD_NONBLOCK) { - descriptor_addFlags((Descriptor*)eventd, O_NONBLOCK); + descriptor_addFlags((LegacyDescriptor*)eventd, O_NONBLOCK); } if (flags & EFD_CLOEXEC) { - descriptor_addFlags((Descriptor*)eventd, O_CLOEXEC); + descriptor_addFlags((LegacyDescriptor*)eventd, O_CLOEXEC); } debug("eventfd() returning fd %i", efd); diff --git a/src/main/host/syscall/fcntl.c b/src/main/host/syscall/fcntl.c index f0b0325ba6..4342d567ca 100644 --- a/src/main/host/syscall/fcntl.c +++ b/src/main/host/syscall/fcntl.c @@ -176,7 +176,7 @@ SysCallReturn syscallhandler_fcntl(SysCallHandler* sys, debug("fcntl called on fd %d for command %lu", fd, command); - Descriptor* desc = process_getRegisteredDescriptor(sys->process, fd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, fd); int errcode = _syscallhandler_validateDescriptor(desc, DT_NONE); if (errcode < 0) { return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = errcode}; diff --git a/src/main/host/syscall/file.c b/src/main/host/syscall/file.c index 05efd54a5d..e42586e2a3 100644 --- a/src/main/host/syscall/file.c +++ b/src/main/host/syscall/file.c @@ -31,7 +31,7 @@ static int _syscallhandler_validateFileHelper(SysCallHandler* sys, int filefd, } /* Check if this is a virtual Shadow descriptor. */ - Descriptor* desc = process_getRegisteredDescriptor(sys->process, filefd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, filefd); if (desc && file_desc_out) { *file_desc_out = (File*)desc; } @@ -66,13 +66,13 @@ static SysCallReturn _syscallhandler_openHelper(SysCallHandler* sys, /* Create the new descriptor for this file. */ File* filed = file_new(); - int handle = process_registerDescriptor(sys->process, (Descriptor*)filed); + int handle = process_registerLegacyDescriptor(sys->process, (LegacyDescriptor*)filed); /* Now open the file. */ errcode = file_open(filed, pathname, flags, mode); if (errcode < 0) { /* This will remove the descriptor entry and unref/free the File. */ - descriptor_close((Descriptor*)filed); + descriptor_close((LegacyDescriptor*)filed); } else { utility_assert(errcode == handle); } diff --git a/src/main/host/syscall/fileat.c b/src/main/host/syscall/fileat.c index 6620180b9a..bd361f72b2 100644 --- a/src/main/host/syscall/fileat.c +++ b/src/main/host/syscall/fileat.c @@ -40,7 +40,7 @@ static int _syscallhandler_validateDirHelper(SysCallHandler* sys, int dirfd, } /* Check if this is a virtual Shadow descriptor. */ - Descriptor* desc = process_getRegisteredDescriptor(sys->process, dirfd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, dirfd); if (desc && dir_desc_out) { *dir_desc_out = (File*)desc; } @@ -131,13 +131,13 @@ SysCallReturn syscallhandler_openat(SysCallHandler* sys, /* Create the new descriptor for this file. */ File* file_desc = file_new(); int handle = - process_registerDescriptor(sys->process, (Descriptor*)file_desc); + process_registerLegacyDescriptor(sys->process, (LegacyDescriptor*)file_desc); /* Now open the file. */ errcode = file_openat(file_desc, dir_desc, pathname, flags, mode); if (errcode < 0) { /* This will remove the descriptor entry and unref/free the File. */ - descriptor_close((Descriptor*)file_desc); + descriptor_close((LegacyDescriptor*)file_desc); } else { utility_assert(errcode == handle); } diff --git a/src/main/host/syscall/ioctl.c b/src/main/host/syscall/ioctl.c index 41c51188f1..06558e120a 100644 --- a/src/main/host/syscall/ioctl.c +++ b/src/main/host/syscall/ioctl.c @@ -51,7 +51,7 @@ SysCallReturn syscallhandler_ioctl(SysCallHandler* sys, debug("ioctl called on fd %d for request %ld", fd, request); - Descriptor* desc = process_getRegisteredDescriptor(sys->process, fd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, fd); int errcode = _syscallhandler_validateDescriptor(desc, DT_NONE); if (errcode < 0) { return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = errcode}; @@ -60,7 +60,7 @@ SysCallReturn syscallhandler_ioctl(SysCallHandler* sys, bool isInbufLenRequest = request == SIOCINQ || request == FIONREAD; bool isOutbufLenRequest = request == SIOCOUTQ || request == TIOCOUTQ; - DescriptorType dtype = descriptor_getType(desc); + LegacyDescriptorType dtype = descriptor_getType(desc); int result = 0; if (dtype == DT_FILE) { diff --git a/src/main/host/syscall/mman.c b/src/main/host/syscall/mman.c index f67c9959f2..e4161d5769 100644 --- a/src/main/host/syscall/mman.c +++ b/src/main/host/syscall/mman.c @@ -49,7 +49,7 @@ static int _syscallhandler_validateMmapArgsHelper(SysCallHandler* sys, int fd, /* We only need a file if it's not an anonymous mapping. */ if (!(flags & MAP_ANONYMOUS)) { - Descriptor* desc = process_getRegisteredDescriptor(sys->process, fd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, fd); int errcode = _syscallhandler_validateDescriptor(desc, DT_NONE); if (errcode) { info("Invalid fd %i", fd); @@ -73,7 +73,7 @@ static int _syscallhandler_validateMmapArgsHelper(SysCallHandler* sys, int fd, static int _syscallhandler_openPluginFile(SysCallHandler* sys, File* file) { utility_assert(file); - int fd = descriptor_getHandle((Descriptor*)file); + int fd = descriptor_getHandle((LegacyDescriptor*)file); debug("Trying to open file %i in the plugin", fd); diff --git a/src/main/host/syscall/protected.c b/src/main/host/syscall/protected.c index 467fb20031..30386e0d1f 100644 --- a/src/main/host/syscall/protected.c +++ b/src/main/host/syscall/protected.c @@ -64,8 +64,8 @@ int _syscallhandler_wasBlocked(const SysCallHandler* sys) { return sys->blockedSyscallNR >= 0; } -int _syscallhandler_validateDescriptor(Descriptor* descriptor, - DescriptorType expectedType) { +int _syscallhandler_validateDescriptor(LegacyDescriptor* descriptor, + LegacyDescriptorType expectedType) { if (descriptor) { Status status = descriptor_getStatus(descriptor); @@ -75,7 +75,7 @@ int _syscallhandler_validateDescriptor(Descriptor* descriptor, return -EBADF; } - DescriptorType type = descriptor_getType(descriptor); + LegacyDescriptorType type = descriptor_getType(descriptor); if (expectedType != DT_NONE && type != expectedType) { warning("descriptor handle '%i' is of type %i, expected type %i", diff --git a/src/main/host/syscall/protected.h b/src/main/host/syscall/protected.h index 875286efce..9363435e7a 100644 --- a/src/main/host/syscall/protected.h +++ b/src/main/host/syscall/protected.h @@ -76,7 +76,7 @@ void _syscallhandler_setListenTimeoutMillis(SysCallHandler* sys, int _syscallhandler_isListenTimeoutPending(SysCallHandler* sys); int _syscallhandler_didListenTimeoutExpire(const SysCallHandler* sys); int _syscallhandler_wasBlocked(const SysCallHandler* sys); -int _syscallhandler_validateDescriptor(Descriptor* descriptor, - DescriptorType expectedType); +int _syscallhandler_validateDescriptor(LegacyDescriptor* descriptor, + LegacyDescriptorType expectedType); #endif /* SRC_MAIN_HOST_SYSCALL_PROTECTED_H_ */ diff --git a/src/main/host/syscall/socket.c b/src/main/host/syscall/socket.c index d6b9ec6726..8ff1e30833 100644 --- a/src/main/host/syscall/socket.c +++ b/src/main/host/syscall/socket.c @@ -35,7 +35,7 @@ * must be read from the socket). This function checks if the descriptor is * in this corner case and we should be allowed to read from it. */ static bool _syscallhandler_readableWhenClosed(SysCallHandler* sys, - Descriptor* desc) { + LegacyDescriptor* desc) { if (desc && descriptor_getType(desc) == DT_TCPSOCKET && (descriptor_getStatus(desc) & STATUS_DESCRIPTOR_CLOSED)) { /* Connection error will be -ENOTCONN when reading is done. */ @@ -55,7 +55,7 @@ static int _syscallhandler_validateSocketHelper(SysCallHandler* sys, int sockfd, } /* Check if this is a virtual Shadow descriptor. */ - Descriptor* desc = process_getRegisteredDescriptor(sys->process, sockfd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, sockfd); if (desc && sock_desc_out) { *sock_desc_out = (Socket*)desc; } @@ -66,7 +66,7 @@ static int _syscallhandler_validateSocketHelper(SysCallHandler* sys, int sockfd, return errcode; } - DescriptorType type = descriptor_getType(desc); + LegacyDescriptorType type = descriptor_getType(desc); if (type != DT_TCPSOCKET && type != DT_UDPSOCKET && type != DT_UNIXSOCKET) { info("descriptor %i with type %i is not a socket", sockfd, (int)type); return -ENOTSOCK; @@ -89,7 +89,7 @@ static int _syscallhandler_validateTCPSocketHelper(SysCallHandler* sys, return errcode; } - DescriptorType type = descriptor_getType((Descriptor*)sock_desc); + LegacyDescriptorType type = descriptor_getType((LegacyDescriptor*)sock_desc); if (type != DT_TCPSOCKET) { info("descriptor %i is not a TCP socket", sockfd); return -EOPNOTSUPP; @@ -112,7 +112,7 @@ static int _syscallhandler_validateUDPSocketHelper(SysCallHandler* sys, return errcode; } - DescriptorType type = descriptor_getType((Descriptor*)sock_desc); + LegacyDescriptorType type = descriptor_getType((LegacyDescriptor*)sock_desc); if (type != DT_UDPSOCKET) { info("descriptor %i is not a UDP socket", sockfd); return -EOPNOTSUPP; @@ -189,7 +189,7 @@ static SysCallReturn _syscallhandler_acceptHelper(SysCallHandler* sys, errcode = tcp_acceptServerPeer( tcp_desc, &inet_addr.sin_addr.s_addr, &inet_addr.sin_port, &accepted_fd); - Descriptor* desc = (Descriptor*)tcp_desc; + LegacyDescriptor* desc = (LegacyDescriptor*)tcp_desc; if (errcode == -EWOULDBLOCK && !(descriptor_getFlags(desc) & O_NONBLOCK)) { /* This is a blocking accept, and we don't have a connection yet. * The socket becomes readable when we have a connection to accept. @@ -214,10 +214,10 @@ static SysCallReturn _syscallhandler_acceptHelper(SysCallHandler* sys, /* Set the flags on the accepted socket if requested. */ if (flags & SOCK_NONBLOCK) { - descriptor_addFlags((Descriptor*)accepted_tcp_desc, O_NONBLOCK); + descriptor_addFlags((LegacyDescriptor*)accepted_tcp_desc, O_NONBLOCK); } if (flags & SOCK_CLOEXEC) { - descriptor_addFlags((Descriptor*)accepted_tcp_desc, O_CLOEXEC); + descriptor_addFlags((LegacyDescriptor*)accepted_tcp_desc, O_CLOEXEC); } /* check if they wanted to know where we got the data from */ @@ -237,7 +237,7 @@ static int _syscallhandler_bindHelper(SysCallHandler* sys, Socket* socket_desc, gchar* peerAddrStr = address_ipToNewString(peerAddr); debug("trying to bind to inet address %s:%u on socket %i with peer %s:%u", bindAddrStr, ntohs(port), - descriptor_getHandle((Descriptor*)socket_desc), peerAddrStr, + descriptor_getHandle((LegacyDescriptor*)socket_desc), peerAddrStr, ntohs(peerPort)); g_free(bindAddrStr); g_free(peerAddrStr); @@ -337,7 +337,7 @@ static int _syscallhandler_getSocketOptHelper(SysCallHandler* sys, Socket* sock, } case SO_ERROR: { *optval = 0; - if (descriptor_getType((Descriptor*)sock) == DT_TCPSOCKET) { + if (descriptor_getType((LegacyDescriptor*)sock) == DT_TCPSOCKET) { /* Return error for failed connect() attempts. */ int connerr = tcp_getConnectionError((TCP*)sock); if (connerr == -ECONNRESET || connerr == -ECONNREFUSED) { @@ -369,7 +369,7 @@ static int _syscallhandler_setSocketOptHelper(SysCallHandler* sys, Socket* sock, size_t newsize = (*val) * 2; // Linux kernel doubles this value upon setting socket_setOutputBufferSize(sock, newsize); - if (descriptor_getType((Descriptor*)sock) == DT_TCPSOCKET) { + if (descriptor_getType((LegacyDescriptor*)sock) == DT_TCPSOCKET) { tcp_disableSendBufferAutotuning((TCP*)sock); } return 0; @@ -380,7 +380,7 @@ static int _syscallhandler_setSocketOptHelper(SysCallHandler* sys, Socket* sock, size_t newsize = (*val) * 2; // Linux kernel doubles this value upon setting socket_setInputBufferSize(sock, newsize); - if (descriptor_getType((Descriptor*)sock) == DT_TCPSOCKET) { + if (descriptor_getType((LegacyDescriptor*)sock) == DT_TCPSOCKET) { tcp_disableReceiveBufferAutotuning((TCP*)sock); } return 0; @@ -429,7 +429,7 @@ SysCallReturn _syscallhandler_recvfromHelper(SysCallHandler* sys, int sockfd, int errcode = _syscallhandler_validateSocketHelper(sys, sockfd, &socket_desc); - Descriptor* desc = (Descriptor*)socket_desc; + LegacyDescriptor* desc = (LegacyDescriptor*)socket_desc; if (errcode < 0 && _syscallhandler_readableWhenClosed(sys, desc)) { errcode = 0; } @@ -561,7 +561,7 @@ SysCallReturn _syscallhandler_sendtoHelper(SysCallHandler* sys, int sockfd, dest_port = ((struct sockaddr_in*)dest_addr)->sin_port; } - Descriptor* desc = (Descriptor*)socket_desc; + LegacyDescriptor* desc = (LegacyDescriptor*)socket_desc; errcode = 0; if (descriptor_getType(desc) == DT_UDPSOCKET) { @@ -828,7 +828,7 @@ SysCallReturn syscallhandler_connect(SysCallHandler* sys, /* Now we are ready to connect. */ errcode = socket_connectToPeer(socket_desc, peerAddr, peerPort, family); - Descriptor* desc = (Descriptor*)socket_desc; + LegacyDescriptor* desc = (LegacyDescriptor*)socket_desc; if (descriptor_getType(desc) == DT_TCPSOCKET && !(descriptor_getFlags(desc) & O_NONBLOCK)) { /* This is a blocking connect call. */ @@ -882,7 +882,7 @@ SysCallReturn syscallhandler_getpeername(SysCallHandler* sys, // If we can validate that, we can delete this comment. // /* Only a TCP socket can be connected to a peer. // * TODO: Needs to be updated when we support AF_UNIX. */ - // DescriptorType type = descriptor_getType((Descriptor*)socket_desc); + // LegacyDescriptorType type = descriptor_getType((LegacyDescriptor*)socket_desc); // if(type != DT_TCPSOCKET) { // info("descriptor %i is not a TCP socket", sockfd); // return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = @@ -894,7 +894,7 @@ SysCallReturn syscallhandler_getpeername(SysCallHandler* sys, struct sockaddr saddr = {0}; size_t slen = 0; - if (descriptor_getType((Descriptor*)socket_desc) == DT_UNIXSOCKET) { + if (descriptor_getType((LegacyDescriptor*)socket_desc) == DT_UNIXSOCKET) { // TODO currently handles socketpair, but will need to be extended // in order to support traditional UNIX sockets struct sockaddr_un* unix_addr = (struct sockaddr_un*)&saddr; @@ -939,7 +939,7 @@ SysCallReturn syscallhandler_getsockname(SysCallHandler* sys, struct sockaddr saddr = {0}; size_t slen = 0; - if (descriptor_getType((Descriptor*)socket_desc) == DT_UNIXSOCKET) { + if (descriptor_getType((LegacyDescriptor*)socket_desc) == DT_UNIXSOCKET) { // TODO currently handles socketpair, but will need to be extended // in order to support traditional UNIX sockets struct sockaddr_un* unix_addr = (struct sockaddr_un*)&saddr; @@ -999,7 +999,7 @@ SysCallReturn syscallhandler_getsockopt(SysCallHandler* sys, errcode = 0; switch (level) { case SOL_TCP: { - if (descriptor_getType((Descriptor*)socket_desc) != DT_TCPSOCKET) { + if (descriptor_getType((LegacyDescriptor*)socket_desc) != DT_TCPSOCKET) { errcode = -EINVAL; break; } @@ -1210,7 +1210,7 @@ SysCallReturn syscallhandler_socket(SysCallHandler* sys, /* Now make sure it will be valid when we operate on it. */ int sockfd = - process_registerDescriptor(sys->process, &sock_desc->super.super); + process_registerLegacyDescriptor(sys->process, &sock_desc->super.super); int errcode = _syscallhandler_validateSocketHelper(sys, sockfd, NULL); if (errcode != 0) { @@ -1274,19 +1274,19 @@ SysCallReturn syscallhandler_socketpair(SysCallHandler* sys, const SysCallArgs* /* Set any options that were given. */ if (type & SOCK_NONBLOCK) { - descriptor_addFlags((Descriptor*)socketA, O_NONBLOCK); - descriptor_addFlags((Descriptor*)socketB, O_NONBLOCK); + descriptor_addFlags((LegacyDescriptor*)socketA, O_NONBLOCK); + descriptor_addFlags((LegacyDescriptor*)socketB, O_NONBLOCK); } if (type & SOCK_CLOEXEC) { - descriptor_addFlags((Descriptor*)socketA, O_CLOEXEC); - descriptor_addFlags((Descriptor*)socketB, O_CLOEXEC); + descriptor_addFlags((LegacyDescriptor*)socketA, O_CLOEXEC); + descriptor_addFlags((LegacyDescriptor*)socketB, O_CLOEXEC); } /* Return the socket fds to the caller. */ int* sockfd = process_getWriteablePtr(sys->process, sys->thread, fdsPtr, 2 * sizeof(int)); - sockfd[0] = process_registerDescriptor(sys->process, (Descriptor*)socketA); - sockfd[1] = process_registerDescriptor(sys->process, (Descriptor*)socketB); + sockfd[0] = process_registerLegacyDescriptor(sys->process, (LegacyDescriptor*)socketA); + sockfd[1] = process_registerLegacyDescriptor(sys->process, (LegacyDescriptor*)socketB); debug("Created socketpair with fd %i and fd %i", sockfd[0], sockfd[1]); diff --git a/src/main/host/syscall/timerfd.c b/src/main/host/syscall/timerfd.c index 083e1ebacc..44f7c5f3df 100644 --- a/src/main/host/syscall/timerfd.c +++ b/src/main/host/syscall/timerfd.c @@ -29,7 +29,7 @@ static int _syscallhandler_validateTimerHelper(SysCallHandler* sys, int tfd, } /* Check if this is a virtual Shadow descriptor. */ - Descriptor* desc = process_getRegisteredDescriptor(sys->process, tfd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, tfd); if (desc && timer_desc_out) { *timer_desc_out = (Timer*)desc; } @@ -67,7 +67,7 @@ SysCallReturn syscallhandler_timerfd_create(SysCallHandler* sys, /* Create the timer and double check that it's valid. */ Timer* timer = timer_new(); - int tfd = process_registerDescriptor(sys->process, (Descriptor*)timer); + int tfd = process_registerLegacyDescriptor(sys->process, (LegacyDescriptor*)timer); #ifdef DEBUG /* This should always be a valid descriptor. */ @@ -80,10 +80,10 @@ SysCallReturn syscallhandler_timerfd_create(SysCallHandler* sys, /* Set any options that were given. */ if (flags & TFD_NONBLOCK) { - descriptor_addFlags((Descriptor*)timer, O_NONBLOCK); + descriptor_addFlags((LegacyDescriptor*)timer, O_NONBLOCK); } if (flags & TFD_CLOEXEC) { - descriptor_addFlags((Descriptor*)timer, O_CLOEXEC); + descriptor_addFlags((LegacyDescriptor*)timer, O_CLOEXEC); } debug("timerfd_create() returning fd %i", tfd); diff --git a/src/main/host/syscall/uio.c b/src/main/host/syscall/uio.c index e5fc2614e6..520fa6e606 100644 --- a/src/main/host/syscall/uio.c +++ b/src/main/host/syscall/uio.c @@ -25,10 +25,10 @@ static int _syscallhandler_validateVecParams(SysCallHandler* sys, int fd, PluginPtr iovPtr, unsigned long iovlen, off_t offset, - Descriptor** desc_out, + LegacyDescriptor** desc_out, const struct iovec** iov_out) { /* Get the descriptor. */ - Descriptor* desc = process_getRegisteredDescriptor(sys->process, fd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, fd); if (!desc) { return -EBADF; } @@ -90,7 +90,7 @@ _syscallhandler_readvHelper(SysCallHandler* sys, int fd, PluginPtr iovPtr, "offset %ld, flags %d", fd, (void*)iovPtr.val, iovlen, pos_l, pos_h, offset, flags); - Descriptor* desc = NULL; + LegacyDescriptor* desc = NULL; const struct iovec* iov; int errcode = _syscallhandler_validateVecParams( sys, fd, iovPtr, iovlen, offset, &desc, &iov); @@ -99,7 +99,7 @@ _syscallhandler_readvHelper(SysCallHandler* sys, int fd, PluginPtr iovPtr, } /* Some logic depends on the descriptor type. */ - DescriptorType dType = descriptor_getType(desc); + LegacyDescriptorType dType = descriptor_getType(desc); ssize_t result = 0; @@ -209,7 +209,7 @@ _syscallhandler_writevHelper(SysCallHandler* sys, int fd, PluginPtr iovPtr, "offset %ld, flags %d", fd, (void*)iovPtr.val, iovlen, pos_l, pos_h, offset, flags); - Descriptor* desc = NULL; + LegacyDescriptor* desc = NULL; const struct iovec* iov; int errcode = _syscallhandler_validateVecParams( sys, fd, iovPtr, iovlen, offset, &desc, &iov); @@ -218,7 +218,7 @@ _syscallhandler_writevHelper(SysCallHandler* sys, int fd, PluginPtr iovPtr, } /* Some logic depends on the descriptor type. */ - DescriptorType dType = descriptor_getType(desc); + LegacyDescriptorType dType = descriptor_getType(desc); ssize_t result = 0; diff --git a/src/main/host/syscall/unistd.c b/src/main/host/syscall/unistd.c index 662457b6c8..c7a958ea35 100644 --- a/src/main/host/syscall/unistd.c +++ b/src/main/host/syscall/unistd.c @@ -54,12 +54,12 @@ static SysCallReturn _syscallhandler_pipeHelper(SysCallHandler* sys, /* Set any options that were given. */ if (flags & O_NONBLOCK) { - descriptor_addFlags((Descriptor*)pipeReader, O_NONBLOCK); - descriptor_addFlags((Descriptor*)pipeWriter, O_NONBLOCK); + descriptor_addFlags((LegacyDescriptor*)pipeReader, O_NONBLOCK); + descriptor_addFlags((LegacyDescriptor*)pipeWriter, O_NONBLOCK); } if (flags & O_CLOEXEC) { - descriptor_addFlags((Descriptor*)pipeReader, O_CLOEXEC); - descriptor_addFlags((Descriptor*)pipeWriter, O_CLOEXEC); + descriptor_addFlags((LegacyDescriptor*)pipeReader, O_CLOEXEC); + descriptor_addFlags((LegacyDescriptor*)pipeWriter, O_CLOEXEC); } /* Return the pipe fds to the caller. */ @@ -67,9 +67,9 @@ static SysCallReturn _syscallhandler_pipeHelper(SysCallHandler* sys, gint* pipefd = process_getWriteablePtr(sys->process, sys->thread, pipefdPtr, sizeNeeded); pipefd[0] = - process_registerDescriptor(sys->process, (Descriptor*)pipeReader); + process_registerLegacyDescriptor(sys->process, (LegacyDescriptor*)pipeReader); pipefd[1] = - process_registerDescriptor(sys->process, (Descriptor*)pipeWriter); + process_registerLegacyDescriptor(sys->process, (LegacyDescriptor*)pipeWriter); debug("Created pipe reader fd %i and writer fd %i", pipefd[0], pipefd[1]); @@ -83,13 +83,13 @@ static SysCallReturn _syscallhandler_readHelper(SysCallHandler* sys, int fd, "trying to read %zu bytes on fd %i at offset %li", bufSize, fd, offset); /* Get the descriptor. */ - Descriptor* desc = process_getRegisteredDescriptor(sys->process, fd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, fd); if (!desc) { return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EBADF}; } /* Some logic depends on the descriptor type. */ - DescriptorType dType = descriptor_getType(desc); + LegacyDescriptorType dType = descriptor_getType(desc); /* We can only seek on files, otherwise its a pipe error. */ if (dType != DT_FILE && offset != 0) { @@ -183,13 +183,13 @@ static SysCallReturn _syscallhandler_writeHelper(SysCallHandler* sys, int fd, offset); /* Get the descriptor. */ - Descriptor* desc = process_getRegisteredDescriptor(sys->process, fd); + LegacyDescriptor* desc = process_getRegisteredLegacyDescriptor(sys->process, fd); if (!desc) { return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EBADF}; } /* Some logic depends on the descriptor type. */ - DescriptorType dType = descriptor_getType(desc); + LegacyDescriptorType dType = descriptor_getType(desc); /* We can only seek on files, otherwise its a pipe error. */ if (dType != DT_FILE && offset != 0) { @@ -284,7 +284,7 @@ SysCallReturn syscallhandler_close(SysCallHandler* sys, } /* Check if this is a virtual Shadow descriptor. */ - Descriptor* descriptor = process_getRegisteredDescriptor(sys->process, fd); + LegacyDescriptor* descriptor = process_getRegisteredLegacyDescriptor(sys->process, fd); errorCode = _syscallhandler_validateDescriptor(descriptor, DT_NONE); if (descriptor && !errorCode) { diff --git a/src/main/host/syscall_condition.c b/src/main/host/syscall_condition.c index cf3a925458..182fb3123a 100644 --- a/src/main/host/syscall_condition.c +++ b/src/main/host/syscall_condition.c @@ -80,7 +80,7 @@ static void _syscallcondition_cleanupListeners(SysCallCondition* cond) { /* Destroy the listeners, which will also unref and free cond. */ if (cond->timeout && cond->timeoutListener) { descriptor_removeListener( - (Descriptor*)cond->timeout, cond->timeoutListener); + (LegacyDescriptor*)cond->timeout, cond->timeoutListener); statuslistener_setMonitorStatus(cond->timeoutListener, STATUS_NONE, SLF_NEVER); } @@ -355,7 +355,7 @@ void syscallcondition_waitNonblock(SysCallCondition* cond, Process* proc, /* Attach the listener to the timer. */ descriptor_addListener( - (Descriptor*)cond->timeout, cond->timeoutListener); + (LegacyDescriptor*)cond->timeout, cond->timeoutListener); } if (cond->trigger.object.as_pointer && !cond->triggerListener) { diff --git a/src/main/host/syscall_condition.h b/src/main/host/syscall_condition.h index b07f607890..c297dad768 100644 --- a/src/main/host/syscall_condition.h +++ b/src/main/host/syscall_condition.h @@ -26,7 +26,7 @@ enum _TriggerType { typedef union _TriggerObject TriggerObject; union _TriggerObject { void* as_pointer; - Descriptor* as_descriptor; + LegacyDescriptor* as_descriptor; Futex* as_futex; }; From f51f211a582e6578e46521fd6c6097139b7f88f8 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Wed, 23 Dec 2020 14:22:09 -0500 Subject: [PATCH 04/13] Remove from descriptor table by fd index, not pointer --- src/main/host/descriptor/descriptor_table.c | 6 +++--- src/main/host/descriptor/descriptor_table.h | 2 +- src/main/host/process.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/host/descriptor/descriptor_table.c b/src/main/host/descriptor/descriptor_table.c index 1e3efdea90..33dcd1ffa5 100644 --- a/src/main/host/descriptor/descriptor_table.c +++ b/src/main/host/descriptor/descriptor_table.c @@ -121,12 +121,12 @@ static void _descriptortable_trimIndicesTail(DescriptorTable* table) { } } -bool descriptortable_remove(DescriptorTable* table, LegacyDescriptor* descriptor) { +bool descriptortable_remove(DescriptorTable* table, int index) { MAGIC_ASSERT(table); - int index = descriptor_getHandle(descriptor); - if (g_hash_table_contains(table->descriptors, GINT_TO_POINTER(index))) { + LegacyDescriptor* descriptor = descriptortable_get(table, index); + /* Make sure we do not operate on the descriptor after we remove it, * because that could cause it to be freed and invalidate it. */ descriptor_setHandle(descriptor, 0); diff --git a/src/main/host/descriptor/descriptor_table.h b/src/main/host/descriptor/descriptor_table.h index dbe31dc39a..d4ab8d3dc6 100644 --- a/src/main/host/descriptor/descriptor_table.h +++ b/src/main/host/descriptor/descriptor_table.h @@ -41,7 +41,7 @@ int descriptortable_add(DescriptorTable* table, LegacyDescriptor* descriptor); * * NOTE: this will unref the descriptor which may cause it to be freed. If you * still need access to it, you should ref it before calling this function. */ -bool descriptortable_remove(DescriptorTable* table, LegacyDescriptor* descriptor); +bool descriptortable_remove(DescriptorTable* table, int index); /* Returns the descriptor at the given table index, or NULL if we are not * storing a descriptor at the given index. */ diff --git a/src/main/host/process.c b/src/main/host/process.c index cd13bee763..f896a2ba24 100644 --- a/src/main/host/process.c +++ b/src/main/host/process.c @@ -745,7 +745,7 @@ void process_deregisterLegacyDescriptor(Process* proc, LegacyDescriptor* desc) { host_disassociateInterface(proc->host, (Socket*)desc); } descriptor_setOwnerProcess(desc, NULL); - descriptortable_remove(proc->descTable, desc); + descriptortable_remove(proc->descTable, descriptor_getHandle(desc)); } } From 11f84e5fb75e36ebd92487a2c26dcd3285c5e1f7 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Fri, 8 Jan 2021 20:23:05 -0500 Subject: [PATCH 05/13] Added support for Rust descriptor objects Added a new Rust `Descriptor` type and modified the descriptor table to store `CompatDescriptor` objects, which can store either this new Rust descriptor type or the legacy C descriptor type. --- src/main/bindings/c/bindings-opaque.h | 2 + src/main/bindings/c/bindings.h | 18 +++ src/main/bindings/c/cbindgen.toml | 2 +- src/main/bindings/rust/CMakeLists.txt | 4 + src/main/bindings/rust/wrapper.h | 1 + src/main/bindings/rust/wrapper.rs | 19 +++- src/main/host/descriptor/descriptor_table.c | 50 ++++++--- src/main/host/descriptor/descriptor_table.h | 7 +- src/main/host/descriptor/mod.rs | 117 ++++++++++++++++++++ src/main/host/mod.rs | 1 + src/main/host/process.c | 46 +++++++- src/main/host/process.h | 6 + 12 files changed, 244 insertions(+), 29 deletions(-) create mode 100644 src/main/host/descriptor/mod.rs diff --git a/src/main/bindings/c/bindings-opaque.h b/src/main/bindings/c/bindings-opaque.h index 345669559c..18bb763a4d 100644 --- a/src/main/bindings/c/bindings-opaque.h +++ b/src/main/bindings/c/bindings-opaque.h @@ -13,6 +13,8 @@ // A queue of byte chunks. typedef struct ByteQueue ByteQueue; +typedef struct CompatDescriptor CompatDescriptor; + // Manages the address-space for a plugin process. // // The MemoryManager's primary purpose is to make plugin process's memory directly accessible to diff --git a/src/main/bindings/c/bindings.h b/src/main/bindings/c/bindings.h index d820885042..8cd699b967 100644 --- a/src/main/bindings/c/bindings.h +++ b/src/main/bindings/c/bindings.h @@ -15,11 +15,29 @@ #include #include #include "main/bindings/c/bindings-opaque.h" +#include "main/host/descriptor/descriptor_types.h" #include "main/host/syscall_types.h" #include "main/host/thread.h" void rust_logging_init(void); +// The new compat descriptor takes ownership of the reference to the legacy descriptor and +// does not increment its ref count, but will decrement the ref count when this compat +// descriptor is freed/dropped. +CompatDescriptor *compatdescriptor_fromLegacy(LegacyDescriptor *legacy_descriptor); + +// If the compat descriptor is a legacy descriptor, returns a pointer to the legacy +// descriptor object. Otherwise returns NULL. The legacy descriptor's ref count is not +// modified, so the pointer must not outlive the lifetime of the compat descriptor. +LegacyDescriptor *compatdescriptor_asLegacy(const CompatDescriptor *descriptor); + +// When the compat descriptor is freed/dropped, it will decrement the legacy descriptor's +// ref count. +void compatdescriptor_free(CompatDescriptor *descriptor); + +// This is a no-op for non-legacy descriptors. +void compatdescriptor_setHandle(CompatDescriptor *descriptor, int handle); + // # Safety // * `thread` must point to a valid object. MemoryManager *memorymanager_new(Thread *thread); diff --git a/src/main/bindings/c/cbindgen.toml b/src/main/bindings/c/cbindgen.toml index f9e77ebda0..8cfe0d1e4c 100644 --- a/src/main/bindings/c/cbindgen.toml +++ b/src/main/bindings/c/cbindgen.toml @@ -9,7 +9,7 @@ header = '''/* // clang-format off ''' autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" -includes = ["main/bindings/c/bindings-opaque.h", "main/host/syscall_types.h", "main/host/thread.h"] +includes = ["main/bindings/c/bindings-opaque.h", "main/host/descriptor/descriptor_types.h", "main/host/syscall_types.h", "main/host/thread.h"] [export] # Avoid exporting C types back through again. diff --git a/src/main/bindings/rust/CMakeLists.txt b/src/main/bindings/rust/CMakeLists.txt index 50e2d5e7b8..88d760bd6d 100644 --- a/src/main/bindings/rust/CMakeLists.txt +++ b/src/main/bindings/rust/CMakeLists.txt @@ -21,8 +21,12 @@ endforeach(COMPILE_DEFINITION) add_custom_command(OUTPUT wrapper.rs COMMAND bindgen --whitelist-function "thread_.*" + --whitelist-function "descriptor_unref" + --whitelist-function "descriptor_setHandle" --whitelist-type "PluginPtr" --whitelist-type "SysCall.*" + --whitelist-type "LegacyDescriptor" + --opaque-type "LegacyDescriptor" --disable-header-comment --raw-line "/* automatically generated by rust-bindgen */" ${CMAKE_CURRENT_SOURCE_DIR}/wrapper.h -o ${CMAKE_CURRENT_SOURCE_DIR}/wrapper.rs -- ${LLVM_FLAGS} diff --git a/src/main/bindings/rust/wrapper.h b/src/main/bindings/rust/wrapper.h index e324626d3d..5beb5648f9 100644 --- a/src/main/bindings/rust/wrapper.h +++ b/src/main/bindings/rust/wrapper.h @@ -5,5 +5,6 @@ // Don't forget to whitelist functions/types/vars in CMakeLists.txt +#include "main/host/descriptor/descriptor.h" #include "main/host/syscall_types.h" #include "main/host/thread.h" diff --git a/src/main/bindings/rust/wrapper.rs b/src/main/bindings/rust/wrapper.rs index 294a7e9e8d..ca5c38965b 100644 --- a/src/main/bindings/rust/wrapper.rs +++ b/src/main/bindings/rust/wrapper.rs @@ -1,9 +1,14 @@ /* automatically generated by rust-bindgen */ +pub type size_t = ::std::os::raw::c_ulong; pub type __uint32_t = ::std::os::raw::c_uint; pub type __int64_t = ::std::os::raw::c_long; pub type __uint64_t = ::std::os::raw::c_ulong; pub type __pid_t = ::std::os::raw::c_int; +pub type pid_t = __pid_t; +pub type gint = ::std::os::raw::c_int; +pub type gpointer = *mut ::std::os::raw::c_void; +pub type LegacyDescriptor = [u64; 7usize]; pub type PluginVirtualPtr = _PluginVirtualPtr; pub type PluginPtr = _PluginVirtualPtr; #[repr(C)] @@ -187,8 +192,6 @@ fn bindgen_test_layout__SysCallReturn() { ); } pub type SysCallReturn = _SysCallReturn; -pub type size_t = ::std::os::raw::c_ulong; -pub type pid_t = __pid_t; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _Thread { @@ -301,3 +304,15 @@ extern "C" { extern "C" { pub fn thread_isLeader(thread: *mut Thread) -> bool; } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SysCallHandler { + _unused: [u8; 0], +} +pub type SysCallHandler = _SysCallHandler; +extern "C" { + pub fn descriptor_unref(data: gpointer); +} +extern "C" { + pub fn descriptor_setHandle(descriptor: *mut LegacyDescriptor, handle: gint); +} diff --git a/src/main/host/descriptor/descriptor_table.c b/src/main/host/descriptor/descriptor_table.c index 33dcd1ffa5..876ca944ad 100644 --- a/src/main/host/descriptor/descriptor_table.c +++ b/src/main/host/descriptor/descriptor_table.c @@ -37,12 +37,16 @@ struct _DescriptorTable { MAGIC_DECLARE; }; +static void _descriptortable_value_free(void* data) { + compatdescriptor_free(data); +} + DescriptorTable* descriptortable_new() { DescriptorTable* table = malloc(sizeof(DescriptorTable)); *table = (DescriptorTable){ .descriptors = g_hash_table_new_full( - g_direct_hash, g_direct_equal, NULL, descriptor_unref), + g_direct_hash, g_direct_equal, NULL, _descriptortable_value_free), .availableIndices = g_queue_new(), .indexCounter = STDERR_FILENO, // the first allocatable index is 3 .referenceCount = 1, @@ -82,7 +86,7 @@ void descriptortable_unref(DescriptorTable* table) { } } -int descriptortable_add(DescriptorTable* table, LegacyDescriptor* descriptor) { +int descriptortable_add(DescriptorTable* table, CompatDescriptor* descriptor) { MAGIC_ASSERT(table); int index = 0; @@ -98,7 +102,7 @@ int descriptortable_add(DescriptorTable* table, LegacyDescriptor* descriptor) { g_hash_table_insert(table->descriptors, GINT_TO_POINTER(index), descriptor); - descriptor_setHandle(descriptor, index); + compatdescriptor_setHandle(descriptor, index); return index; } @@ -125,11 +129,11 @@ bool descriptortable_remove(DescriptorTable* table, int index) { MAGIC_ASSERT(table); if (g_hash_table_contains(table->descriptors, GINT_TO_POINTER(index))) { - LegacyDescriptor* descriptor = descriptortable_get(table, index); + CompatDescriptor* descriptor = descriptortable_get(table, index); /* Make sure we do not operate on the descriptor after we remove it, * because that could cause it to be freed and invalidate it. */ - descriptor_setHandle(descriptor, 0); + compatdescriptor_setHandle(descriptor, 0); g_hash_table_remove(table->descriptors, GINT_TO_POINTER(index)); g_queue_insert_sorted(table->availableIndices, GINT_TO_POINTER(index), _descriptortable_compareInts, NULL); @@ -140,24 +144,24 @@ bool descriptortable_remove(DescriptorTable* table, int index) { } } -LegacyDescriptor* descriptortable_get(DescriptorTable* table, int index) { +CompatDescriptor* descriptortable_get(DescriptorTable* table, int index) { MAGIC_ASSERT(table); return g_hash_table_lookup(table->descriptors, GINT_TO_POINTER(index)); } void descriptortable_set(DescriptorTable* table, int index, - LegacyDescriptor* descriptor) { + CompatDescriptor* descriptor) { MAGIC_ASSERT(table); /* We may be replacing a descriptor that is already set at index. */ - LegacyDescriptor* existing = descriptortable_get(table, index); + CompatDescriptor* existing = descriptortable_get(table, index); if (existing) { - descriptor_setHandle(existing, 0); + compatdescriptor_setHandle(existing, 0); } /* Store the new descriptor at the index. */ g_hash_table_insert(table->descriptors, GINT_TO_POINTER(index), descriptor); - descriptor_setHandle(descriptor, index); + compatdescriptor_setHandle(descriptor, index); } /* TODO: remove this once the TCP layer is better designed. */ @@ -172,16 +176,28 @@ void descriptortable_shutdownHelper(DescriptorTable* table) { gpointer key, value; g_hash_table_iter_init(&iter, table->descriptors); while (g_hash_table_iter_next(&iter, &key, &value)) { - LegacyDescriptor* desc = value; - if (desc && desc->type == DT_TCPSOCKET) { + CompatDescriptor* desc = value; + + if (desc == NULL) { + continue; + } + + LegacyDescriptor* legacyDesc = compatdescriptor_asLegacy(value); + + /* if the descriptor was not a legacy descriptor */ + if (legacyDesc == NULL) { + continue; + } + + if (legacyDesc->type == DT_TCPSOCKET) { /* tcp servers and their children holds refs to each other. make * sure they all get freed by removing the refs in one direction */ - tcp_clearAllChildrenIfServer((TCP*)desc); - } else if (desc && (desc->type == DT_UNIXSOCKET || desc->type == DT_PIPE)) { + tcp_clearAllChildrenIfServer((TCP*)legacyDesc); + } else if (legacyDesc->type == DT_UNIXSOCKET || legacyDesc->type == DT_PIPE) { /* we need to correctly update the linked channel refs */ - channel_setLinkedChannel((Channel*)desc, NULL); - } else if (desc && desc->type == DT_EPOLL) { - epoll_clearWatchListeners((Epoll*)desc); + channel_setLinkedChannel((Channel*)legacyDesc, NULL); + } else if (legacyDesc->type == DT_EPOLL) { + epoll_clearWatchListeners((Epoll*)legacyDesc); } } } diff --git a/src/main/host/descriptor/descriptor_table.h b/src/main/host/descriptor/descriptor_table.h index d4ab8d3dc6..50884b7d13 100644 --- a/src/main/host/descriptor/descriptor_table.h +++ b/src/main/host/descriptor/descriptor_table.h @@ -8,6 +8,7 @@ #include +#include "main/bindings/c/bindings.h" #include "main/host/descriptor/descriptor_types.h" /* Opaque object to store the state needed to implement the module. */ @@ -31,7 +32,7 @@ void descriptortable_unref(DescriptorTable* table); * NOTE: that this consumes a reference to the descriptor, so if you are storing * it outside of the descriptor table you will need to ref it after calling * this function. */ -int descriptortable_add(DescriptorTable* table, LegacyDescriptor* descriptor); +int descriptortable_add(DescriptorTable* table, CompatDescriptor* descriptor); /* Stop storing the descriptor so that it can no longer be referenced. The table * index that was used to store the descriptor is cleared from the descriptor @@ -45,14 +46,14 @@ bool descriptortable_remove(DescriptorTable* table, int index); /* Returns the descriptor at the given table index, or NULL if we are not * storing a descriptor at the given index. */ -LegacyDescriptor* descriptortable_get(DescriptorTable* table, int index); +CompatDescriptor* descriptortable_get(DescriptorTable* table, int index); /* Store the given descriptor at given index. Any previous descriptor that was * stored there will be removed and its table index will be cleared. This * unrefs any existing descriptor stored at index as in remove(), and consumes * a ref to the existing descriptor as in add(). */ void descriptortable_set(DescriptorTable* table, int index, - LegacyDescriptor* descriptor); + CompatDescriptor* descriptor); /* This is a helper function that handles some corner cases where some * descriptors are linked to each other and we must remove that link in diff --git a/src/main/host/descriptor/mod.rs b/src/main/host/descriptor/mod.rs new file mode 100644 index 0000000000..b2be1d4fee --- /dev/null +++ b/src/main/host/descriptor/mod.rs @@ -0,0 +1,117 @@ +use crate::cshadow as c; + +/// A trait we can use as a compile-time check to make sure that an object is Send. +trait IsSend: Send {} + +/// A trait we can use as a compile-time check to make sure that an object is Sync. +trait IsSync: Sync {} + +/// A type that allows us to make a pointer Send + Sync since there is no way +/// to add these traits to the pointer itself. +#[derive(Clone, Copy)] +pub struct SyncSendPointer(*mut T); + +unsafe impl Send for SyncSendPointer {} +unsafe impl Sync for SyncSendPointer {} + +impl SyncSendPointer { + /// Get the pointer. + pub fn ptr(&self) -> *mut T { + self.0 + } + + /// Get a mutable reference to the pointer. + pub fn ptr_ref(&mut self) -> &mut *mut T { + &mut self.0 + } +} + +#[derive(Clone)] +pub struct Descriptor { + // TODO: implement the descriptor + flags: i32, +} + +// don't implement copy or clone without considering the legacy descriptor's ref count +#[allow(dead_code)] +pub enum CompatDescriptor { + New(Descriptor), + Legacy(SyncSendPointer), +} + +// will not compile if `CompatDescriptor` is not Send + Sync +impl IsSend for CompatDescriptor {} +impl IsSync for CompatDescriptor {} + +impl Drop for CompatDescriptor { + fn drop(&mut self) { + if let CompatDescriptor::Legacy(d) = self { + // unref the legacy descriptor object + unsafe { c::descriptor_unref(d.ptr() as *mut core::ffi::c_void) }; + } + } +} + +mod export { + use super::*; + + /// The new compat descriptor takes ownership of the reference to the legacy descriptor and + /// does not increment its ref count, but will decrement the ref count when this compat + /// descriptor is freed/dropped. + #[no_mangle] + pub extern "C" fn compatdescriptor_fromLegacy( + legacy_descriptor: *mut c::LegacyDescriptor, + ) -> *mut CompatDescriptor { + assert!(!legacy_descriptor.is_null()); + + let descriptor = CompatDescriptor::Legacy(SyncSendPointer(legacy_descriptor)); + Box::into_raw(Box::new(descriptor)) + } + + /// If the compat descriptor is a legacy descriptor, returns a pointer to the legacy + /// descriptor object. Otherwise returns NULL. The legacy descriptor's ref count is not + /// modified, so the pointer must not outlive the lifetime of the compat descriptor. + #[no_mangle] + pub extern "C" fn compatdescriptor_asLegacy( + descriptor: *const CompatDescriptor, + ) -> *mut c::LegacyDescriptor { + assert!(!descriptor.is_null()); + + let descriptor = unsafe { &*descriptor }; + + if let CompatDescriptor::Legacy(d) = descriptor { + d.ptr() + } else { + std::ptr::null_mut() + } + } + + /// When the compat descriptor is freed/dropped, it will decrement the legacy descriptor's + /// ref count. + #[no_mangle] + pub extern "C" fn compatdescriptor_free(descriptor: *mut CompatDescriptor) { + if descriptor.is_null() { + return; + } + + let descriptor = unsafe { &mut *descriptor }; + unsafe { Box::from_raw(descriptor) }; + } + + /// This is a no-op for non-legacy descriptors. + #[no_mangle] + pub extern "C" fn compatdescriptor_setHandle( + descriptor: *mut CompatDescriptor, + handle: libc::c_int, + ) { + assert!(!descriptor.is_null()); + + let descriptor = unsafe { &mut *descriptor }; + + if let CompatDescriptor::Legacy(d) = descriptor { + unsafe { c::descriptor_setHandle(d.ptr(), handle) } + } + + // new descriptor types don't store their file handle, so do nothing + } +} diff --git a/src/main/host/mod.rs b/src/main/host/mod.rs index 5ef37f2438..607a708e11 100644 --- a/src/main/host/mod.rs +++ b/src/main/host/mod.rs @@ -1,3 +1,4 @@ +mod descriptor; mod memory_manager; pub mod syscall_types; pub mod thread; diff --git a/src/main/host/process.c b/src/main/host/process.c index f896a2ba24..f8ad539d3c 100644 --- a/src/main/host/process.c +++ b/src/main/host/process.c @@ -297,13 +297,15 @@ static void _process_openStdIOFileHelper(Process* proc, bool isStdOut) { debug("Successfully opened %s file at %s", isStdOut ? "stdout" : "stderr", fileName); + CompatDescriptor* compatDesc = compatdescriptor_fromLegacy((LegacyDescriptor*)stdfile); + if (isStdOut) { descriptortable_set( - proc->descTable, STDOUT_FILENO, (LegacyDescriptor*)stdfile); + proc->descTable, STDOUT_FILENO, compatDesc); proc->stdoutFile = stdfile; } else { descriptortable_set( - proc->descTable, STDERR_FILENO, (LegacyDescriptor*)stdfile); + proc->descTable, STDERR_FILENO, compatDesc); proc->stderrFile = stdfile; } @@ -726,14 +728,34 @@ void process_flushPtrs(Process* proc, Thread* thread) { } // ****************************************************** -// Handler the descriptors owned by this process +// Handle the descriptors owned by this process // ****************************************************** +int process_registerCompatDescriptor(Process* proc, CompatDescriptor* compatDesc) { + MAGIC_ASSERT(proc); + utility_assert(compatDesc); + return descriptortable_add(proc->descTable, compatDesc); +} + +void process_deregisterCompatDescriptor(Process* proc, int handle) { + MAGIC_ASSERT(proc); + descriptortable_remove(proc->descTable, handle); +} + +CompatDescriptor* process_getRegisteredCompatDescriptor(Process* proc, int handle) { + MAGIC_ASSERT(proc); + CompatDescriptor* compatDesc = descriptortable_get(proc->descTable, handle); + return compatDesc; +} + int process_registerLegacyDescriptor(Process* proc, LegacyDescriptor* desc) { MAGIC_ASSERT(proc); utility_assert(desc); + descriptor_setOwnerProcess(desc, proc); - return descriptortable_add(proc->descTable, desc); + CompatDescriptor* compatDesc = compatdescriptor_fromLegacy(desc); + + return process_registerCompatDescriptor(proc, compatDesc); } void process_deregisterLegacyDescriptor(Process* proc, LegacyDescriptor* desc) { @@ -751,6 +773,18 @@ void process_deregisterLegacyDescriptor(Process* proc, LegacyDescriptor* desc) { LegacyDescriptor* process_getRegisteredLegacyDescriptor(Process* proc, int handle) { MAGIC_ASSERT(proc); - return descriptortable_get(proc->descTable, handle); -} + CompatDescriptor* compatDesc = process_getRegisteredCompatDescriptor(proc, handle); + if (compatDesc == NULL) { + return NULL; + } + + // will return NULL if the descriptor is valid but is not a legacy descriptor + LegacyDescriptor* legacyDesc = compatdescriptor_asLegacy(compatDesc); + + if (legacyDesc == NULL) { + warning("Attempted to convert compat descriptor fd=%d to a legacy descriptor", handle); + } + + return legacyDesc; +} diff --git a/src/main/host/process.h b/src/main/host/process.h index ddc7b21813..d7757356d2 100644 --- a/src/main/host/process.h +++ b/src/main/host/process.h @@ -71,6 +71,12 @@ const gchar* process_getPluginName(Process* proc); /* Returns the processID that was assigned to us in process_new */ guint process_getProcessID(Process* proc); +/* Handle all of the descriptors owned by this process. */ +int process_registerCompatDescriptor(Process* proc, CompatDescriptor* compatDesc); +void process_deregisterCompatDescriptor(Process* proc, int handle); +CompatDescriptor* process_getRegisteredCompatDescriptor(Process* proc, int handle); + +/* Handle only the legacy descriptors owned by this process. */ int process_registerLegacyDescriptor(Process* proc, LegacyDescriptor* desc); void process_deregisterLegacyDescriptor(Process* proc, LegacyDescriptor* desc); LegacyDescriptor* process_getRegisteredLegacyDescriptor(Process* proc, int handle); From 832005a0fe7e82333d8de5c0fd89159dc6e32026 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Tue, 12 Jan 2021 00:58:54 -0500 Subject: [PATCH 06/13] Added the basic structure of the Rust file object Added a new Rust `PosixFile` object which is referenced by `Descriptor` objects. Also added the structure of the C interface that Shadow will later use to integrate this new Rust type with legacy descriptors such as `Epoll`. This interface is defined but not yet implemented. --- src/main/Cargo.toml | 1 + src/main/bindings/c/bindings-opaque.h | 3 + src/main/bindings/c/bindings.h | 27 ++++++ src/main/bindings/c/cbindgen.toml | 8 +- src/main/bindings/rust/CMakeLists.txt | 2 + src/main/bindings/rust/wrapper.h | 2 + src/main/bindings/rust/wrapper.rs | 14 +++ src/main/host/descriptor/mod.rs | 128 +++++++++++++++++++++++++- 8 files changed, 183 insertions(+), 2 deletions(-) diff --git a/src/main/Cargo.toml b/src/main/Cargo.toml index 7d1fce4355..80181fd2ac 100644 --- a/src/main/Cargo.toml +++ b/src/main/Cargo.toml @@ -9,6 +9,7 @@ path = "lib.rs" crate-type = ["staticlib"] [dependencies] +atomic_refcell = "0.1" lazy_static = "1.4.0" libc = "0.2" log = "0.4" diff --git a/src/main/bindings/c/bindings-opaque.h b/src/main/bindings/c/bindings-opaque.h index 18bb763a4d..e3a226a2ec 100644 --- a/src/main/bindings/c/bindings-opaque.h +++ b/src/main/bindings/c/bindings-opaque.h @@ -32,4 +32,7 @@ typedef struct CompatDescriptor CompatDescriptor; // MemoryManager via its `handle_*` methods. typedef struct MemoryManager MemoryManager; +// An opaque type used when passing `*const AtomicRefCell` to C. +typedef struct PosixFileArc PosixFileArc; + #endif /* main_opaque_bindings_h */ diff --git a/src/main/bindings/c/bindings.h b/src/main/bindings/c/bindings.h index 8cd699b967..b15d9e4683 100644 --- a/src/main/bindings/c/bindings.h +++ b/src/main/bindings/c/bindings.h @@ -16,6 +16,7 @@ #include #include "main/bindings/c/bindings-opaque.h" #include "main/host/descriptor/descriptor_types.h" +#include "main/host/status_listener.h" #include "main/host/syscall_types.h" #include "main/host/thread.h" @@ -38,6 +39,32 @@ void compatdescriptor_free(CompatDescriptor *descriptor); // This is a no-op for non-legacy descriptors. void compatdescriptor_setHandle(CompatDescriptor *descriptor, int handle); +// If the compat descriptor is a new descriptor, returns a pointer to the reference-counted +// posix file object. Otherwise returns NULL. The posix file object's ref count is not +// modified, so the pointer must not outlive the lifetime of the compat descriptor. +const PosixFileArc *compatdescriptor_borrowPosixFile(CompatDescriptor *descriptor); + +// If the compat descriptor is a new descriptor, returns a pointer to the reference-counted +// posix file object. Otherwise returns NULL. The posix file object's ref count is +// incremented, so the pointer must always later be passed to `posixfile_drop()`, otherwise +// the memory will leak. +const PosixFileArc *compatdescriptor_newRefPosixFile(CompatDescriptor *descriptor); + +// Decrement the ref count of the posix file object. The pointer must not be used after +// calling this function. +void posixfile_drop(const PosixFileArc *file); + +// Get the status of the posix file object. +Status posixfile_getStatus(const PosixFileArc *file); + +// Add a status listener to the posix file object. This will increment the status +// listener's ref count, and will decrement the ref count when this status listener is +// removed or when the posix file is freed/dropped. +void posixfile_addListener(const PosixFileArc *file, StatusListener *listener); + +// Remove a listener from the posix file object. +void posixfile_removeListener(const PosixFileArc *file, StatusListener *listener); + // # Safety // * `thread` must point to a valid object. MemoryManager *memorymanager_new(Thread *thread); diff --git a/src/main/bindings/c/cbindgen.toml b/src/main/bindings/c/cbindgen.toml index 8cfe0d1e4c..6fdb6704ce 100644 --- a/src/main/bindings/c/cbindgen.toml +++ b/src/main/bindings/c/cbindgen.toml @@ -9,7 +9,13 @@ header = '''/* // clang-format off ''' autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" -includes = ["main/bindings/c/bindings-opaque.h", "main/host/descriptor/descriptor_types.h", "main/host/syscall_types.h", "main/host/thread.h"] +includes = [ + "main/bindings/c/bindings-opaque.h", + "main/host/descriptor/descriptor_types.h", + "main/host/status_listener.h", + "main/host/syscall_types.h", + "main/host/thread.h", +] [export] # Avoid exporting C types back through again. diff --git a/src/main/bindings/rust/CMakeLists.txt b/src/main/bindings/rust/CMakeLists.txt index 88d760bd6d..1eaf24a1e1 100644 --- a/src/main/bindings/rust/CMakeLists.txt +++ b/src/main/bindings/rust/CMakeLists.txt @@ -24,6 +24,8 @@ add_custom_command(OUTPUT wrapper.rs --whitelist-function "descriptor_unref" --whitelist-function "descriptor_setHandle" --whitelist-type "PluginPtr" + --whitelist-type "Status" + --whitelist-type "StatusListener" --whitelist-type "SysCall.*" --whitelist-type "LegacyDescriptor" --opaque-type "LegacyDescriptor" diff --git a/src/main/bindings/rust/wrapper.h b/src/main/bindings/rust/wrapper.h index 5beb5648f9..71b4dff4fd 100644 --- a/src/main/bindings/rust/wrapper.h +++ b/src/main/bindings/rust/wrapper.h @@ -6,5 +6,7 @@ // Don't forget to whitelist functions/types/vars in CMakeLists.txt #include "main/host/descriptor/descriptor.h" +#include "main/host/status.h" +#include "main/host/status_listener.h" #include "main/host/syscall_types.h" #include "main/host/thread.h" diff --git a/src/main/bindings/rust/wrapper.rs b/src/main/bindings/rust/wrapper.rs index ca5c38965b..da762aba84 100644 --- a/src/main/bindings/rust/wrapper.rs +++ b/src/main/bindings/rust/wrapper.rs @@ -8,7 +8,21 @@ pub type __pid_t = ::std::os::raw::c_int; pub type pid_t = __pid_t; pub type gint = ::std::os::raw::c_int; pub type gpointer = *mut ::std::os::raw::c_void; +pub use self::_Status as Status; +pub const _Status_STATUS_NONE: _Status = 0; +pub const _Status_STATUS_DESCRIPTOR_ACTIVE: _Status = 1; +pub const _Status_STATUS_DESCRIPTOR_READABLE: _Status = 2; +pub const _Status_STATUS_DESCRIPTOR_WRITABLE: _Status = 4; +pub const _Status_STATUS_DESCRIPTOR_CLOSED: _Status = 8; +pub const _Status_STATUS_FUTEX_WAKEUP: _Status = 16; +pub type _Status = i32; pub type LegacyDescriptor = [u64; 7usize]; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _StatusListener { + _unused: [u8; 0], +} +pub type StatusListener = _StatusListener; pub type PluginVirtualPtr = _PluginVirtualPtr; pub type PluginPtr = _PluginVirtualPtr; #[repr(C)] diff --git a/src/main/host/descriptor/mod.rs b/src/main/host/descriptor/mod.rs index b2be1d4fee..f74ee25dca 100644 --- a/src/main/host/descriptor/mod.rs +++ b/src/main/host/descriptor/mod.rs @@ -1,3 +1,6 @@ +use atomic_refcell::AtomicRefCell; +use std::sync::Arc; + use crate::cshadow as c; /// A trait we can use as a compile-time check to make sure that an object is Send. @@ -26,12 +29,41 @@ impl SyncSendPointer { } } +pub enum PosixFile {} + +// will not compile if `PosixFile` is not Send + Sync +impl IsSend for PosixFile {} +impl IsSync for PosixFile {} + #[derive(Clone)] pub struct Descriptor { - // TODO: implement the descriptor + file: Arc>, flags: i32, } +#[allow(dead_code)] +impl Descriptor { + pub fn new(file: Arc>) -> Self { + Self { file, flags: 0 } + } + + pub fn get_file(&self) -> &Arc> { + &self.file + } + + pub fn get_flags(&self) -> i32 { + self.flags + } + + pub fn set_flags(&mut self, flags: i32) { + self.flags = flags; + } + + pub fn add_flags(&mut self, flags: i32) { + self.flags |= flags; + } +} + // don't implement copy or clone without considering the legacy descriptor's ref count #[allow(dead_code)] pub enum CompatDescriptor { @@ -55,6 +87,10 @@ impl Drop for CompatDescriptor { mod export { use super::*; + /// An opaque type used when passing `*const AtomicRefCell` to C. + #[no_mangle] + pub enum PosixFileArc {} + /// The new compat descriptor takes ownership of the reference to the legacy descriptor and /// does not increment its ref count, but will decrement the ref count when this compat /// descriptor is freed/dropped. @@ -114,4 +150,94 @@ mod export { // new descriptor types don't store their file handle, so do nothing } + + /// If the compat descriptor is a new descriptor, returns a pointer to the reference-counted + /// posix file object. Otherwise returns NULL. The posix file object's ref count is not + /// modified, so the pointer must not outlive the lifetime of the compat descriptor. + #[no_mangle] + pub extern "C" fn compatdescriptor_borrowPosixFile( + descriptor: *mut CompatDescriptor, + ) -> *const PosixFileArc { + assert!(!descriptor.is_null()); + + let descriptor = unsafe { &mut *descriptor }; + + (match descriptor { + CompatDescriptor::Legacy(_) => std::ptr::null_mut(), + CompatDescriptor::New(d) => Arc::as_ptr(d.get_file()), + }) as *const PosixFileArc + } + + /// If the compat descriptor is a new descriptor, returns a pointer to the reference-counted + /// posix file object. Otherwise returns NULL. The posix file object's ref count is + /// incremented, so the pointer must always later be passed to `posixfile_drop()`, otherwise + /// the memory will leak. + #[no_mangle] + pub extern "C" fn compatdescriptor_newRefPosixFile( + descriptor: *mut CompatDescriptor, + ) -> *const PosixFileArc { + assert!(!descriptor.is_null()); + + let descriptor = unsafe { &mut *descriptor }; + + (match descriptor { + CompatDescriptor::Legacy(_) => std::ptr::null_mut(), + CompatDescriptor::New(d) => Arc::into_raw(Arc::clone(&d.get_file())), + }) as *const PosixFileArc + } + + /// Decrement the ref count of the posix file object. The pointer must not be used after + /// calling this function. + #[no_mangle] + pub extern "C" fn posixfile_drop(file: *const PosixFileArc) { + assert!(!file.is_null()); + + unsafe { Arc::from_raw(file as *const AtomicRefCell) }; + } + + /// Get the status of the posix file object. + #[allow(unused_variables)] + #[no_mangle] + pub extern "C" fn posixfile_getStatus(file: *const PosixFileArc) -> c::Status { + assert!(!file.is_null()); + + let file = file as *const AtomicRefCell; + let file = unsafe { &*file }; + + todo!(); + } + + /// Add a status listener to the posix file object. This will increment the status + /// listener's ref count, and will decrement the ref count when this status listener is + /// removed or when the posix file is freed/dropped. + #[allow(unused_variables)] + #[no_mangle] + pub extern "C" fn posixfile_addListener( + file: *const PosixFileArc, + listener: *mut c::StatusListener, + ) { + assert!(!file.is_null()); + assert!(!listener.is_null()); + + let file = file as *const AtomicRefCell; + let file = unsafe { &*file }; + + todo!(); + } + + /// Remove a listener from the posix file object. + #[allow(unused_variables)] + #[no_mangle] + pub extern "C" fn posixfile_removeListener( + file: *const PosixFileArc, + listener: *mut c::StatusListener, + ) { + assert!(!file.is_null()); + assert!(!listener.is_null()); + + let file = file as *const AtomicRefCell; + let file = unsafe { &*file }; + + todo!(); + } } From 0be590dbd0c0ca6f04fa71e7f9700afcc5f56e13 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Tue, 12 Jan 2021 10:47:40 -0500 Subject: [PATCH 07/13] The epoll tables now index their entries by (fd, object_ptr) Rather than indexing only by the fd, the epoll descriptor 'watching' and 'ready' tables now index their entries by a tuple of the fd and a pointer to the object. This is similar to how Linux implements epoll, and will give us more expected behaviour. It is also on the path to adding support for watching Rust descriptor objects. --- src/main/host/descriptor/epoll.c | 93 +++++++++++++++++++++----------- src/main/host/descriptor/epoll.h | 2 +- src/main/host/syscall/epoll.c | 2 +- 3 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/main/host/descriptor/epoll.c b/src/main/host/descriptor/epoll.c index 8b150edbd1..a98e71b903 100644 --- a/src/main/host/descriptor/epoll.c +++ b/src/main/host/descriptor/epoll.c @@ -59,6 +59,8 @@ typedef struct _EpollWatch EpollWatch; struct _EpollWatch { /* the shadow descriptor we are watching for events */ LegacyDescriptor* descriptor; + /* the fd of the object we are watching */ + int fd; /* The listener that notifies us when status changes. */ StatusListener* listener; /* holds the actual event info */ @@ -69,6 +71,16 @@ struct _EpollWatch { MAGIC_DECLARE; }; +/* the epoll tables are indexed by the (fd, objectPtr) tuple so you can add the same object + * multiple times under different fds, and you can add the same fd multiple times as long as the + * object is different */ +typedef struct _EpollKey EpollKey; +struct _EpollKey { + int fd; + /* store the pointer as an int so that we never accidentally de-reference it */ + uintptr_t objectPtr; +}; + struct _Epoll { /* epoll itself is also a descriptor */ LegacyDescriptor super; @@ -82,11 +94,31 @@ struct _Epoll { MAGIC_DECLARE; }; +static EpollKey* _epollkey_new(int fd, uintptr_t objectPtr) { + EpollKey* key = g_new0(EpollKey, 1); + utility_assert(key); + + key->fd = fd; + key->objectPtr = objectPtr; + + return key; +} + +static guint _epollkey_hash(gconstpointer ptr) { + const EpollKey* key = ptr; + return g_int_hash(&key->fd) ^ g_int_hash(&key->objectPtr); +} + +static gboolean _epollkey_equal(gconstpointer ptr_1, gconstpointer ptr_2) { + const EpollKey* key_1 = ptr_1; + const EpollKey* key_2 = ptr_2; + return key_1->fd == key_2->fd && key_1->objectPtr == key_2->objectPtr; +} + /* forward declaration */ -static void _epoll_descriptorStatusChanged(Epoll* epoll, - LegacyDescriptor* descriptor); +static void _epoll_descriptorStatusChanged(Epoll* epoll, const EpollKey* key); -static EpollWatch* _epollwatch_new(Epoll* epoll, LegacyDescriptor* descriptor, +static EpollWatch* _epollwatch_new(Epoll* epoll, int fd, LegacyDescriptor* descriptor, const struct epoll_event* event) { EpollWatch* watch = g_new0(EpollWatch, 1); MAGIC_INIT(watch); @@ -96,15 +128,18 @@ static EpollWatch* _epollwatch_new(Epoll* epoll, LegacyDescriptor* descriptor, * (which is freed below in _epollwatch_free) */ descriptor_ref(descriptor); + watch->fd = fd; watch->descriptor = descriptor; watch->event = *event; watch->referenceCount = 1; + EpollKey *key = _epollkey_new(fd, (uintptr_t)(void*)descriptor); + /* Create the listener and ref the objects held by the listener. * The watch object already holds a ref to the descriptor so we * don't ref it again. */ watch->listener = statuslistener_new( - (StatusCallbackFunc)_epoll_descriptorStatusChanged, epoll, NULL, descriptor, NULL); + (StatusCallbackFunc)_epoll_descriptorStatusChanged, epoll, NULL, key, g_free); return watch; } @@ -185,8 +220,8 @@ Epoll* epoll_new() { descriptor_init(&(epoll->super), DT_EPOLL, &epollFunctions); /* allocate backend needed for managing events for this descriptor */ - epoll->watching = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, (GDestroyNotify)_epollwatch_unref); - epoll->ready = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, (GDestroyNotify)_epollwatch_unref); + epoll->watching = g_hash_table_new_full(_epollkey_hash, _epollkey_equal, g_free, (GDestroyNotify)_epollwatch_unref); + epoll->ready = g_hash_table_new_full(_epollkey_hash, _epollkey_equal, g_free, (GDestroyNotify)_epollwatch_unref); /* the epoll descriptor itself is always able to be epolled */ descriptor_adjustStatus(&(epoll->super), STATUS_DESCRIPTOR_ACTIVE, TRUE); @@ -285,16 +320,19 @@ static const gchar* _epoll_operationToStr(gint op) { } } -gint epoll_control(Epoll* epoll, gint operation, LegacyDescriptor* descriptor, +gint epoll_control(Epoll* epoll, gint operation, int fd, LegacyDescriptor* descriptor, const struct epoll_event* event) { MAGIC_ASSERT(epoll); - debug("epoll descriptor %i, operation %s, descriptor %i", - epoll->super.handle, _epoll_operationToStr(operation), descriptor->handle); + debug("epoll descriptor %i, operation %s, descriptor %i", epoll->super.handle, + _epoll_operationToStr(operation), fd); - gint* watchHandleRef = descriptor_getHandleReference(descriptor); + /* this on-stack key can be used for lookups only, not new entries */ + EpollKey key; + key.fd = fd; + key.objectPtr = (uintptr_t)(void*)descriptor; - EpollWatch* watch = g_hash_table_lookup(epoll->watching, watchHandleRef); + EpollWatch* watch = g_hash_table_lookup(epoll->watching, &key); switch (operation) { case EPOLL_CTL_ADD: { @@ -305,9 +343,10 @@ gint epoll_control(Epoll* epoll, gint operation, LegacyDescriptor* descriptor, } /* start watching for status changes */ - watch = _epollwatch_new(epoll, descriptor, event); + watch = _epollwatch_new(epoll, fd, descriptor, event); watch->flags |= EWF_WATCHING; - g_hash_table_replace(epoll->watching, watchHandleRef, watch); + gpointer new_key = _epollkey_new(key.fd, key.objectPtr); + g_hash_table_replace(epoll->watching, new_key, watch); /* It's added, so we need to listen for changes. Here we listen for * all statuses, because epoll will filter what it needs. @@ -321,7 +360,7 @@ gint epoll_control(Epoll* epoll, gint operation, LegacyDescriptor* descriptor, descriptor_addListener(watch->descriptor, watch->listener); /* initiate a callback if the new watched descriptor is ready */ - _epoll_descriptorStatusChanged(epoll, descriptor); + _epoll_descriptorStatusChanged(epoll, &key); break; } @@ -342,7 +381,7 @@ gint epoll_control(Epoll* epoll, gint operation, LegacyDescriptor* descriptor, watch->flags &= ~EWF_ONESHOT_REPORTED; /* initiate a callback if the new event type on the watched descriptor is ready */ - _epoll_descriptorStatusChanged(epoll, descriptor); + _epoll_descriptorStatusChanged(epoll, &key); break; } @@ -361,8 +400,8 @@ gint epoll_control(Epoll* epoll, gint operation, LegacyDescriptor* descriptor, descriptor_removeListener(watch->descriptor, watch->listener); /* unref gets called on the watch when it is removed from these tables */ - g_hash_table_remove(epoll->ready, watchHandleRef); - g_hash_table_remove(epoll->watching, watchHandleRef); + g_hash_table_remove(epoll->ready, &key); + g_hash_table_remove(epoll->watching, &key); break; } @@ -441,31 +480,25 @@ gint epoll_getEvents(Epoll* epoll, struct epoll_event* eventArray, gint eventArr return 0; } -static void _epoll_descriptorStatusChanged(Epoll* epoll, - LegacyDescriptor* descriptor) { +static void _epoll_descriptorStatusChanged(Epoll* epoll, const EpollKey* key) { MAGIC_ASSERT(epoll); - /* make sure we are actually watching the descriptor */ - gint* watchHandleRef = descriptor_getHandleReference(descriptor); - EpollWatch* watch = g_hash_table_lookup(epoll->watching, watchHandleRef); - - /* if we are not watching, its an error because we shouldn't be listening */ - utility_assert(watch && (watch->descriptor == descriptor)); - - debug("status changed in epoll %i for descriptor %i", descriptor_getHandle(&epoll->super), descriptor->handle); + EpollWatch* watch = g_hash_table_lookup(epoll->watching, key); + debug("status changed in epoll %i for descriptor %i", descriptor_getHandle(&epoll->super), watch->fd); /* update the status for the child watch fd */ _epollwatch_updateStatus(watch); /* check if its ready (has an event to report) now */ if(_epollwatch_isReady(watch)) { - if(!g_hash_table_contains(epoll->ready, watchHandleRef)) { + if(!g_hash_table_contains(epoll->ready, key)) { _epollwatch_ref(watch); - g_hash_table_replace(epoll->ready, watchHandleRef, watch); + gpointer keyCopy = _epollkey_new(key->fd, key->objectPtr); + g_hash_table_replace(epoll->ready, keyCopy, watch); } } else { /* this calls unref on the watch if its in the table */ - g_hash_table_remove(epoll->ready, watchHandleRef); + g_hash_table_remove(epoll->ready, key); } /* check the status on the parent epoll fd and adjust as needed */ diff --git a/src/main/host/descriptor/epoll.h b/src/main/host/descriptor/epoll.h index 80911340c9..06c72ea7f9 100644 --- a/src/main/host/descriptor/epoll.h +++ b/src/main/host/descriptor/epoll.h @@ -17,7 +17,7 @@ typedef struct _Epoll Epoll; /* free this with descriptor_free() */ Epoll* epoll_new(); -gint epoll_control(Epoll* epoll, gint operation, LegacyDescriptor* descriptor, +gint epoll_control(Epoll* epoll, gint operation, int fd, LegacyDescriptor* descriptor, const struct epoll_event* event); gint epoll_getEvents(Epoll* epoll, struct epoll_event* eventArray, gint eventArrayLength, gint* nEvents); diff --git a/src/main/host/syscall/epoll.c b/src/main/host/syscall/epoll.c index fd48d482b7..b6aba4781e 100644 --- a/src/main/host/syscall/epoll.c +++ b/src/main/host/syscall/epoll.c @@ -110,7 +110,7 @@ SysCallReturn syscallhandler_epoll_ctl(SysCallHandler* sys, } debug("Calling epoll_control on epoll %i with child %i", epfd, fd); - errorCode = epoll_control(epoll, op, descriptor, event); + errorCode = epoll_control(epoll, op, fd, descriptor, event); return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = errorCode}; } From 34328cd5b6e9a2fd8427356a5eae81aede100d9e Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Tue, 12 Jan 2021 12:47:49 -0500 Subject: [PATCH 08/13] Added Rust descriptor support to epoll The `Epoll` descriptor type can now watch for events on both `LegacyDescriptor` objects and `PosixFileArc` objects. --- src/main/host/descriptor/epoll.c | 124 ++++++++++++++++++++++++++----- src/main/host/descriptor/epoll.h | 2 +- src/main/host/syscall/epoll.c | 29 +++++--- 3 files changed, 126 insertions(+), 29 deletions(-) diff --git a/src/main/host/descriptor/epoll.c b/src/main/host/descriptor/epoll.c index a98e71b903..7a8af57579 100644 --- a/src/main/host/descriptor/epoll.c +++ b/src/main/host/descriptor/epoll.c @@ -10,6 +10,7 @@ #include #include +#include "main/bindings/c/bindings.h" #include "main/core/support/definitions.h" #include "main/core/support/object_counter.h" #include "main/core/work/task.h" @@ -55,13 +56,27 @@ enum _EpollWatchFlags { EWF_ONESHOT_REPORTED = 1 << 12, }; +typedef enum _EpollWatchTypes EpollWatchTypes; +enum _EpollWatchTypes { + EWT_LEGACY_DESCRIPTOR, + EWT_POSIX_FILE, +}; + +typedef union _EpollWatchObject EpollWatchObject; +union _EpollWatchObject { + LegacyDescriptor* as_descriptor; + const PosixFileArc* as_file; +}; + typedef struct _EpollWatch EpollWatch; struct _EpollWatch { - /* the shadow descriptor we are watching for events */ - LegacyDescriptor* descriptor; + /* the type of object we are watching (for example descriptor or file) */ + EpollWatchTypes watchType; + /* the object we are watching for events */ + EpollWatchObject watchObject; /* the fd of the object we are watching */ int fd; - /* The listener that notifies us when status changes. */ + /* the listener that notifies us when status changes */ StatusListener* listener; /* holds the actual event info */ struct epoll_event event; @@ -118,22 +133,35 @@ static gboolean _epollkey_equal(gconstpointer ptr_1, gconstpointer ptr_2) { /* forward declaration */ static void _epoll_descriptorStatusChanged(Epoll* epoll, const EpollKey* key); -static EpollWatch* _epollwatch_new(Epoll* epoll, int fd, LegacyDescriptor* descriptor, - const struct epoll_event* event) { +static EpollWatch* _epollwatch_new(Epoll* epoll, int fd, EpollWatchTypes type, + EpollWatchObject object, const struct epoll_event* event) { EpollWatch* watch = g_new0(EpollWatch, 1); MAGIC_INIT(watch); utility_assert(event); /* ref it for the EpollWatch, which also covers the listener reference * (which is freed below in _epollwatch_free) */ - descriptor_ref(descriptor); + if (type == EWT_LEGACY_DESCRIPTOR) { + descriptor_ref(object.as_descriptor); + } + watch->watchType = type; + watch->watchObject = object; watch->fd = fd; - watch->descriptor = descriptor; watch->event = *event; watch->referenceCount = 1; - EpollKey *key = _epollkey_new(fd, (uintptr_t)(void*)descriptor); + uintptr_t objectPtr; + if (watch->watchType == EWT_LEGACY_DESCRIPTOR) { + objectPtr = (uintptr_t)(void*)object.as_descriptor; + } else if (watch->watchType == EWT_POSIX_FILE) { + objectPtr = (uintptr_t)(void*)object.as_file; + } else { + warning("Unrecognized epoll watch type: %d", type); + objectPtr = (uintptr_t)NULL; + } + + EpollKey *key = _epollkey_new(fd, objectPtr); /* Create the listener and ref the objects held by the listener. * The watch object already holds a ref to the descriptor so we @@ -148,7 +176,12 @@ static void _epollwatch_free(EpollWatch* watch) { MAGIC_ASSERT(watch); statuslistener_unref(watch->listener); - descriptor_unref(watch->descriptor); + + if (watch->watchType == EWT_LEGACY_DESCRIPTOR) { + descriptor_unref(watch->watchObject.as_descriptor); + } else if (watch->watchType == EWT_POSIX_FILE) { + posixfile_drop(watch->watchObject.as_file); + } MAGIC_CLEAR(watch); g_free(watch); @@ -199,7 +232,12 @@ void epoll_clearWatchListeners(Epoll* epoll) { EpollWatch* watch = value; MAGIC_ASSERT(watch); statuslistener_setMonitorStatus(watch->listener, STATUS_NONE, SLF_NEVER); - descriptor_removeListener(watch->descriptor, watch->listener); + + if (watch->watchType == EWT_LEGACY_DESCRIPTOR) { + descriptor_removeListener(watch->watchObject.as_descriptor, watch->listener); + } else if (watch->watchType == EWT_POSIX_FILE) { + posixfile_removeListener(watch->watchObject.as_file, watch->listener); + } } } @@ -247,7 +285,13 @@ static void _epollwatch_updateStatus(EpollWatch* watch) { watch->flags = 0; /* check shadow descriptor status */ - Status status = descriptor_getStatus(watch->descriptor); + Status status; + if (watch->watchType == EWT_LEGACY_DESCRIPTOR) { + status = descriptor_getStatus(watch->watchObject.as_descriptor); + } else if (watch->watchType == EWT_POSIX_FILE) { + status = posixfile_getStatus(watch->watchObject.as_file); + } + watch->flags |= (status & STATUS_DESCRIPTOR_ACTIVE) ? EWF_ACTIVE : EWF_NONE; watch->flags |= (status & STATUS_DESCRIPTOR_READABLE) ? EWF_READABLE : EWF_NONE; watch->flags |= (status & STATUS_DESCRIPTOR_WRITABLE) ? EWF_WRITEABLE : EWF_NONE; @@ -320,17 +364,53 @@ static const gchar* _epoll_operationToStr(gint op) { } } -gint epoll_control(Epoll* epoll, gint operation, int fd, LegacyDescriptor* descriptor, +static void _getWatchObject(CompatDescriptor* descriptor, EpollWatchTypes* watchType, + EpollWatchObject* watchObject) { + LegacyDescriptor* legacyDescriptor = compatdescriptor_asLegacy(descriptor); + + /* if the compat descriptor is for a legacy descriptor */ + if (legacyDescriptor != NULL) { + *watchType = EWT_LEGACY_DESCRIPTOR; + watchObject->as_descriptor = legacyDescriptor; + } else { + const PosixFileArc* file = compatdescriptor_newRefPosixFile(descriptor); + /* if the compat descriptor is for a posix file object */ + if (file != NULL) { + *watchType = EWT_POSIX_FILE; + watchObject->as_file = file; + } else { + error("unrecognized watch object"); + } + } +} + +gint epoll_control(Epoll* epoll, gint operation, int fd, CompatDescriptor* descriptor, const struct epoll_event* event) { MAGIC_ASSERT(epoll); debug("epoll descriptor %i, operation %s, descriptor %i", epoll->super.handle, _epoll_operationToStr(operation), fd); + EpollWatchTypes watchType; + EpollWatchObject watchObject; + + /* get the watch type and object for the provided descriptor object */ + _getWatchObject(descriptor, &watchType, &watchObject); + /* this on-stack key can be used for lookups only, not new entries */ EpollKey key; key.fd = fd; - key.objectPtr = (uintptr_t)(void*)descriptor; + switch (watchType) { + case EWT_LEGACY_DESCRIPTOR: + key.objectPtr = (uintptr_t)(void*)watchObject.as_descriptor; + break; + case EWT_POSIX_FILE: + key.objectPtr = (uintptr_t)(void*)watchObject.as_file; + break; + default: + error("unrecognized watch type"); + return -ENOENT; + } EpollWatch* watch = g_hash_table_lookup(epoll->watching, &key); @@ -343,7 +423,7 @@ gint epoll_control(Epoll* epoll, gint operation, int fd, LegacyDescriptor* descr } /* start watching for status changes */ - watch = _epollwatch_new(epoll, fd, descriptor, event); + watch = _epollwatch_new(epoll, fd, watchType, watchObject, event); watch->flags |= EWF_WATCHING; gpointer new_key = _epollkey_new(key.fd, key.objectPtr); g_hash_table_replace(epoll->watching, new_key, watch); @@ -357,9 +437,13 @@ gint epoll_control(Epoll* epoll, gint operation, int fd, LegacyDescriptor* descr STATUS_DESCRIPTOR_READABLE | STATUS_DESCRIPTOR_WRITABLE, SLF_ALWAYS); - descriptor_addListener(watch->descriptor, watch->listener); + if (watch->watchType == EWT_LEGACY_DESCRIPTOR) { + descriptor_addListener(watch->watchObject.as_descriptor, watch->listener); + } else if (watch->watchType == EWT_POSIX_FILE) { + posixfile_addListener(watch->watchObject.as_file, watch->listener); + } - /* initiate a callback if the new watched descriptor is ready */ + /* initiate a callback if the new watched object is ready */ _epoll_descriptorStatusChanged(epoll, &key); break; @@ -380,7 +464,7 @@ gint epoll_control(Epoll* epoll, gint operation, int fd, LegacyDescriptor* descr watch->flags &= ~EWF_EDGETRIGGER_REPORTED; watch->flags &= ~EWF_ONESHOT_REPORTED; - /* initiate a callback if the new event type on the watched descriptor is ready */ + /* initiate a callback if the new event type on the watched object is ready */ _epoll_descriptorStatusChanged(epoll, &key); break; @@ -397,7 +481,11 @@ gint epoll_control(Epoll* epoll, gint operation, int fd, LegacyDescriptor* descr /* its deleted, so stop listening for updates */ statuslistener_setMonitorStatus(watch->listener, STATUS_NONE, SLF_NEVER); - descriptor_removeListener(watch->descriptor, watch->listener); + if (watch->watchType == EWT_LEGACY_DESCRIPTOR) { + descriptor_removeListener(watch->watchObject.as_descriptor, watch->listener); + } else if (watch->watchType == EWT_POSIX_FILE) { + posixfile_removeListener(watch->watchObject.as_file, watch->listener); + } /* unref gets called on the watch when it is removed from these tables */ g_hash_table_remove(epoll->ready, &key); diff --git a/src/main/host/descriptor/epoll.h b/src/main/host/descriptor/epoll.h index 06c72ea7f9..e37c28f252 100644 --- a/src/main/host/descriptor/epoll.h +++ b/src/main/host/descriptor/epoll.h @@ -17,7 +17,7 @@ typedef struct _Epoll Epoll; /* free this with descriptor_free() */ Epoll* epoll_new(); -gint epoll_control(Epoll* epoll, gint operation, int fd, LegacyDescriptor* descriptor, +gint epoll_control(Epoll* epoll, gint operation, int fd, CompatDescriptor* descriptor, const struct epoll_event* event); gint epoll_getEvents(Epoll* epoll, struct epoll_event* eventArray, gint eventArrayLength, gint* nEvents); diff --git a/src/main/host/syscall/epoll.c b/src/main/host/syscall/epoll.c index b6aba4781e..fc8259a50d 100644 --- a/src/main/host/syscall/epoll.c +++ b/src/main/host/syscall/epoll.c @@ -80,9 +80,8 @@ SysCallReturn syscallhandler_epoll_ctl(SysCallHandler* sys, } /* Get and check the epoll descriptor. */ - LegacyDescriptor* descriptor = - process_getRegisteredLegacyDescriptor(sys->process, epfd); - gint errorCode = _syscallhandler_validateDescriptor(descriptor, DT_EPOLL); + LegacyDescriptor* epollDescriptor = process_getRegisteredLegacyDescriptor(sys->process, epfd); + gint errorCode = _syscallhandler_validateDescriptor(epollDescriptor, DT_EPOLL); if (errorCode) { debug("Error when trying to validate epoll %i", epfd); @@ -91,17 +90,27 @@ SysCallReturn syscallhandler_epoll_ctl(SysCallHandler* sys, } /* It's now safe to cast. */ - Epoll* epoll = (Epoll*)descriptor; + Epoll* epoll = (Epoll*)epollDescriptor; utility_assert(epoll); /* Find the child descriptor that the epoll is monitoring. */ - descriptor = process_getRegisteredLegacyDescriptor(sys->process, fd); - errorCode = _syscallhandler_validateDescriptor(descriptor, DT_NONE); + CompatDescriptor* compatDescriptor = process_getRegisteredCompatDescriptor(sys->process, fd); - if (errorCode) { + if (compatDescriptor == NULL) { info("Child %i is not a shadow descriptor", fd); - return (SysCallReturn){ - .state = SYSCALL_DONE, .retval.as_i64 = errorCode}; + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EBADF}; + } + + LegacyDescriptor* legacyDescriptor = compatdescriptor_asLegacy(compatDescriptor); + + /* Validate only if a legacy descriptor */ + if (legacyDescriptor != NULL) { + errorCode = _syscallhandler_validateDescriptor(legacyDescriptor, DT_NONE); + + if (errorCode) { + info("Child %i is not a shadow descriptor", fd); + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = errorCode}; + } } const struct epoll_event* event = NULL; @@ -110,7 +119,7 @@ SysCallReturn syscallhandler_epoll_ctl(SysCallHandler* sys, } debug("Calling epoll_control on epoll %i with child %i", epfd, fd); - errorCode = epoll_control(epoll, op, fd, descriptor, event); + errorCode = epoll_control(epoll, op, fd, compatDescriptor, event); return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = errorCode}; } From d43b8fa7361f040b55c9fc78781503f1be4eed69 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Tue, 12 Jan 2021 13:29:58 -0500 Subject: [PATCH 09/13] Added Rust descriptor support to `SysCallCondition` Shadow syscalls can now block on Rust `PosixFile` objects. --- src/main/host/syscall_condition.c | 35 +++++++++++++++++++++++++++++++ src/main/host/syscall_condition.h | 2 ++ 2 files changed, 37 insertions(+) diff --git a/src/main/host/syscall_condition.c b/src/main/host/syscall_condition.c index 182fb3123a..611abe7b0d 100644 --- a/src/main/host/syscall_condition.c +++ b/src/main/host/syscall_condition.c @@ -57,6 +57,12 @@ SysCallCondition* syscallcondition_new(Trigger trigger, Timer* timeout) { descriptor_ref(cond->trigger.object.as_descriptor); return cond; } + case TRIGGER_POSIX_FILE: { + /* The file represents an Arc, so the reference count is fine; + * Just need to remember to drop it later. + */ + return cond; + } case TRIGGER_FUTEX: { futex_ref(cond->trigger.object.as_futex); return cond; @@ -96,6 +102,10 @@ static void _syscallcondition_cleanupListeners(SysCallCondition* cond) { cond->trigger.object.as_descriptor, cond->triggerListener); break; } + case TRIGGER_POSIX_FILE: { + posixfile_removeListener(cond->trigger.object.as_file, cond->triggerListener); + break; + } case TRIGGER_FUTEX: { futex_removeListener(cond->trigger.object.as_futex, cond->triggerListener); break; @@ -147,6 +157,10 @@ static void _syscallcondition_free(SysCallCondition* cond) { descriptor_unref(cond->trigger.object.as_descriptor); break; } + case TRIGGER_POSIX_FILE: { + posixfile_drop(cond->trigger.object.as_file); + break; + } case TRIGGER_FUTEX: { futex_unref(cond->trigger.object.as_futex); break; @@ -201,6 +215,12 @@ static void _syscallcondition_logListeningState(SysCallCondition* cond, cond->timeout ? " and " : ""); break; } + case TRIGGER_POSIX_FILE: { + g_string_append_printf(string, "status on posix file %p%s", + (void*)cond->trigger.object.as_file, + cond->timeout ? " and " : ""); + break; + } case TRIGGER_FUTEX: { g_string_append_printf(string, "status on futex %p%s", (void*)futex_getAddress(cond->trigger.object.as_futex).val, @@ -241,6 +261,12 @@ static bool _syscallcondition_statusIsValid(SysCallCondition* cond) { } break; } + case TRIGGER_POSIX_FILE: { + if (posixfile_getStatus(cond->trigger.object.as_file) & cond->trigger.status) { + return true; + } + break; + } case TRIGGER_FUTEX: { // Futex status doesn't change return true; @@ -376,6 +402,15 @@ void syscallcondition_waitNonblock(SysCallCondition* cond, Process* proc, descriptor_addListener(cond->trigger.object.as_descriptor, cond->triggerListener); break; } + case TRIGGER_POSIX_FILE: { + /* Monitor the requested status when it transitions from off to on. */ + statuslistener_setMonitorStatus( + cond->triggerListener, cond->trigger.status, SLF_OFF_TO_ON); + + /* Attach the listener to the descriptor. */ + posixfile_addListener(cond->trigger.object.as_file, cond->triggerListener); + break; + } case TRIGGER_FUTEX: { /* Monitor the requested status an every status change. */ statuslistener_setMonitorStatus( diff --git a/src/main/host/syscall_condition.h b/src/main/host/syscall_condition.h index c297dad768..d54506e699 100644 --- a/src/main/host/syscall_condition.h +++ b/src/main/host/syscall_condition.h @@ -19,6 +19,7 @@ typedef enum _TriggerType TriggerType; enum _TriggerType { TRIGGER_NONE, TRIGGER_DESCRIPTOR, + TRIGGER_POSIX_FILE, TRIGGER_FUTEX, }; @@ -27,6 +28,7 @@ typedef union _TriggerObject TriggerObject; union _TriggerObject { void* as_pointer; LegacyDescriptor* as_descriptor; + const PosixFileArc* as_file; Futex* as_futex; }; From 607ff065673a26631ead16cba8dd2e058230930a Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Wed, 13 Jan 2021 20:32:49 -0500 Subject: [PATCH 10/13] Added support for `pipe()` in Rust This commit implements a `FilePipe` type which supports the `pipe()` syscall completely in Rust. --- src/main/Cargo.toml | 1 + src/main/bindings/c/bindings.h | 13 + src/main/bindings/c/cbindgen.toml | 1 + src/main/bindings/rust/CMakeLists.txt | 17 ++ src/main/bindings/rust/wrapper.h | 2 + src/main/bindings/rust/wrapper.rs | 404 +++++++++++++++++++++++++- src/main/host/descriptor/mod.rs | 200 ++++++++++++- src/main/host/descriptor/pipe.rs | 280 ++++++++++++++++++ src/main/host/mod.rs | 3 +- src/main/host/syscall/mod.rs | 60 ++++ src/main/host/syscall/unistd.rs | 318 ++++++++++++++++++++ src/main/host/syscall_handler.c | 16 +- src/main/lib.rs | 2 + src/main/utility/byte_queue.rs | 12 + src/main/utility/event_queue.rs | 172 +++++++++++ src/main/utility/mod.rs | 1 + 16 files changed, 1485 insertions(+), 17 deletions(-) create mode 100644 src/main/host/descriptor/pipe.rs create mode 100644 src/main/host/syscall/mod.rs create mode 100644 src/main/host/syscall/unistd.rs create mode 100644 src/main/utility/event_queue.rs diff --git a/src/main/Cargo.toml b/src/main/Cargo.toml index 80181fd2ac..607b1ac0d8 100644 --- a/src/main/Cargo.toml +++ b/src/main/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["staticlib"] [dependencies] atomic_refcell = "0.1" +bitflags = "1.2" lazy_static = "1.4.0" libc = "0.2" log = "0.4" diff --git a/src/main/bindings/c/bindings.h b/src/main/bindings/c/bindings.h index b15d9e4683..0a13ffa4e5 100644 --- a/src/main/bindings/c/bindings.h +++ b/src/main/bindings/c/bindings.h @@ -17,6 +17,7 @@ #include "main/bindings/c/bindings-opaque.h" #include "main/host/descriptor/descriptor_types.h" #include "main/host/status_listener.h" +#include "main/host/syscall_handler.h" #include "main/host/syscall_types.h" #include "main/host/thread.h" @@ -132,10 +133,22 @@ SysCallReg memorymanager_handleMprotect(MemoryManager *memory_manager, uintptr_t size, int32_t prot); +SysCallReturn rustsyscallhandler_close(SysCallHandler *sys, const SysCallArgs *args); + +SysCallReturn rustsyscallhandler_read(SysCallHandler *sys, const SysCallArgs *args); + +SysCallReturn rustsyscallhandler_write(SysCallHandler *sys, const SysCallArgs *args); + +SysCallReturn rustsyscallhandler_pipe(SysCallHandler *sys, const SysCallArgs *args); + +SysCallReturn rustsyscallhandler_pipe2(SysCallHandler *sys, const SysCallArgs *args); + ByteQueue *bytequeue_new(size_t chunk_size); void bytequeue_free(ByteQueue *bq_ptr); +size_t bytequeue_len(ByteQueue *bq); + void bytequeue_push(ByteQueue *bq, const unsigned char *src, size_t len); size_t bytequeue_pop(ByteQueue *bq, unsigned char *dst, size_t len); diff --git a/src/main/bindings/c/cbindgen.toml b/src/main/bindings/c/cbindgen.toml index 6fdb6704ce..d98741685d 100644 --- a/src/main/bindings/c/cbindgen.toml +++ b/src/main/bindings/c/cbindgen.toml @@ -13,6 +13,7 @@ includes = [ "main/bindings/c/bindings-opaque.h", "main/host/descriptor/descriptor_types.h", "main/host/status_listener.h", + "main/host/syscall_handler.h", "main/host/syscall_types.h", "main/host/thread.h", ] diff --git a/src/main/bindings/rust/CMakeLists.txt b/src/main/bindings/rust/CMakeLists.txt index 1eaf24a1e1..9a7a333bc6 100644 --- a/src/main/bindings/rust/CMakeLists.txt +++ b/src/main/bindings/rust/CMakeLists.txt @@ -23,14 +23,31 @@ add_custom_command(OUTPUT wrapper.rs --whitelist-function "thread_.*" --whitelist-function "descriptor_unref" --whitelist-function "descriptor_setHandle" + --whitelist-function "process_.*CompatDescriptor" + --whitelist-function "process_get.*Ptr" + --whitelist-function "statuslistener_ref" + --whitelist-function "statuslistener_unref" + --whitelist-function "statuslistener_onStatusChanged" + --whitelist-function "syscallcondition_new" + --whitelist-function "syscallhandler_.*" + --blacklist-function "syscallhandler_new" + --blacklist-function "syscallhandler_ref" + --blacklist-function "syscallhandler_unref" + --blacklist-function "syscallhandler_make_syscall" --whitelist-type "PluginPtr" --whitelist-type "Status" --whitelist-type "StatusListener" --whitelist-type "SysCall.*" --whitelist-type "LegacyDescriptor" + --whitelist-type "Trigger" + --whitelist-type "TriggerType" + --whitelist-var "CONFIG_PIPE_BUFFER_SIZE" + --whitelist-var "SYSCALL_IO_BUFSIZE" --opaque-type "LegacyDescriptor" + --opaque-type "CompatDescriptor" --disable-header-comment --raw-line "/* automatically generated by rust-bindgen */" + --raw-line "use crate::host::descriptor::CompatDescriptor\;" ${CMAKE_CURRENT_SOURCE_DIR}/wrapper.h -o ${CMAKE_CURRENT_SOURCE_DIR}/wrapper.rs -- ${LLVM_FLAGS} MAIN_DEPENDENCY wrapper.h IMPLICIT_DEPENDS C wrapper.h) diff --git a/src/main/bindings/rust/wrapper.h b/src/main/bindings/rust/wrapper.h index 71b4dff4fd..6aa84fff6c 100644 --- a/src/main/bindings/rust/wrapper.h +++ b/src/main/bindings/rust/wrapper.h @@ -8,5 +8,7 @@ #include "main/host/descriptor/descriptor.h" #include "main/host/status.h" #include "main/host/status_listener.h" +#include "main/host/syscall_condition.h" #include "main/host/syscall_types.h" +#include "main/host/syscall/unistd.h" #include "main/host/thread.h" diff --git a/src/main/bindings/rust/wrapper.rs b/src/main/bindings/rust/wrapper.rs index da762aba84..b0c692bf35 100644 --- a/src/main/bindings/rust/wrapper.rs +++ b/src/main/bindings/rust/wrapper.rs @@ -1,5 +1,8 @@ /* automatically generated by rust-bindgen */ +use crate::host::descriptor::CompatDescriptor; +pub const CONFIG_PIPE_BUFFER_SIZE: u32 = 65536; +pub const SYSCALL_IO_BUFSIZE: u32 = 16384; pub type size_t = ::std::os::raw::c_ulong; pub type __uint32_t = ::std::os::raw::c_uint; pub type __int64_t = ::std::os::raw::c_long; @@ -7,7 +10,14 @@ pub type __uint64_t = ::std::os::raw::c_ulong; pub type __pid_t = ::std::os::raw::c_int; pub type pid_t = __pid_t; pub type gint = ::std::os::raw::c_int; +pub type gdouble = f64; pub type gpointer = *mut ::std::os::raw::c_void; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _GTimer { + _unused: [u8; 0], +} +pub type GTimer = _GTimer; pub use self::_Status as Status; pub const _Status_STATUS_NONE: _Status = 0; pub const _Status_STATUS_DESCRIPTOR_ACTIVE: _Status = 1; @@ -16,13 +26,44 @@ pub const _Status_STATUS_DESCRIPTOR_WRITABLE: _Status = 4; pub const _Status_STATUS_DESCRIPTOR_CLOSED: _Status = 8; pub const _Status_STATUS_FUTEX_WAKEUP: _Status = 16; pub type _Status = i32; -pub type LegacyDescriptor = [u64; 7usize]; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _Process { + _unused: [u8; 0], +} +pub type Process = _Process; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _Host { + _unused: [u8; 0], +} +pub type Host = _Host; +pub type LegacyDescriptor = [u64; 6usize]; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PosixFileArc { + _unused: [u8; 0], +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _StatusListener { _unused: [u8; 0], } pub type StatusListener = _StatusListener; +extern "C" { + pub fn statuslistener_ref(listener: *mut StatusListener); +} +extern "C" { + pub fn statuslistener_unref(listener: *mut StatusListener); +} +extern "C" { + pub fn statuslistener_onStatusChanged( + listener: *mut StatusListener, + currentStatus: Status, + transitions: Status, + ); +} +pub type SysCallHandler = _SysCallHandler; pub type PluginVirtualPtr = _PluginVirtualPtr; pub type PluginPtr = _PluginVirtualPtr; #[repr(C)] @@ -208,6 +249,12 @@ fn bindgen_test_layout__SysCallReturn() { pub type SysCallReturn = _SysCallReturn; #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct _Futex { + _unused: [u8; 0], +} +pub type Futex = _Futex; +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct _Thread { _unused: [u8; 0], } @@ -320,13 +367,364 @@ extern "C" { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct _SysCallHandler { +pub struct _Timer { _unused: [u8; 0], } -pub type SysCallHandler = _SysCallHandler; +pub type Timer = _Timer; +extern "C" { + pub fn process_registerCompatDescriptor( + proc_: *mut Process, + compatDesc: *mut CompatDescriptor, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn process_deregisterCompatDescriptor(proc_: *mut Process, handle: ::std::os::raw::c_int); +} +extern "C" { + pub fn process_getRegisteredCompatDescriptor( + proc_: *mut Process, + handle: ::std::os::raw::c_int, + ) -> *mut CompatDescriptor; +} +extern "C" { + pub fn process_getReadablePtr( + proc_: *mut Process, + thread: *mut Thread, + plugin_src: PluginPtr, + n: size_t, + ) -> *const ::std::os::raw::c_void; +} +extern "C" { + pub fn process_getWriteablePtr( + proc_: *mut Process, + thread: *mut Thread, + plugin_src: PluginPtr, + n: size_t, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn process_getMutablePtr( + proc_: *mut Process, + thread: *mut Thread, + plugin_src: PluginPtr, + n: size_t, + ) -> *mut ::std::os::raw::c_void; +} extern "C" { pub fn descriptor_unref(data: gpointer); } extern "C" { pub fn descriptor_setHandle(descriptor: *mut LegacyDescriptor, handle: gint); } +pub use self::_TriggerType as TriggerType; +pub const _TriggerType_TRIGGER_NONE: _TriggerType = 0; +pub const _TriggerType_TRIGGER_DESCRIPTOR: _TriggerType = 1; +pub const _TriggerType_TRIGGER_POSIX_FILE: _TriggerType = 2; +pub const _TriggerType_TRIGGER_FUTEX: _TriggerType = 3; +pub type _TriggerType = i32; +pub type TriggerObject = _TriggerObject; +#[repr(C)] +#[derive(Copy, Clone)] +pub union _TriggerObject { + pub as_pointer: *mut ::std::os::raw::c_void, + pub as_descriptor: *mut LegacyDescriptor, + pub as_file: *const PosixFileArc, + pub as_futex: *mut Futex, + _bindgen_union_align: u64, +} +#[test] +fn bindgen_test_layout__TriggerObject() { + assert_eq!( + ::std::mem::size_of::<_TriggerObject>(), + 8usize, + concat!("Size of: ", stringify!(_TriggerObject)) + ); + assert_eq!( + ::std::mem::align_of::<_TriggerObject>(), + 8usize, + concat!("Alignment of ", stringify!(_TriggerObject)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_TriggerObject>())).as_pointer as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_TriggerObject), + "::", + stringify!(as_pointer) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_TriggerObject>())).as_descriptor as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_TriggerObject), + "::", + stringify!(as_descriptor) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_TriggerObject>())).as_file as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_TriggerObject), + "::", + stringify!(as_file) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_TriggerObject>())).as_futex as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_TriggerObject), + "::", + stringify!(as_futex) + ) + ); +} +pub type Trigger = _Trigger; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct _Trigger { + pub type_: TriggerType, + pub object: TriggerObject, + pub status: Status, +} +#[test] +fn bindgen_test_layout__Trigger() { + assert_eq!( + ::std::mem::size_of::<_Trigger>(), + 24usize, + concat!("Size of: ", stringify!(_Trigger)) + ); + assert_eq!( + ::std::mem::align_of::<_Trigger>(), + 8usize, + concat!("Alignment of ", stringify!(_Trigger)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_Trigger>())).type_ as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Trigger), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_Trigger>())).object as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_Trigger), + "::", + stringify!(object) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_Trigger>())).status as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_Trigger), + "::", + stringify!(status) + ) + ); +} +extern "C" { + pub fn syscallcondition_new(trigger: Trigger, timeout: *mut Timer) -> *mut SysCallCondition; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SysCallHandler { + pub host: *mut Host, + pub process: *mut Process, + pub thread: *mut Thread, + pub timer: *mut Timer, + pub blockedSyscallNR: ::std::os::raw::c_long, + pub perfTimer: *mut GTimer, + pub perfSecondsCurrent: gdouble, + pub perfSecondsTotal: gdouble, + pub numSyscalls: ::std::os::raw::c_long, + pub referenceCount: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout__SysCallHandler() { + assert_eq!( + ::std::mem::size_of::<_SysCallHandler>(), + 80usize, + concat!("Size of: ", stringify!(_SysCallHandler)) + ); + assert_eq!( + ::std::mem::align_of::<_SysCallHandler>(), + 8usize, + concat!("Alignment of ", stringify!(_SysCallHandler)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_SysCallHandler>())).host as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(host) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_SysCallHandler>())).process as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(process) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_SysCallHandler>())).thread as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(thread) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_SysCallHandler>())).timer as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(timer) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<_SysCallHandler>())).blockedSyscallNR as *const _ as usize + }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(blockedSyscallNR) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_SysCallHandler>())).perfTimer as *const _ as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(perfTimer) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<_SysCallHandler>())).perfSecondsCurrent as *const _ as usize + }, + 48usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(perfSecondsCurrent) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<_SysCallHandler>())).perfSecondsTotal as *const _ as usize + }, + 56usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(perfSecondsTotal) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_SysCallHandler>())).numSyscalls as *const _ as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(numSyscalls) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_SysCallHandler>())).referenceCount as *const _ as usize }, + 72usize, + concat!( + "Offset of field: ", + stringify!(_SysCallHandler), + "::", + stringify!(referenceCount) + ) + ); +} +extern "C" { + pub fn syscallhandler_close( + sys: *mut SysCallHandler, + args: *const SysCallArgs, + ) -> SysCallReturn; +} +extern "C" { + pub fn syscallhandler_getpid( + sys: *mut SysCallHandler, + args: *const SysCallArgs, + ) -> SysCallReturn; +} +extern "C" { + pub fn syscallhandler_pipe(sys: *mut SysCallHandler, args: *const SysCallArgs) + -> SysCallReturn; +} +extern "C" { + pub fn syscallhandler_pipe2( + sys: *mut SysCallHandler, + args: *const SysCallArgs, + ) -> SysCallReturn; +} +extern "C" { + pub fn syscallhandler_pread64( + sys: *mut SysCallHandler, + args: *const SysCallArgs, + ) -> SysCallReturn; +} +extern "C" { + pub fn syscallhandler_pwrite64( + sys: *mut SysCallHandler, + args: *const SysCallArgs, + ) -> SysCallReturn; +} +extern "C" { + pub fn syscallhandler_read(sys: *mut SysCallHandler, args: *const SysCallArgs) + -> SysCallReturn; +} +extern "C" { + pub fn syscallhandler_set_tid_address( + sys: *mut SysCallHandler, + args: *const SysCallArgs, + ) -> SysCallReturn; +} +extern "C" { + pub fn syscallhandler_uname( + sys: *mut SysCallHandler, + args: *const SysCallArgs, + ) -> SysCallReturn; +} +extern "C" { + pub fn syscallhandler_write( + sys: *mut SysCallHandler, + args: *const SysCallArgs, + ) -> SysCallReturn; +} diff --git a/src/main/host/descriptor/mod.rs b/src/main/host/descriptor/mod.rs index f74ee25dca..494a9bad9c 100644 --- a/src/main/host/descriptor/mod.rs +++ b/src/main/host/descriptor/mod.rs @@ -2,6 +2,9 @@ use atomic_refcell::AtomicRefCell; use std::sync::Arc; use crate::cshadow as c; +use crate::utility::event_queue::{EventQueue, EventSource, Handle}; + +pub mod pipe; /// A trait we can use as a compile-time check to make sure that an object is Send. trait IsSend: Send {} @@ -29,19 +32,203 @@ impl SyncSendPointer { } } -pub enum PosixFile {} +#[derive(PartialEq)] +pub enum SyscallReturn { + Success(i32), + Error(nix::errno::Errno), +} + +bitflags::bitflags! { + // file modes: https://github.com/torvalds/linux/blob/master/include/linux/fs.h#L111 + pub struct FileMode: u32 { + const READ = 0b00000001; + const WRITE = 0b00000010; + } +} + +#[derive(Clone)] +pub enum NewStatusListenerFilter { + Never, + OffToOn, + OnToOff, + Always, +} + +/// A wrapper for a `*mut c::StatusListener` that increments its ref count when created, +/// and decrements when dropped. +struct LegacyStatusListener(SyncSendPointer); + +impl LegacyStatusListener { + fn new(ptr: *mut c::StatusListener) -> Self { + assert!(!ptr.is_null()); + unsafe { c::statuslistener_ref(ptr) }; + Self(SyncSendPointer(ptr)) + } + + fn ptr(&self) -> *mut c::StatusListener { + self.0.ptr() + } +} + +impl Drop for LegacyStatusListener { + fn drop(&mut self) { + unsafe { c::statuslistener_unref(self.0.ptr()) }; + } +} + +/// Stores event listener handles so that `c::StatusListener` objects can subscribe to events. +struct LegacyListenerHelper { + handle_map: std::collections::HashMap>, +} + +impl LegacyListenerHelper { + fn new() -> Self { + Self { + handle_map: std::collections::HashMap::new(), + } + } + + fn add_listener( + &mut self, + ptr: *mut c::StatusListener, + event_source: &mut EventSource<(c::Status, c::Status)>, + ) { + assert!(!ptr.is_null()); + + // if it's already listening, don't add a second time + if self.handle_map.contains_key(&(ptr as usize)) { + return; + } + + // this will ref the pointer and unref it when the closure is dropped + let ptr_wrapper = LegacyStatusListener::new(ptr); + + let handle = event_source.add_listener(move |(status, changed), _event_queue| unsafe { + c::statuslistener_onStatusChanged(ptr_wrapper.ptr(), status, changed) + }); + + // use a usize as the key so we don't accidentally deref the pointer + self.handle_map.insert(ptr as usize, handle); + } + + fn remove_listener(&mut self, ptr: *mut c::StatusListener) { + assert!(!ptr.is_null()); + self.handle_map.remove(&(ptr as usize)); + } +} + +/// A specified event source that passes a status and the changed bits to the function, but only if +/// the monitored bits have changed and if the change the filter is satisfied. +struct StatusEventSource { + inner: EventSource<(c::Status, c::Status)>, + legacy_helper: LegacyListenerHelper, +} + +impl StatusEventSource { + pub fn new() -> Self { + Self { + inner: EventSource::new(), + legacy_helper: LegacyListenerHelper::new(), + } + } + + pub fn add_listener( + &mut self, + monitoring: c::Status, + filter: NewStatusListenerFilter, + notify_fn: impl Fn(c::Status, c::Status, &mut EventQueue) + Send + Sync + 'static, + ) -> Handle<(c::Status, c::Status)> { + self.inner + .add_listener(move |(status, changed), event_queue| { + // true if any of the bits we're monitoring have changed + let flipped = monitoring & changed != 0; + + // true if any of the bits we're monitoring are set + let on = monitoring & status != 0; + + let notify = match filter { + // at least one monitored bit is on, and at least one has changed + NewStatusListenerFilter::OffToOn => flipped && on, + // all monitored bits are off, and at least one has changed + NewStatusListenerFilter::OnToOff => flipped && !on, + // at least one monitored bit has changed + NewStatusListenerFilter::Always => flipped, + NewStatusListenerFilter::Never => false, + }; + + if !notify { + return; + } + + (notify_fn)(status, changed, event_queue) + }) + } + + pub fn add_legacy_listener(&mut self, ptr: *mut c::StatusListener) { + self.legacy_helper.add_listener(ptr, &mut self.inner); + } + + pub fn remove_legacy_listener(&mut self, ptr: *mut c::StatusListener) { + self.legacy_helper.remove_listener(ptr); + } + + pub fn notify_listeners( + &mut self, + status: c::Status, + changed: c::Status, + event_queue: &mut EventQueue, + ) { + self.inner.notify_listeners((status, changed), event_queue) + } +} + +/// Represents a POSIX description, or a Linux "struct file". +pub enum PosixFile { + Pipe(pipe::PipeFile), +} // will not compile if `PosixFile` is not Send + Sync impl IsSend for PosixFile {} impl IsSync for PosixFile {} +impl PosixFile { + pub fn read(&mut self, bytes: &mut [u8], event_queue: &mut EventQueue) -> SyscallReturn { + match self { + Self::Pipe(f) => f.read(bytes, event_queue), + } + } + + pub fn write(&mut self, bytes: &[u8], event_queue: &mut EventQueue) -> SyscallReturn { + match self { + Self::Pipe(f) => f.write(bytes, event_queue), + } + } + + pub fn status(&self) -> c::Status { + match self { + Self::Pipe(f) => f.status(), + } + } + + pub fn add_legacy_listener(&mut self, ptr: *mut c::StatusListener) { + match self { + Self::Pipe(f) => f.add_legacy_listener(ptr), + } + } + + pub fn remove_legacy_listener(&mut self, ptr: *mut c::StatusListener) { + match self { + Self::Pipe(f) => f.remove_legacy_listener(ptr), + } + } +} + #[derive(Clone)] pub struct Descriptor { file: Arc>, flags: i32, } -#[allow(dead_code)] impl Descriptor { pub fn new(file: Arc>) -> Self { Self { file, flags: 0 } @@ -65,7 +252,6 @@ impl Descriptor { } // don't implement copy or clone without considering the legacy descriptor's ref count -#[allow(dead_code)] pub enum CompatDescriptor { New(Descriptor), Legacy(SyncSendPointer), @@ -204,13 +390,12 @@ mod export { let file = file as *const AtomicRefCell; let file = unsafe { &*file }; - todo!(); + file.borrow().status() } /// Add a status listener to the posix file object. This will increment the status /// listener's ref count, and will decrement the ref count when this status listener is /// removed or when the posix file is freed/dropped. - #[allow(unused_variables)] #[no_mangle] pub extern "C" fn posixfile_addListener( file: *const PosixFileArc, @@ -222,11 +407,10 @@ mod export { let file = file as *const AtomicRefCell; let file = unsafe { &*file }; - todo!(); + file.borrow_mut().add_legacy_listener(listener); } /// Remove a listener from the posix file object. - #[allow(unused_variables)] #[no_mangle] pub extern "C" fn posixfile_removeListener( file: *const PosixFileArc, @@ -238,6 +422,6 @@ mod export { let file = file as *const AtomicRefCell; let file = unsafe { &*file }; - todo!(); + file.borrow_mut().remove_legacy_listener(listener); } } diff --git a/src/main/host/descriptor/pipe.rs b/src/main/host/descriptor/pipe.rs new file mode 100644 index 0000000000..2aeb12dae1 --- /dev/null +++ b/src/main/host/descriptor/pipe.rs @@ -0,0 +1,280 @@ +use atomic_refcell::AtomicRefCell; +use std::sync::Arc; + +use crate::cshadow as c; +use crate::host::descriptor::{ + FileMode, NewStatusListenerFilter, PosixFile, StatusEventSource, SyscallReturn, +}; +use crate::utility::byte_queue::ByteQueue; +use crate::utility::event_queue::{EventQueue, Handle}; + +pub struct PipeFile { + buffer: Arc>, + event_source: StatusEventSource, + status: c::Status, + mode: FileMode, + buffer_event_handle: Option>, +} + +impl PipeFile { + pub fn new(buffer: Arc>, mode: FileMode) -> Self { + let mut rv = Self { + buffer, + event_source: StatusEventSource::new(), + status: c::_Status_STATUS_NONE, + mode, + buffer_event_handle: None, + }; + + rv.status = rv.filter_status(rv.buffer.borrow_mut().status()); + + rv + } + + pub fn read(&mut self, bytes: &mut [u8], event_queue: &mut EventQueue) -> SyscallReturn { + // if the file is not open for reading, return EBADF + if !self.mode.contains(FileMode::READ) { + return SyscallReturn::Error(nix::errno::Errno::EBADF); + } + + let num_read = { + let mut buffer = self.buffer.borrow_mut(); + buffer.read(bytes, event_queue) + }; + + SyscallReturn::Success(num_read as i32) + } + + pub fn write(&mut self, bytes: &[u8], event_queue: &mut EventQueue) -> SyscallReturn { + // if the file is not open for writing, return EBADF + if !self.mode.contains(FileMode::WRITE) { + return SyscallReturn::Error(nix::errno::Errno::EBADF); + } + + let count = { + let mut buffer = self.buffer.borrow_mut(); + buffer.write(bytes, event_queue) + }; + + // the write would block if we could not write any bytes, but were asked to + if count == 0 && bytes.len() > 0 { + SyscallReturn::Error(nix::errno::EWOULDBLOCK) + } else { + SyscallReturn::Success(count as i32) + } + } + + pub fn enable_notifications(arc: &Arc>) { + // we remove some of these later in this function + let monitoring = c::_Status_STATUS_DESCRIPTOR_ACTIVE + | c::_Status_STATUS_DESCRIPTOR_CLOSED + | c::_Status_STATUS_DESCRIPTOR_READABLE + | c::_Status_STATUS_DESCRIPTOR_WRITABLE; + + let weak = Arc::downgrade(arc); + match *arc.borrow_mut() { + PosixFile::Pipe(ref mut f) => { + // remove any status flags that aren't relevant to us + let monitoring = f.filter_status(monitoring); + + f.buffer_event_handle = Some(f.buffer.borrow_mut().add_listener( + monitoring, + NewStatusListenerFilter::Always, + move |status, _changed, event_queue| { + // if the file hasn't been dropped + if let Some(file) = weak.upgrade() { + let mut file = file.borrow_mut(); + match *file { + PosixFile::Pipe(ref mut f) => { + f.adjust_status(status, true, event_queue) + } + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } + }, + )); + } + #[allow(unreachable_patterns)] + _ => unreachable!(), + }; + } + + pub fn add_listener( + &mut self, + monitoring: c::Status, + filter: NewStatusListenerFilter, + notify_fn: impl Fn(c::Status, c::Status, &mut EventQueue) + Send + Sync + 'static, + ) -> Handle<(c::Status, c::Status)> { + self.event_source + .add_listener(monitoring, filter, notify_fn) + } + + pub fn add_legacy_listener(&mut self, ptr: *mut c::StatusListener) { + self.event_source.add_legacy_listener(ptr); + } + + pub fn remove_legacy_listener(&mut self, ptr: *mut c::StatusListener) { + self.event_source.remove_legacy_listener(ptr); + } + + pub fn status(&self) -> c::Status { + self.status + } + + fn filter_status(&self, mut status: c::Status) -> c::Status { + // if not open for reading + if !self.mode.contains(FileMode::READ) { + // remove the readable flag + status &= !c::_Status_STATUS_DESCRIPTOR_READABLE; + } + + // if not open for writing + if !self.mode.contains(FileMode::WRITE) { + // remove the writable flag + status &= !c::_Status_STATUS_DESCRIPTOR_WRITABLE; + } + + status + } + + pub fn adjust_status( + &mut self, + status: c::Status, + do_set_bits: bool, + event_queue: &mut EventQueue, + ) { + let old_status = self.status; + + // remove any flags that aren't relevant + let status = self.filter_status(status); + + if do_set_bits { + self.status |= status; + } else { + self.status &= !status; + } + + self.handle_status_change(old_status, event_queue); + } + + fn handle_status_change(&mut self, old_status: c::Status, event_queue: &mut EventQueue) { + let statuses_changed = self.status ^ old_status; + + // if nothing changed + if statuses_changed == 0 { + return; + } + + self.event_source + .notify_listeners(self.status, statuses_changed, event_queue); + } +} + +pub struct SharedBuf { + queue: ByteQueue, + max_len: usize, + status: c::Status, + event_source: StatusEventSource, +} + +impl SharedBuf { + pub fn new() -> Self { + Self { + queue: ByteQueue::new(8192), + max_len: c::CONFIG_PIPE_BUFFER_SIZE as usize, + status: c::_Status_STATUS_DESCRIPTOR_ACTIVE | c::_Status_STATUS_DESCRIPTOR_WRITABLE, + event_source: StatusEventSource::new(), + } + } + + pub fn is_empty(&self) -> bool { + self.queue.len() == 0 + } + + pub fn space_available(&self) -> usize { + self.max_len - self.queue.len() + } + + pub fn read(&mut self, bytes: &mut [u8], event_queue: &mut EventQueue) -> usize { + let num = self.queue.pop(bytes); + + // readable if not empty + self.adjust_status( + c::_Status_STATUS_DESCRIPTOR_READABLE, + !self.is_empty(), + event_queue, + ); + + // writable if space is available + self.adjust_status( + c::_Status_STATUS_DESCRIPTOR_WRITABLE, + self.space_available() > 0, + event_queue, + ); + + num + } + + pub fn write(&mut self, bytes: &[u8], event_queue: &mut EventQueue) -> usize { + let available = self.space_available(); + let writable = &bytes[..std::cmp::min(bytes.len(), available)]; + self.queue.push(writable); + + self.adjust_status( + c::_Status_STATUS_DESCRIPTOR_READABLE, + !self.is_empty(), + event_queue, + ); + self.adjust_status( + c::_Status_STATUS_DESCRIPTOR_WRITABLE, + self.space_available() > 0, + event_queue, + ); + + writable.len() + } + + pub fn add_listener( + &mut self, + monitoring: c::Status, + filter: NewStatusListenerFilter, + notify_fn: impl Fn(c::Status, c::Status, &mut EventQueue) + Send + Sync + 'static, + ) -> Handle<(c::Status, c::Status)> { + self.event_source + .add_listener(monitoring, filter, notify_fn) + } + + pub fn status(&self) -> c::Status { + self.status + } + + fn adjust_status( + &mut self, + status: c::Status, + do_set_bits: bool, + event_queue: &mut EventQueue, + ) { + let old_status = self.status; + + if do_set_bits { + self.status |= status; + } else { + self.status &= !status; + } + + self.handle_status_change(old_status, event_queue); + } + + fn handle_status_change(&mut self, old_status: c::Status, event_queue: &mut EventQueue) { + let statuses_changed = self.status ^ old_status; + + // if nothing changed + if statuses_changed == 0 { + return; + } + + self.event_source + .notify_listeners(self.status, statuses_changed, event_queue); + } +} diff --git a/src/main/host/mod.rs b/src/main/host/mod.rs index 607a708e11..1ffc2713ce 100644 --- a/src/main/host/mod.rs +++ b/src/main/host/mod.rs @@ -1,4 +1,5 @@ -mod descriptor; +pub mod descriptor; mod memory_manager; +pub mod syscall; pub mod syscall_types; pub mod thread; diff --git a/src/main/host/syscall/mod.rs b/src/main/host/syscall/mod.rs new file mode 100644 index 0000000000..a7413b302c --- /dev/null +++ b/src/main/host/syscall/mod.rs @@ -0,0 +1,60 @@ +use atomic_refcell::AtomicRefCell; +use std::sync::Arc; + +use crate::cshadow as c; +use crate::host::descriptor::{CompatDescriptor, PosixFile}; + +pub mod unistd; + +impl c::Trigger { + pub fn from_posix_file(file: &Arc>, status: c::Status) -> Self { + let file_ptr = Arc::into_raw(Arc::clone(file)); + + Self { + type_: c::_TriggerType_TRIGGER_POSIX_FILE, + object: c::TriggerObject { + as_file: file_ptr as *const c::PosixFileArc, + }, + status, + } + } +} + +impl c::SysCallReturn { + pub fn from_errno(errno: nix::errno::Errno) -> Self { + Self { + state: c::SysCallReturnState_SYSCALL_DONE, + retval: c::SysCallReg { + as_i64: -(errno as i64), + }, + cond: std::ptr::null_mut(), + } + } + + pub fn from_int(int: i64) -> Self { + Self { + state: c::SysCallReturnState_SYSCALL_DONE, + retval: c::SysCallReg { as_i64: int }, + cond: std::ptr::null_mut(), + } + } +} + +/// Returns a pointer to the `CompatDescriptor` for the fd. The pointer will never be NULL. +pub fn get_descriptor( + fd: libc::c_int, + process: *mut c::Process, +) -> Result<*mut CompatDescriptor, nix::errno::Errno> { + // check that fd is within bounds + if fd < 0 { + return Err(nix::errno::Errno::EBADF); + } + + // check that the fd exists + let desc = unsafe { c::process_getRegisteredCompatDescriptor(process, fd) }; + if desc.is_null() { + return Err(nix::errno::Errno::EBADF); + } + + Ok(desc) +} diff --git a/src/main/host/syscall/unistd.rs b/src/main/host/syscall/unistd.rs new file mode 100644 index 0000000000..3ff458d9f5 --- /dev/null +++ b/src/main/host/syscall/unistd.rs @@ -0,0 +1,318 @@ +use crate::cshadow as c; +use crate::host::descriptor::pipe; +use crate::host::descriptor::{CompatDescriptor, Descriptor, FileMode, PosixFile, SyscallReturn}; +use crate::host::syscall; +use crate::utility::event_queue::EventQueue; + +use std::sync::Arc; + +use atomic_refcell::AtomicRefCell; +use log::*; + +pub fn close(sys: &mut c::SysCallHandler, args: &c::SysCallArgs) -> c::SysCallReturn { + let fd = unsafe { args.args[0].as_i64 } as libc::c_int; + + debug!("Trying to close fd {}", fd); + + // scope used to make sure that desc cannot be used after deregistering it + { + // get the descriptor, or return early if it doesn't exist + let desc = match syscall::get_descriptor(fd, sys.process) { + Ok(d) => unsafe { &mut *d }, + Err(errno) => return c::SysCallReturn::from_errno(errno), + }; + + // if it's a legacy descriptor, use the C syscall handler instead + if let CompatDescriptor::Legacy(_) = desc { + return unsafe { + c::syscallhandler_close( + sys as *mut c::SysCallHandler, + args as *const c::SysCallArgs, + ) + }; + } + } + + unsafe { c::process_deregisterCompatDescriptor(sys.process, fd) }; + + c::SysCallReturn::from_int(0) +} + +pub fn read(sys: &mut c::SysCallHandler, args: &c::SysCallArgs) -> c::SysCallReturn { + let fd = unsafe { args.args[0].as_i64 } as libc::c_int; + let buf_ptr = unsafe { args.args[1].as_ptr }; + let buf_size = unsafe { args.args[2].as_u64 } as libc::size_t; + let offset = 0 as libc::off_t; + + read_helper(sys, args, fd, buf_ptr, buf_size, offset) +} + +fn read_helper( + sys: &mut c::SysCallHandler, + args: &c::SysCallArgs, + fd: libc::c_int, + buf_ptr: c::PluginPtr, + buf_size: libc::size_t, + _offset: libc::off_t, +) -> c::SysCallReturn { + // get the descriptor, or return early if it doesn't exist + let desc = match syscall::get_descriptor(fd, sys.process) { + Ok(d) => unsafe { &mut *d }, + Err(errno) => return c::SysCallReturn::from_errno(errno), + }; + + // if it's a legacy descriptor, use the C syscall handler instead + let desc = match desc { + CompatDescriptor::New(d) => d, + CompatDescriptor::Legacy(_) => unsafe { + return c::syscallhandler_read( + sys as *mut c::SysCallHandler, + args as *const c::SysCallArgs, + ); + }, + }; + + // need a non-null buffer + if buf_ptr.val == 0 { + return c::SysCallReturn::from_errno(nix::errno::Errno::EFAULT); + } + + // need a non-zero size + if buf_size == 0 { + info!("Invalid length {} provided on descriptor {}", buf_size, fd); + return c::SysCallReturn::from_errno(nix::errno::Errno::EINVAL); + } + + // TODO: dynamically compute size based on how much data is actually available in the descriptor + let size_needed = std::cmp::min(buf_size, c::SYSCALL_IO_BUFSIZE as usize); + + let buf_ptr = + unsafe { c::process_getWriteablePtr(sys.process, sys.thread, buf_ptr, size_needed as u64) }; + let mut buf = unsafe { std::slice::from_raw_parts_mut(buf_ptr as *mut u8, size_needed) }; + + // call the file's read(), and run any resulting events + let result = EventQueue::queue_and_run(|event_queue| { + desc.get_file().borrow_mut().read(&mut buf, event_queue) + }); + + // if the syscall would block and it's a blocking descriptor + if result == SyscallReturn::Error(nix::errno::EWOULDBLOCK) + && (desc.get_flags() & libc::O_NONBLOCK) == 0 + { + let trigger = + c::Trigger::from_posix_file(desc.get_file(), c::_Status_STATUS_DESCRIPTOR_READABLE); + + return c::SysCallReturn { + state: c::SysCallReturnState_SYSCALL_BLOCK, + retval: c::SysCallReg { as_i64: 0i64 }, + cond: unsafe { c::syscallcondition_new(trigger, std::ptr::null_mut()) }, + }; + } + + match result { + SyscallReturn::Success(x) => c::SysCallReturn::from_int(x as i64), + SyscallReturn::Error(x) => c::SysCallReturn::from_errno(x), + } +} + +pub fn write(sys: &mut c::SysCallHandler, args: &c::SysCallArgs) -> c::SysCallReturn { + let fd = unsafe { args.args[0].as_i64 } as libc::c_int; + let buf_ptr = unsafe { args.args[1].as_ptr }; + let buf_size = unsafe { args.args[2].as_u64 } as libc::size_t; + let offset = 0 as libc::off_t; + + write_helper(sys, args, fd, buf_ptr, buf_size, offset) +} + +fn write_helper( + sys: &mut c::SysCallHandler, + args: &c::SysCallArgs, + fd: libc::c_int, + buf_ptr: c::PluginPtr, + buf_size: libc::size_t, + _offset: libc::off_t, +) -> c::SysCallReturn { + // get the descriptor, or return early if it doesn't exist + let desc = match syscall::get_descriptor(fd, sys.process) { + Ok(d) => unsafe { &mut *d }, + Err(errno) => return c::SysCallReturn::from_errno(errno), + }; + + // if it's a legacy descriptor, use the C syscall handler instead + let desc = match desc { + CompatDescriptor::New(d) => d, + CompatDescriptor::Legacy(_) => unsafe { + return c::syscallhandler_write( + sys as *mut c::SysCallHandler, + args as *const c::SysCallArgs, + ); + }, + }; + + // need a non-null buffer + if buf_ptr.val == 0 { + return c::SysCallReturn::from_errno(nix::errno::Errno::EFAULT); + } + + // TODO: dynamically compute size based on how much data is actually available in the descriptor + let size_needed = std::cmp::min(buf_size, c::SYSCALL_IO_BUFSIZE as usize); + + let buf_ptr = + unsafe { c::process_getReadablePtr(sys.process, sys.thread, buf_ptr, size_needed as u64) }; + let buf = unsafe { std::slice::from_raw_parts(buf_ptr as *const u8, size_needed) }; + + // call the file's write(), and run any resulting events + let result = EventQueue::queue_and_run(|event_queue| { + desc.get_file().borrow_mut().write(&buf, event_queue) + }); + + // if the syscall would block and it's a blocking descriptor + if result == SyscallReturn::Error(nix::errno::EWOULDBLOCK) + && (desc.get_flags() & libc::O_NONBLOCK) == 0 + { + let trigger = + c::Trigger::from_posix_file(desc.get_file(), c::_Status_STATUS_DESCRIPTOR_WRITABLE); + + return c::SysCallReturn { + state: c::SysCallReturnState_SYSCALL_BLOCK, + retval: c::SysCallReg { as_i64: 0i64 }, + cond: unsafe { c::syscallcondition_new(trigger, std::ptr::null_mut()) }, + }; + } + + match result { + SyscallReturn::Success(x) => c::SysCallReturn::from_int(x as i64), + SyscallReturn::Error(x) => c::SysCallReturn::from_errno(x), + } +} + +pub fn pipe(sys: &mut c::SysCallHandler, args: &c::SysCallArgs) -> c::SysCallReturn { + let fd_ptr = unsafe { args.args[0].as_ptr }; + + pipe_helper(sys, fd_ptr, 0) +} + +pub fn pipe2(sys: &mut c::SysCallHandler, args: &c::SysCallArgs) -> c::SysCallReturn { + let fd_ptr = unsafe { args.args[0].as_ptr }; + let flags = unsafe { args.args[1].as_u64 } as libc::c_int; + + pipe_helper(sys, fd_ptr, flags) +} + +fn pipe_helper(sys: &mut c::SysCallHandler, fd_ptr: c::PluginPtr, flags: i32) -> c::SysCallReturn { + // make sure they didn't pass a NULL pointer + if fd_ptr.val == 0 { + return c::SysCallReturn::from_errno(nix::errno::Errno::EFAULT); + } + + // pipe flags that we support + let supported_flags = libc::O_NONBLOCK & libc::O_CLOEXEC; + let flags_to_set = flags & supported_flags; + + // the user requested flags that we don't support + if flags != flags_to_set { + // exit early if the O_DIRECT flag was set + if flags & libc::O_DIRECT != 0 { + warn!("We don't currently support pipes in 'O_DIRECT' mode"); + return c::SysCallReturn::from_errno(nix::errno::Errno::EOPNOTSUPP); + } + warn!("Ignoring pipe flags"); + } + + // reference-counted buffer for the pipe + let buffer = pipe::SharedBuf::new(); + let buffer = Arc::new(AtomicRefCell::new(buffer)); + + // reference-counted file object for read end of the pipe + let reader = pipe::PipeFile::new(Arc::clone(&buffer), FileMode::READ); + let reader = Arc::new(AtomicRefCell::new(PosixFile::Pipe(reader))); + + // reference-counted file object for write end of the pipe + let writer = pipe::PipeFile::new(Arc::clone(&buffer), FileMode::WRITE); + let writer = Arc::new(AtomicRefCell::new(PosixFile::Pipe(writer))); + + // set the file objects to listen for events on the buffer + pipe::PipeFile::enable_notifications(&reader); + pipe::PipeFile::enable_notifications(&writer); + + // file descriptors for the read and write file objects + let mut reader_desc = Descriptor::new(reader); + let mut writer_desc = Descriptor::new(writer); + + // set the file descriptor flags + reader_desc.set_flags(flags_to_set); + writer_desc.set_flags(flags_to_set); + + // register the file descriptors and return them to the caller + let num_items = 2; + let size_needed = num_items * std::mem::size_of::(); + let fd_ptr = + unsafe { c::process_getWriteablePtr(sys.process, sys.thread, fd_ptr, size_needed as u64) }; + let fds = unsafe { std::slice::from_raw_parts_mut(fd_ptr as *mut libc::c_int, num_items) }; + + fds[0] = unsafe { + c::process_registerCompatDescriptor( + sys.process, + Box::into_raw(Box::new(CompatDescriptor::New(reader_desc))), + ) + }; + fds[1] = unsafe { + c::process_registerCompatDescriptor( + sys.process, + Box::into_raw(Box::new(CompatDescriptor::New(writer_desc))), + ) + }; + + debug!("Created pipe reader fd {} and writer fd {}", fds[0], fds[1]); + + c::SysCallReturn::from_int(0) +} + +mod export { + use super::*; + + #[no_mangle] + pub extern "C" fn rustsyscallhandler_close( + sys: *mut c::SysCallHandler, + args: *const c::SysCallArgs, + ) -> c::SysCallReturn { + assert!(!sys.is_null() && !args.is_null()); + close(unsafe { &mut *sys }, unsafe { &*args }) + } + + #[no_mangle] + pub extern "C" fn rustsyscallhandler_read( + sys: *mut c::SysCallHandler, + args: *const c::SysCallArgs, + ) -> c::SysCallReturn { + assert!(!sys.is_null() && !args.is_null()); + read(unsafe { &mut *sys }, unsafe { &*args }) + } + + #[no_mangle] + pub extern "C" fn rustsyscallhandler_write( + sys: *mut c::SysCallHandler, + args: *const c::SysCallArgs, + ) -> c::SysCallReturn { + assert!(!sys.is_null() && !args.is_null()); + write(unsafe { &mut *sys }, unsafe { &*args }) + } + + #[no_mangle] + pub extern "C" fn rustsyscallhandler_pipe( + sys: *mut c::SysCallHandler, + args: *const c::SysCallArgs, + ) -> c::SysCallReturn { + assert!(!sys.is_null() && !args.is_null()); + pipe(unsafe { &mut *sys }, unsafe { &*args }) + } + + #[no_mangle] + pub extern "C" fn rustsyscallhandler_pipe2( + sys: *mut c::SysCallHandler, + args: *const c::SysCallArgs, + ) -> c::SysCallReturn { + assert!(!sys.is_null() && !args.is_null()); + pipe2(unsafe { &mut *sys }, unsafe { &*args }) + } +} diff --git a/src/main/host/syscall_handler.c b/src/main/host/syscall_handler.c index 847b88ca39..a01948bdfe 100644 --- a/src/main/host/syscall_handler.c +++ b/src/main/host/syscall_handler.c @@ -165,6 +165,12 @@ static void _syscallhandler_post_syscall(SysCallHandler* sys, long number, scr = syscallhandler_##s(sys, args); \ _syscallhandler_post_syscall(sys, args->number, #s, &scr); \ break +#define HANDLE_NEW(s) \ + case SYS_##s: \ + _syscallhandler_pre_syscall(sys, args->number, #s); \ + scr = rustsyscallhandler_##s(sys, args); \ + _syscallhandler_post_syscall(sys, args->number, #s, &scr); \ + break #define NATIVE(s) \ case SYS_##s: \ debug("native syscall %ld " #s, args->number); \ @@ -200,7 +206,7 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(brk); HANDLE(clock_gettime); HANDLE(clone); - HANDLE(close); + HANDLE_NEW(close); HANDLE(connect); HANDLE(creat); HANDLE(epoll_create); @@ -260,8 +266,8 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(newfstatat); HANDLE(open); HANDLE(openat); - HANDLE(pipe); - HANDLE(pipe2); + HANDLE_NEW(pipe); + HANDLE_NEW(pipe2); HANDLE(pread64); HANDLE(preadv); #ifdef SYS_preadv2 @@ -272,7 +278,7 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, #ifdef SYS_pwritev2 HANDLE(pwritev2); #endif - HANDLE(read); + HANDLE_NEW(read); HANDLE(readahead); HANDLE(readlinkat); HANDLE(readv); @@ -298,7 +304,7 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(uname); HANDLE(unlinkat); HANDLE(utimensat); - HANDLE(write); + HANDLE_NEW(write); HANDLE(writev); // ************************************** diff --git a/src/main/lib.rs b/src/main/lib.rs index 1cd4c99419..2fd351aab3 100644 --- a/src/main/lib.rs +++ b/src/main/lib.rs @@ -9,6 +9,8 @@ mod cshadow { #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] + // the following is added due to https://github.com/rust-lang/rust/issues/66220 + #![allow(improper_ctypes)] include!("bindings/rust/wrapper.rs"); } diff --git a/src/main/utility/byte_queue.rs b/src/main/utility/byte_queue.rs index 315b944bcc..dbd63e7234 100644 --- a/src/main/utility/byte_queue.rs +++ b/src/main/utility/byte_queue.rs @@ -45,6 +45,11 @@ impl ByteQueue { } } + /// Number of bytes in the queue. + pub fn len(&self) -> usize { + self.length + } + /// Push bytes to the head of the queue. pub fn push(&mut self, src: &[u8]) { // create new buffer head lazily as opposed to proactively @@ -187,6 +192,13 @@ mod export { } } + #[no_mangle] + pub extern "C" fn bytequeue_len(bq: *mut ByteQueue) -> libc::size_t { + assert!(!bq.is_null()); + let bq = unsafe { &mut *bq }; + bq.len() + } + #[no_mangle] pub extern "C" fn bytequeue_push( bq: *mut ByteQueue, diff --git a/src/main/utility/event_queue.rs b/src/main/utility/event_queue.rs new file mode 100644 index 0000000000..1ecad3589e --- /dev/null +++ b/src/main/utility/event_queue.rs @@ -0,0 +1,172 @@ +use atomic_refcell::AtomicRefCell; +use log::*; +use std::sync::{Arc, Weak}; + +/// A queue of events (functions/closures) which when run can add their own events to the queue. +pub struct EventQueue(std::collections::VecDeque>); + +impl EventQueue { + /// Create an empty event queue. + pub fn new() -> Self { + Self(std::collections::VecDeque::new()) + } + + /// Add an event to the queue. + pub fn add(&mut self, f: impl FnOnce(&mut Self) + 'static) { + self.0.push_back(Box::new(f)); + } + + /// Process all of the events in the queue (and any new events that are generated). + pub fn run(&mut self) { + // loop until there are no more events + let mut count = 0; + while let Some(f) = self.0.pop_front() { + // run the event and allow it to add new events + (f)(self); + + count += 1; + if count == 200 { + debug!("Possible infinite loop of event callbacks."); + } else if count == 10_000 { + warn!("Very likely an infinite loop of event callbacks."); + } + } + } + + /// A convenience function to create an EventQueue, allow the caller to add events, + /// and process them all before returning. + pub fn queue_and_run(f: F) -> U + where + F: FnOnce(&mut Self) -> U, + { + let mut event_queue = Self::new(); + let rv = (f)(&mut event_queue); + event_queue.run(); + rv + } +} + +#[derive(Clone, Copy, PartialEq, PartialOrd)] +struct HandleId(u32); + +/// A handle allows you to stop listening for events. +pub struct Handle { + id: HandleId, + source: Weak>>, +} + +impl Handle { + fn new(id: HandleId, source: Weak>>) -> Self { + Self { id, source } + } + + pub fn stop_listening(self) {} +} + +impl Drop for Handle { + fn drop(&mut self) { + if let Some(x) = self.source.upgrade() { + x.borrow_mut().remove_listener(self.id); + } + } +} + +pub struct EventSource { + inner: Arc>>, +} + +impl EventSource { + pub fn new() -> Self { + Self { + inner: Arc::new(AtomicRefCell::new(EventSourceInner::new())), + } + } + + pub fn add_listener( + &mut self, + notify_fn: impl Fn(T, &mut EventQueue) + Send + Sync + 'static, + ) -> Handle { + let inner_ref = Arc::downgrade(&Arc::clone(&self.inner)); + self.inner.borrow_mut().add_listener(inner_ref, notify_fn) + } + + pub fn notify_listeners(&mut self, message: T, event_queue: &mut EventQueue) { + for (_, l) in &self.inner.borrow().listeners { + let l_clone = l.clone(); + event_queue.add(move |event_queue| (l_clone)(message, event_queue)); + } + } +} + +struct EventSourceInner { + listeners: std::vec::Vec<(HandleId, Arc>)>, + next_id: std::num::Wrapping, +} + +impl EventSourceInner { + pub fn new() -> Self { + Self { + listeners: std::vec::Vec::new(), + next_id: std::num::Wrapping(0), + } + } + + fn get_unused_id(&mut self) -> HandleId { + // it's very unlikely that there will be collisions, but we loop anyways since we + // don't care about worst-case performance here + let handle_id = loop { + let id = HandleId(self.next_id.0); + self.next_id += std::num::Wrapping(1); + + if !self.listeners.iter().any(|x| x.0 == id) { + break id; + } + }; + handle_id + } + + pub fn add_listener( + &mut self, + inner: std::sync::Weak>, + notify_fn: impl Fn(T, &mut EventQueue) + Send + Sync + 'static, + ) -> Handle { + let handle_id = self.get_unused_id(); + + self.listeners + .push((handle_id, Arc::new(Box::new(notify_fn)))); + + Handle::new(handle_id, inner) + } + + pub fn remove_listener(&mut self, id: HandleId) { + self.listeners + .remove(self.listeners.iter().position(|x| x.0 == id).unwrap()); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_eventqueue() { + let counter = Arc::new(AtomicRefCell::new(0u32)); + let counter_clone = Arc::clone(&counter); + + let mut source = EventSource::new(); + + let handle = source.add_listener(move |inc, _| { + *counter_clone.borrow_mut() += inc; + }); + + EventQueue::queue_and_run(|queue| source.notify_listeners(1, queue)); + EventQueue::queue_and_run(|queue| source.notify_listeners(3, queue)); + + handle.stop_listening(); + + EventQueue::queue_and_run(|queue| source.notify_listeners(5, queue)); + EventQueue::queue_and_run(|queue| source.notify_listeners(7, queue)); + + assert_eq!(*counter.borrow(), 4); + } +} diff --git a/src/main/utility/mod.rs b/src/main/utility/mod.rs index d293f53f8b..b4b93a8a97 100644 --- a/src/main/utility/mod.rs +++ b/src/main/utility/mod.rs @@ -1,4 +1,5 @@ pub mod byte_queue; +pub mod event_queue; pub mod interval_map; pub mod proc_maps; pub mod syscall; From 59802a642abafde0ae85170b70a16701e04b5442 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Wed, 13 Jan 2021 20:34:28 -0500 Subject: [PATCH 11/13] Added simple pipe tests --- src/test/CMakeLists.txt | 1 + src/test/Cargo.toml | 4 + src/test/pipe/CMakeLists.txt | 18 ++ src/test/pipe/pipe.shadow.config.yaml | 32 ++++ src/test/pipe/test_pipe.rs | 246 ++++++++++++++++++++++++++ 5 files changed, 301 insertions(+) create mode 100644 src/test/pipe/CMakeLists.txt create mode 100644 src/test/pipe/pipe.shadow.config.yaml create mode 100644 src/test/pipe/test_pipe.rs diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 598eb74498..dabe535b88 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -47,6 +47,7 @@ add_subdirectory(file) add_subdirectory(futex) add_subdirectory(memory) add_subdirectory(phold) +add_subdirectory(pipe) add_subdirectory(poll) add_subdirectory(pthreads) add_subdirectory(random) diff --git a/src/test/Cargo.toml b/src/test/Cargo.toml index 5a02f33bd6..5493397ae1 100644 --- a/src/test/Cargo.toml +++ b/src/test/Cargo.toml @@ -73,6 +73,10 @@ path = "memory/test_mmap.rs" name = "test_eventfd" path = "eventfd/test_eventfd.rs" +[[bin]] +name = "test_pipe" +path = "pipe/test_pipe.rs" + [dependencies] libc = "0.2" nix = "0.19.0" diff --git a/src/test/pipe/CMakeLists.txt b/src/test/pipe/CMakeLists.txt new file mode 100644 index 0000000000..44b4537945 --- /dev/null +++ b/src/test/pipe/CMakeLists.txt @@ -0,0 +1,18 @@ +add_test(NAME pipe COMMAND ../target/debug/test_pipe --libc-passing) +list(APPEND TestNames pipe) + +foreach(Method ptrace preload) + # runs the shadow tests with only the passing tests, not all tests + add_test( + NAME pipe-shadow-${Method} + COMMAND sh -c "\ + ${yaml2xml} ${CMAKE_CURRENT_SOURCE_DIR}/pipe.shadow.config.yaml --output - \ + | ${CMAKE_BINARY_DIR}/src/main/shadow --interpose-method=${Method} -l debug -d pipe.shadow-${Method}.data - \ + " + ) + list(APPEND TestNames pipe-shadow-${Method}) +endforeach() + +set_property(TEST ${TestNames} PROPERTY ENVIRONMENT "RUST_BACKTRACE=1") +# need to check the test's return code, not just shadow's (see shadow/shadow#902) +set_property(TEST ${TestNames} PROPERTY FAIL_REGULAR_EXPRESSION "main error code '.*' for process") diff --git a/src/test/pipe/pipe.shadow.config.yaml b/src/test/pipe/pipe.shadow.config.yaml new file mode 100644 index 0000000000..eff9c65c01 --- /dev/null +++ b/src/test/pipe/pipe.shadow.config.yaml @@ -0,0 +1,32 @@ +options: + stoptime: 5 +topology: +- graphml: | + + + + + + + + + US + 10240 + 10240 + + + 50.0 + 0.0 + + + +plugins: +- id: testpipe + path: ../target/debug/test_pipe +hosts: +- id: testnode + quantity: 1 + processes: + - plugin: testpipe + starttime: 1 + arguments: --shadow-passing diff --git a/src/test/pipe/test_pipe.rs b/src/test/pipe/test_pipe.rs new file mode 100644 index 0000000000..b1e1b732b4 --- /dev/null +++ b/src/test/pipe/test_pipe.rs @@ -0,0 +1,246 @@ +/* + * The Shadow Simulator + * See LICENSE for licensing information + */ + +use test_utils::set; +use test_utils::TestEnvironment as TestEnv; + +fn main() -> Result<(), String> { + // should we restrict the tests we run? + let filter_shadow_passing = std::env::args().any(|x| x == "--shadow-passing"); + let filter_libc_passing = std::env::args().any(|x| x == "--libc-passing"); + // should we summarize the results rather than exit on a failed test + let summarize = std::env::args().any(|x| x == "--summarize"); + + let mut tests = get_tests(); + if filter_shadow_passing { + tests = tests + .into_iter() + .filter(|x| x.passing(TestEnv::Shadow)) + .collect() + } + if filter_libc_passing { + tests = tests + .into_iter() + .filter(|x| x.passing(TestEnv::Libc)) + .collect() + } + + test_utils::run_tests(&tests, summarize)?; + + println!("Success."); + Ok(()) +} + +fn get_tests() -> Vec> { + let tests: Vec> = vec![ + test_utils::ShadowTest::new("test_pipe", test_pipe, set![TestEnv::Libc, TestEnv::Shadow]), + test_utils::ShadowTest::new( + "test_read_write", + test_read_write, + set![TestEnv::Libc, TestEnv::Shadow], + ), + // TODO: support dup() in Shadow + test_utils::ShadowTest::new("test_dup", test_dup, set![TestEnv::Libc]), + test_utils::ShadowTest::new( + "test_write_to_read_end", + test_write_to_read_end, + set![TestEnv::Libc, TestEnv::Shadow], + ), + test_utils::ShadowTest::new( + "test_read_from_write_end", + test_read_from_write_end, + set![TestEnv::Libc, TestEnv::Shadow], + ), + ]; + + tests +} + +fn test_pipe() -> Result<(), String> { + let mut fds = [0 as libc::c_int; 2]; + test_utils::check_system_call!(|| { unsafe { libc::pipe(fds.as_mut_ptr()) } }, &[])?; + + test_utils::result_assert(fds[0] > 0, "fds[0] not set")?; + test_utils::result_assert(fds[1] > 0, "fds[1] not set")?; + + Ok(()) +} + +fn test_read_write() -> Result<(), String> { + let mut fds = [0 as libc::c_int; 2]; + test_utils::check_system_call!(|| { unsafe { libc::pipe(fds.as_mut_ptr()) } }, &[])?; + + test_utils::result_assert(fds[0] > 0, "fds[0] not set")?; + test_utils::result_assert(fds[1] > 0, "fds[1] not set")?; + + let (read_fd, write_fd) = (fds[0], fds[1]); + + test_utils::run_and_close_fds(&[write_fd, read_fd], || { + let write_buf = [1u8, 2, 3, 4]; + + let rv = test_utils::check_system_call!( + || { + unsafe { + libc::write( + write_fd, + write_buf.as_ptr() as *const libc::c_void, + write_buf.len(), + ) + } + }, + &[] + )?; + + test_utils::result_assert_eq(rv, 4, "Expected to write 4 bytes")?; + + let mut read_buf = [0u8; 4]; + + let rv = test_utils::check_system_call!( + || { + unsafe { + libc::read( + read_fd, + read_buf.as_mut_ptr() as *mut libc::c_void, + read_buf.len(), + ) + } + }, + &[] + )?; + + test_utils::result_assert_eq(rv, 4, "Expected to read 4 bytes")?; + + test_utils::result_assert_eq(write_buf, read_buf, "Buffers differ")?; + + Ok(()) + }) +} + +fn test_dup() -> Result<(), String> { + let mut fds = [0 as libc::c_int; 2]; + test_utils::check_system_call!(|| { unsafe { libc::pipe(fds.as_mut_ptr()) } }, &[])?; + + test_utils::result_assert(fds[0] > 0, "fds[0] not set")?; + test_utils::result_assert(fds[1] > 0, "fds[1] not set")?; + + let (read_fd, write_fd) = (fds[0], fds[1]); + + // TODO: use nix instead here + fn write(fd: libc::c_int, buf: &[u8]) -> Result { + test_utils::check_system_call!( + || { unsafe { libc::write(fd, buf.as_ptr() as *const libc::c_void, buf.len(),) } }, + &[] + ) + } + + fn read(fd: libc::c_int, buf: &mut [u8]) -> Result { + test_utils::check_system_call!( + || { unsafe { libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len(),) } }, + &[] + ) + } + + test_utils::run_and_close_fds(&[write_fd, read_fd], || { + let write_fd_dup = + test_utils::check_system_call!(|| { unsafe { libc::dup(write_fd) } }, &[])?; + + test_utils::run_and_close_fds(&[write_fd_dup], || { + let write_buf = [1u8, 2, 3, 4]; + + // write 4 bytes to original fd + let rv = write(write_fd, &write_buf)?; + test_utils::result_assert_eq(rv, 4, "Expected to write 4 bytes")?; + + // write 5 bytes to duped fd + let rv = write(write_fd_dup, &write_buf)?; + test_utils::result_assert_eq(rv, 4, "Expected to write 4 bytes")?; + + // read 8 bytes + let mut read_buf = [0u8; 8]; + let rv = read(read_fd, &mut read_buf)?; + test_utils::result_assert_eq(rv, 8, "Expected to read 8 bytes")?; + + test_utils::result_assert_eq(&write_buf[..], &read_buf[..4], "First 4 bytes differ")?; + test_utils::result_assert_eq(&write_buf[..], &read_buf[4..8], "Last 4 bytes differ")?; + + Ok(()) + }) + }) +} + +fn test_write_to_read_end() -> Result<(), String> { + let mut fds = [0 as libc::c_int; 2]; + test_utils::check_system_call!(|| { unsafe { libc::pipe(fds.as_mut_ptr()) } }, &[])?; + + test_utils::result_assert(fds[0] > 0, "fds[0] not set")?; + test_utils::result_assert(fds[1] > 0, "fds[1] not set")?; + + let (read_fd, write_fd) = (fds[0], fds[1]); + + test_utils::run_and_close_fds(&[write_fd, read_fd], || { + let write_buf = [1u8, 2, 3, 4]; + + test_utils::check_system_call!( + || { + unsafe { + libc::write( + read_fd, + write_buf.as_ptr() as *const libc::c_void, + write_buf.len(), + ) + } + }, + &[libc::EBADF] + )?; + + Ok(()) + }) +} + +fn test_read_from_write_end() -> Result<(), String> { + let mut fds = [0 as libc::c_int; 2]; + test_utils::check_system_call!(|| { unsafe { libc::pipe(fds.as_mut_ptr()) } }, &[])?; + + test_utils::result_assert(fds[0] > 0, "fds[0] not set")?; + test_utils::result_assert(fds[1] > 0, "fds[1] not set")?; + + let (read_fd, write_fd) = (fds[0], fds[1]); + + test_utils::run_and_close_fds(&[write_fd, read_fd], || { + let write_buf = [1u8, 2, 3, 4]; + + let rv = test_utils::check_system_call!( + || { + unsafe { + libc::write( + write_fd, + write_buf.as_ptr() as *const libc::c_void, + write_buf.len(), + ) + } + }, + &[] + )?; + + test_utils::result_assert_eq(rv, 4, "Expected to write 4 bytes")?; + + let mut read_buf = [0u8; 4]; + + test_utils::check_system_call!( + || { + unsafe { + libc::read( + write_fd, + read_buf.as_mut_ptr() as *mut libc::c_void, + read_buf.len(), + ) + } + }, + &[libc::EBADF] + )?; + + Ok(()) + }) +} From c17e2d6cb4efe10bf4f19be5e11bcea6b712f42c Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Thu, 14 Jan 2021 02:03:13 -0500 Subject: [PATCH 12/13] Can disable the Rust syscall handlers using a flag Use the `--use-c-syscalls` flag to build Shadow without the Rust syscall handlers. For example: ./setup build --debug --test --clean --use-c-syscalls --- CMakeLists.txt | 5 +++++ setup | 6 ++++++ src/main/host/syscall_handler.c | 28 +++++++++++++++++----------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c56f9f876..05c0e530f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,6 +116,7 @@ option(SHADOW_TEST "build tests (default: OFF)" OFF) option(SHADOW_EXPORT "export service libraries and headers (default: OFF)" OFF) option(SHADOW_WERROR "turn compiler warnings into errors. (default: OFF)" OFF) option(SHADOW_COVERAGE "enable code-coverage instrumentation. (default: OFF)" OFF) +option(SHADOW_USE_C_SYSCALLS "use only the C syscall handlers. (default: OFF)" OFF) ## display selected user options MESSAGE(STATUS) @@ -165,6 +166,10 @@ else() set(CARGO_ENV_VARS "") endif(SHADOW_COVERAGE STREQUAL ON) +if(SHADOW_USE_C_SYSCALLS STREQUAL ON) + add_definitions(-DUSE_C_SYSCALLS) +endif() + if($ENV{VERBOSE}) add_definitions(-DVERBOSE) endif() diff --git a/setup b/setup index 97a9edc32f..cfdd28cc3f 100755 --- a/setup +++ b/setup @@ -67,6 +67,11 @@ def main(): action="store_true", dest="do_coverage", default=False) + parser_build.add_argument('--use-c-syscalls', + help="use only the C syscall handlers (disables Rust syscall handlers)", + action="store_true", dest="do_use_c_syscalls", + default=False) + parser_build.add_argument('-v', '--verbose', help="print verbose output from the compiler", action="store_true", dest="do_verbose", @@ -194,6 +199,7 @@ def build(args, remaining): if args.disable_tgen: cmake_cmd += " -DBUILD_TGEN=OFF" if args.do_valgrind: cmake_cmd += " -DLOADER_VALGRIND=ON" if args.do_werror: cmake_cmd += " -DSHADOW_WERROR=ON" + if args.do_use_c_syscalls: cmake_cmd += " -DSHADOW_USE_C_SYSCALLS=ON" if args.do_coverage: if not args.do_debug: diff --git a/src/main/host/syscall_handler.c b/src/main/host/syscall_handler.c index a01948bdfe..5bf8b59eca 100644 --- a/src/main/host/syscall_handler.c +++ b/src/main/host/syscall_handler.c @@ -165,17 +165,23 @@ static void _syscallhandler_post_syscall(SysCallHandler* sys, long number, scr = syscallhandler_##s(sys, args); \ _syscallhandler_post_syscall(sys, args->number, #s, &scr); \ break -#define HANDLE_NEW(s) \ - case SYS_##s: \ - _syscallhandler_pre_syscall(sys, args->number, #s); \ - scr = rustsyscallhandler_##s(sys, args); \ - _syscallhandler_post_syscall(sys, args->number, #s, &scr); \ - break #define NATIVE(s) \ case SYS_##s: \ debug("native syscall %ld " #s, args->number); \ scr = (SysCallReturn){.state = SYSCALL_NATIVE}; \ break + +#ifdef USE_C_SYSCALLS +#define HANDLE_RUST(s) HANDLE(s) +#else +#define HANDLE_RUST(s) \ + case SYS_##s: \ + _syscallhandler_pre_syscall(sys, args->number, #s); \ + scr = rustsyscallhandler_##s(sys, args); \ + _syscallhandler_post_syscall(sys, args->number, #s, &scr); \ + break +#endif + SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, const SysCallArgs* args) { MAGIC_ASSERT(sys); @@ -206,7 +212,7 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(brk); HANDLE(clock_gettime); HANDLE(clone); - HANDLE_NEW(close); + HANDLE_RUST(close); HANDLE(connect); HANDLE(creat); HANDLE(epoll_create); @@ -266,8 +272,8 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(newfstatat); HANDLE(open); HANDLE(openat); - HANDLE_NEW(pipe); - HANDLE_NEW(pipe2); + HANDLE_RUST(pipe); + HANDLE_RUST(pipe2); HANDLE(pread64); HANDLE(preadv); #ifdef SYS_preadv2 @@ -278,7 +284,7 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, #ifdef SYS_pwritev2 HANDLE(pwritev2); #endif - HANDLE_NEW(read); + HANDLE_RUST(read); HANDLE(readahead); HANDLE(readlinkat); HANDLE(readv); @@ -304,7 +310,7 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(uname); HANDLE(unlinkat); HANDLE(utimensat); - HANDLE_NEW(write); + HANDLE_RUST(write); HANDLE(writev); // ************************************** From 59f9846acf3311f840caf9e8666249700d5675c1 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Tue, 19 Jan 2021 19:19:26 -0500 Subject: [PATCH 13/13] Improved how descriptor/file flags are stored in Rust All flags were being stored in the descriptor object, but only the FD_CLOEXEC should be. The rest should be stored in the posix file object itself. Also improved the comments. --- src/main/host/descriptor/mod.rs | 57 +++++++++++++++++++++++++++----- src/main/host/descriptor/pipe.rs | 14 ++++++-- src/main/host/syscall/unistd.rs | 55 ++++++++++++++++++++---------- 3 files changed, 97 insertions(+), 29 deletions(-) diff --git a/src/main/host/descriptor/mod.rs b/src/main/host/descriptor/mod.rs index 494a9bad9c..93d554581b 100644 --- a/src/main/host/descriptor/mod.rs +++ b/src/main/host/descriptor/mod.rs @@ -39,7 +39,27 @@ pub enum SyscallReturn { } bitflags::bitflags! { - // file modes: https://github.com/torvalds/linux/blob/master/include/linux/fs.h#L111 + /// These are flags that can potentially be changed from the plugin (analagous to the Linux + /// `filp->f_flags` status flags). Not all `O_` flags are valid here. For example file access + /// mode flags (ex: `O_RDWR`) are stored elsewhere, and file creation flags (ex: `O_CREAT`) + /// are not stored anywhere. Many of these can be represented in different ways, for example: + /// `O_NONBLOCK`, `SOCK_NONBLOCK`, `EFD_NONBLOCK`, `GRND_NONBLOCK`, etc, and not all have the + /// same value. + pub struct FileFlags: libc::c_int { + const NONBLOCK = libc::O_NONBLOCK; + const APPEND = libc::O_APPEND; + const ASYNC = libc::O_ASYNC; + const DIRECT = libc::O_DIRECT; + const NOATIME = libc::O_NOATIME; + } +} + +bitflags::bitflags! { + /// These are flags that should generally not change (analagous to the Linux `filp->f_mode`). + /// Since the plugin will never see these values and they're not exposed by the kernel, we + /// don't match the kernel `FMODE_` values here. + /// + /// Examples: https://github.com/torvalds/linux/blob/master/include/linux/fs.h#L111 pub struct FileMode: u32 { const READ = 0b00000001; const WRITE = 0b00000010; @@ -210,6 +230,18 @@ impl PosixFile { } } + pub fn get_flags(&self) -> FileFlags { + match self { + Self::Pipe(f) => f.get_flags(), + } + } + + pub fn set_flags(&mut self, flags: FileFlags) { + match self { + Self::Pipe(f) => f.set_flags(flags), + } + } + pub fn add_legacy_listener(&mut self, ptr: *mut c::StatusListener) { match self { Self::Pipe(f) => f.add_legacy_listener(ptr), @@ -223,32 +255,39 @@ impl PosixFile { } } +bitflags::bitflags! { + // Linux only supports a single descriptor flag: + // https://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html + pub struct DescriptorFlags: u32 { + const CLOEXEC = libc::FD_CLOEXEC as u32; + } +} + #[derive(Clone)] pub struct Descriptor { file: Arc>, - flags: i32, + flags: DescriptorFlags, } impl Descriptor { pub fn new(file: Arc>) -> Self { - Self { file, flags: 0 } + Self { + file, + flags: DescriptorFlags::empty(), + } } pub fn get_file(&self) -> &Arc> { &self.file } - pub fn get_flags(&self) -> i32 { + pub fn get_flags(&self) -> DescriptorFlags { self.flags } - pub fn set_flags(&mut self, flags: i32) { + pub fn set_flags(&mut self, flags: DescriptorFlags) { self.flags = flags; } - - pub fn add_flags(&mut self, flags: i32) { - self.flags |= flags; - } } // don't implement copy or clone without considering the legacy descriptor's ref count diff --git a/src/main/host/descriptor/pipe.rs b/src/main/host/descriptor/pipe.rs index 2aeb12dae1..cb7a24f1cf 100644 --- a/src/main/host/descriptor/pipe.rs +++ b/src/main/host/descriptor/pipe.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use crate::cshadow as c; use crate::host::descriptor::{ - FileMode, NewStatusListenerFilter, PosixFile, StatusEventSource, SyscallReturn, + FileFlags, FileMode, NewStatusListenerFilter, PosixFile, StatusEventSource, SyscallReturn, }; use crate::utility::byte_queue::ByteQueue; use crate::utility::event_queue::{EventQueue, Handle}; @@ -13,16 +13,18 @@ pub struct PipeFile { event_source: StatusEventSource, status: c::Status, mode: FileMode, + flags: FileFlags, buffer_event_handle: Option>, } impl PipeFile { - pub fn new(buffer: Arc>, mode: FileMode) -> Self { + pub fn new(buffer: Arc>, mode: FileMode, flags: FileFlags) -> Self { let mut rv = Self { buffer, event_source: StatusEventSource::new(), status: c::_Status_STATUS_NONE, mode, + flags, buffer_event_handle: None, }; @@ -31,6 +33,14 @@ impl PipeFile { rv } + pub fn get_flags(&self) -> FileFlags { + self.flags + } + + pub fn set_flags(&mut self, flags: FileFlags) { + self.flags = flags; + } + pub fn read(&mut self, bytes: &mut [u8], event_queue: &mut EventQueue) -> SyscallReturn { // if the file is not open for reading, return EBADF if !self.mode.contains(FileMode::READ) { diff --git a/src/main/host/syscall/unistd.rs b/src/main/host/syscall/unistd.rs index 3ff458d9f5..2dee19d76d 100644 --- a/src/main/host/syscall/unistd.rs +++ b/src/main/host/syscall/unistd.rs @@ -1,6 +1,8 @@ use crate::cshadow as c; use crate::host::descriptor::pipe; -use crate::host::descriptor::{CompatDescriptor, Descriptor, FileMode, PosixFile, SyscallReturn}; +use crate::host::descriptor::{ + CompatDescriptor, Descriptor, DescriptorFlags, FileFlags, FileMode, PosixFile, SyscallReturn, +}; use crate::host::syscall; use crate::utility::event_queue::EventQueue; @@ -90,17 +92,20 @@ fn read_helper( unsafe { c::process_getWriteablePtr(sys.process, sys.thread, buf_ptr, size_needed as u64) }; let mut buf = unsafe { std::slice::from_raw_parts_mut(buf_ptr as *mut u8, size_needed) }; + let posix_file = desc.get_file(); + let file_flags = posix_file.borrow().get_flags(); + // call the file's read(), and run any resulting events let result = EventQueue::queue_and_run(|event_queue| { - desc.get_file().borrow_mut().read(&mut buf, event_queue) + posix_file.borrow_mut().read(&mut buf, event_queue) }); // if the syscall would block and it's a blocking descriptor if result == SyscallReturn::Error(nix::errno::EWOULDBLOCK) - && (desc.get_flags() & libc::O_NONBLOCK) == 0 + && !file_flags.contains(FileFlags::NONBLOCK) { let trigger = - c::Trigger::from_posix_file(desc.get_file(), c::_Status_STATUS_DESCRIPTOR_READABLE); + c::Trigger::from_posix_file(posix_file, c::_Status_STATUS_DESCRIPTOR_READABLE); return c::SysCallReturn { state: c::SysCallReturnState_SYSCALL_BLOCK, @@ -161,17 +166,19 @@ fn write_helper( unsafe { c::process_getReadablePtr(sys.process, sys.thread, buf_ptr, size_needed as u64) }; let buf = unsafe { std::slice::from_raw_parts(buf_ptr as *const u8, size_needed) }; + let posix_file = desc.get_file(); + let file_flags = posix_file.borrow().get_flags(); + // call the file's write(), and run any resulting events - let result = EventQueue::queue_and_run(|event_queue| { - desc.get_file().borrow_mut().write(&buf, event_queue) - }); + let result = + EventQueue::queue_and_run(|event_queue| posix_file.borrow_mut().write(&buf, event_queue)); // if the syscall would block and it's a blocking descriptor if result == SyscallReturn::Error(nix::errno::EWOULDBLOCK) - && (desc.get_flags() & libc::O_NONBLOCK) == 0 + && !file_flags.contains(FileFlags::NONBLOCK) { let trigger = - c::Trigger::from_posix_file(desc.get_file(), c::_Status_STATUS_DESCRIPTOR_WRITABLE); + c::Trigger::from_posix_file(posix_file, c::_Status_STATUS_DESCRIPTOR_WRITABLE); return c::SysCallReturn { state: c::SysCallReturnState_SYSCALL_BLOCK, @@ -205,14 +212,26 @@ fn pipe_helper(sys: &mut c::SysCallHandler, fd_ptr: c::PluginPtr, flags: i32) -> return c::SysCallReturn::from_errno(nix::errno::Errno::EFAULT); } - // pipe flags that we support - let supported_flags = libc::O_NONBLOCK & libc::O_CLOEXEC; - let flags_to_set = flags & supported_flags; + let mut file_flags = FileFlags::empty(); + let mut descriptor_flags = DescriptorFlags::empty(); + + // keep track of which flags we use + let mut remaining_flags = flags; + + if flags & libc::O_NONBLOCK != 0 { + file_flags.insert(FileFlags::NONBLOCK); + remaining_flags &= !libc::O_NONBLOCK; + } + + if flags & libc::O_CLOEXEC != 0 { + descriptor_flags.insert(DescriptorFlags::CLOEXEC); + remaining_flags &= !libc::O_CLOEXEC; + } // the user requested flags that we don't support - if flags != flags_to_set { + if remaining_flags != 0 { // exit early if the O_DIRECT flag was set - if flags & libc::O_DIRECT != 0 { + if remaining_flags & libc::O_DIRECT != 0 { warn!("We don't currently support pipes in 'O_DIRECT' mode"); return c::SysCallReturn::from_errno(nix::errno::Errno::EOPNOTSUPP); } @@ -224,11 +243,11 @@ fn pipe_helper(sys: &mut c::SysCallHandler, fd_ptr: c::PluginPtr, flags: i32) -> let buffer = Arc::new(AtomicRefCell::new(buffer)); // reference-counted file object for read end of the pipe - let reader = pipe::PipeFile::new(Arc::clone(&buffer), FileMode::READ); + let reader = pipe::PipeFile::new(Arc::clone(&buffer), FileMode::READ, file_flags); let reader = Arc::new(AtomicRefCell::new(PosixFile::Pipe(reader))); // reference-counted file object for write end of the pipe - let writer = pipe::PipeFile::new(Arc::clone(&buffer), FileMode::WRITE); + let writer = pipe::PipeFile::new(Arc::clone(&buffer), FileMode::WRITE, file_flags); let writer = Arc::new(AtomicRefCell::new(PosixFile::Pipe(writer))); // set the file objects to listen for events on the buffer @@ -240,8 +259,8 @@ fn pipe_helper(sys: &mut c::SysCallHandler, fd_ptr: c::PluginPtr, flags: i32) -> let mut writer_desc = Descriptor::new(writer); // set the file descriptor flags - reader_desc.set_flags(flags_to_set); - writer_desc.set_flags(flags_to_set); + reader_desc.set_flags(descriptor_flags); + writer_desc.set_flags(descriptor_flags); // register the file descriptors and return them to the caller let num_items = 2;