From 4da664212376a9fa63ef26278cc376bdfdb7883d Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Thu, 20 Mar 2025 15:17:43 +0100 Subject: [PATCH] Add socket abstraction --- src/common/network/socket.hpp | 2 + src/samples/test-sample/test.cpp | 18 +-- .../emulation_test_utils.hpp | 14 +- .../serialization_test.cpp | 8 +- .../static_socket_factory.cpp | 129 ++++++++++++++++++ .../static_socket_factory.hpp | 8 ++ src/windows-emulator/devices/afd_endpoint.cpp | 70 ++++------ src/windows-emulator/emulator_utils.hpp | 6 + src/windows-emulator/network/i_socket.hpp | 26 ++++ .../network/socket_factory.cpp | 55 ++++++++ .../network/socket_factory.hpp | 24 ++++ .../network/socket_wrapper.cpp | 59 ++++++++ .../network/socket_wrapper.hpp | 35 +++++ src/windows-emulator/windows_emulator.cpp | 32 ++++- src/windows-emulator/windows_emulator.hpp | 22 ++- 15 files changed, 437 insertions(+), 71 deletions(-) create mode 100644 src/windows-emulator-test/static_socket_factory.cpp create mode 100644 src/windows-emulator-test/static_socket_factory.hpp create mode 100644 src/windows-emulator/network/i_socket.hpp create mode 100644 src/windows-emulator/network/socket_factory.cpp create mode 100644 src/windows-emulator/network/socket_factory.hpp create mode 100644 src/windows-emulator/network/socket_wrapper.cpp create mode 100644 src/windows-emulator/network/socket_wrapper.hpp diff --git a/src/common/network/socket.hpp b/src/common/network/socket.hpp index 957c9c1b..bd941364 100644 --- a/src/common/network/socket.hpp +++ b/src/common/network/socket.hpp @@ -8,6 +8,7 @@ #ifdef _WIN32 using send_size = int; +using sent_size = int; #define GET_SOCKET_ERROR() (WSAGetLastError()) #define poll WSAPoll #define SERR(x) (WSA##x) @@ -15,6 +16,7 @@ using send_size = int; #else using SOCKET = int; using send_size = size_t; +using sent_size = ssize_t; #define INVALID_SOCKET (SOCKET)(~0) #define SOCKET_ERROR (-1) #define GET_SOCKET_ERROR() (errno) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 5ec4c9b6..9efc5925 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -400,16 +400,10 @@ void print_time() int main(const int argc, const char* argv[]) { - bool reproducible = false; - if (argc == 2) + if (argc == 2 && argv[1] == "-time"sv) { - if (argv[1] == "-time"sv) - { - print_time(); - return 0; - } - - reproducible = argv[1] == "-reproducible"sv; + print_time(); + return 0; } bool valid = true; @@ -423,13 +417,9 @@ int main(const int argc, const char* argv[]) RUN_TEST(test_exceptions, "Exceptions") RUN_TEST(test_native_exceptions, "Native Exceptions") RUN_TEST(test_tls, "TLS") + RUN_TEST(test_socket, "Socket") Sleep(1); - if (!reproducible) - { - RUN_TEST(test_socket, "Socket") - } - return valid ? 0 : 1; } diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index cab014c1..67776802 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -4,6 +4,8 @@ #include #include +#include "static_socket_factory.hpp" + #define ASSERT_NOT_TERMINATED(win_emu) \ do \ { \ @@ -40,7 +42,6 @@ namespace test struct sample_configuration { - bool reproducible{false}; bool print_time{false}; }; @@ -53,11 +54,6 @@ namespace test settings.arguments.emplace_back(u"-time"); } - if (config.reproducible) - { - settings.arguments.emplace_back(u"-reproducible"); - } - return settings; } @@ -74,7 +70,6 @@ namespace test settings.emulation_root = get_emulator_root(); - settings.port_mappings[28970] = static_cast(getpid()); settings.path_mappings["C:\\a.txt"] = std::filesystem::temp_directory_path() / ("emulator-test-file-" + std::to_string(getpid()) + ".txt"); @@ -82,6 +77,9 @@ namespace test get_sample_app_settings(config), settings, std::move(callbacks), + emulator_interfaces{ + .socket_factory = network::create_static_socket_factory(), + }, }; } @@ -97,7 +95,7 @@ namespace test inline windows_emulator create_reproducible_sample_emulator() { - return create_sample_emulator({.reproducible = true}); + return create_sample_emulator(); } inline void bisect_emulation(windows_emulator& emu) diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp index 803d4046..8518537b 100644 --- a/src/windows-emulator-test/serialization_test.cpp +++ b/src/windows-emulator-test/serialization_test.cpp @@ -84,7 +84,13 @@ namespace test utils::buffer_deserializer deserializer{serializer.get_buffer()}; - windows_emulator new_emu{{.emulation_root = get_emulator_root(), .use_relative_time = true}}; + windows_emulator new_emu{ + {.emulation_root = get_emulator_root(), .use_relative_time = true}, + { + .socket_factory = network::create_static_socket_factory(), + }, + }; + new_emu.log.disable_output(true); new_emu.deserialize(deserializer); diff --git a/src/windows-emulator-test/static_socket_factory.cpp b/src/windows-emulator-test/static_socket_factory.cpp new file mode 100644 index 00000000..c12cdd38 --- /dev/null +++ b/src/windows-emulator-test/static_socket_factory.cpp @@ -0,0 +1,129 @@ +#include "static_socket_factory.hpp" + +#include +#include +#include + +#include + +namespace network +{ + namespace + { + struct static_socket_factory : socket_factory + { + using packet_data = std::vector; + using packet = std::pair; + using packet_queue = std::queue; + using packet_mapping = std::unordered_map; + std::shared_ptr packets = std::make_shared(); + + uint16_t port{0}; + + struct static_socket : i_socket + { + int error{0}; + address a{}; + std::shared_ptr packets{}; + + static_socket(static_socket_factory& f, const int af) + : packets(f.packets) + { + if (af == AF_INET) + { + a.set_ipv4(0); + } + else if (af == AF_INET6) + { + a.set_ipv6({}); + } + else + { + throw std::runtime_error("Invalid address family"); + } + + a.set_port(++f.port); + } + + ~static_socket() override = default; + + void set_blocking(const bool blocking) override + { + if (blocking) + { + throw std::runtime_error("Blocking sockets not supported yet!"); + } + } + + int get_last_error() override + { + return this->error; + } + + bool is_ready(const bool) override + { + return true; + } + + bool bind(const address& addr) override + { + this->a = addr; + return true; + } + + sent_size send(std::span) override + { + throw std::runtime_error("Not implemented"); + } + + sent_size sendto(const address& destination, std::span data) override + { + this->error = 0; + (*this->packets)[destination].emplace(this->a, packet_data{data.begin(), data.end()}); + return static_cast(data.size()); + } + + sent_size recv(std::span) override + { + throw std::runtime_error("Not implemented"); + } + + sent_size recvfrom(address& source, std::span data) override + { + this->error = 0; + + auto& q = (*this->packets)[this->a]; + + if (q.empty()) + { + this->error = SERR(EWOULDBLOCK); + return -1; + } + + const auto p = std::move(q.front()); + q.pop(); + + memcpy(data.data(), p.second.data(), std::min(data.size(), p.second.size())); + + source = p.first; + return static_cast(p.second.size()); + } + }; + + std::unique_ptr create_socket(const int af, const int, const int) override + { + return std::make_unique(*this, af); + } + + int poll_sockets(std::span) override + { + throw std::runtime_error("Not implemented"); + } + }; + } + + std::unique_ptr create_static_socket_factory() + { + return std::make_unique(); + } +} diff --git a/src/windows-emulator-test/static_socket_factory.hpp b/src/windows-emulator-test/static_socket_factory.hpp new file mode 100644 index 00000000..6f162869 --- /dev/null +++ b/src/windows-emulator-test/static_socket_factory.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace network +{ + std::unique_ptr create_static_socket_factory(); +} diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index f2885659..73245080 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -3,6 +3,7 @@ #include "afd_types.hpp" #include "../windows_emulator.hpp" +#include "../network/socket_factory.hpp" #include #include @@ -313,10 +314,10 @@ namespace } NTSTATUS perform_poll(windows_emulator& win_emu, const io_device_context& c, - const std::span endpoints, + const std::span endpoints, const std::span handles) { - std::vector poll_data{}; + std::vector poll_data{}; poll_data.resize(endpoints.size()); for (size_t i = 0; i < endpoints.size() && i < handles.size(); ++i) @@ -324,12 +325,12 @@ namespace auto& pfd = poll_data.at(i); const auto& handle = handles[i]; - pfd.fd = endpoints[i]; + pfd.s = endpoints[i]; pfd.events = map_afd_request_events_to_socket(handle.PollEvents); pfd.revents = pfd.events; } - const auto count = poll(poll_data.data(), static_cast(poll_data.size()), 0); + const auto count = win_emu.socket_factory().poll_sockets(poll_data); if (count <= 0) { return STATUS_PENDING; @@ -358,17 +359,20 @@ namespace assert(current_index == static_cast(count)); - emulator_object{win_emu.emu(), c.input_buffer}.access( - [&](AFD_POLL_INFO64& info) { info.NumberOfHandles = static_cast(current_index); }); + const emulator_object info_obj{win_emu.emu(), c.input_buffer}; + info_obj.access([&](AFD_POLL_INFO64& info) { + info.NumberOfHandles = static_cast(current_index); // + }); return STATUS_SUCCESS; } struct afd_endpoint : io_device { + std::unique_ptr s_{}; + bool executing_delayed_ioctl_{}; std::optional creation_data{}; - std::optional s_{}; std::optional require_poll_{}; std::optional delayed_ioctl_{}; std::optional timeout_{}; @@ -381,21 +385,15 @@ namespace afd_endpoint(afd_endpoint&&) = delete; afd_endpoint& operator=(afd_endpoint&&) = delete; - ~afd_endpoint() override - { - if (this->s_) - { - closesocket(*this->s_); - } - } + ~afd_endpoint() override = default; void create(windows_emulator& win_emu, const io_device_creation_data& data) override { this->creation_data = get_creation_data(win_emu, data); - this->setup(); + this->setup(win_emu.socket_factory()); } - void setup() + void setup(network::socket_factory& factory) { if (!this->creation_data) { @@ -408,15 +406,13 @@ namespace const auto type = translate_win_to_host_type(data.type); const auto protocol = translate_win_to_host_protocol(data.protocol); - const auto sock = socket(af, type, protocol); - if (sock == INVALID_SOCKET) + this->s_ = factory.create_socket(af, type, protocol); + if (!this->s_) { throw std::runtime_error("Failed to create socket!"); } - network::socket::set_blocking(sock, false); - - this->s_ = sock; + this->s_->set_blocking(false); } void delay_ioctrl(const io_device_context& c, @@ -452,7 +448,7 @@ namespace if (this->require_poll_.has_value()) { - const auto is_ready = network::socket::is_socket_ready(*this->s_, *this->require_poll_); + const auto is_ready = this->s_->is_ready(*this->require_poll_); if (!is_ready) { return; @@ -482,7 +478,7 @@ namespace void deserialize_object(utils::buffer_deserializer& buffer) override { buffer.read_optional(this->creation_data); - this->setup(); + this->setup(buffer.read()); buffer.read_optional(this->require_poll_); buffer.read_optional(this->delayed_ioctl_); @@ -546,7 +542,7 @@ namespace const auto addr = convert_to_host_address(win_emu, std::span(data).subspan(address_offset)); - if (bind(*this->s_, &addr.get_addr(), addr.get_size()) == SOCKET_ERROR) + if (!this->s_->bind(addr)) { return STATUS_ADDRESS_ALREADY_ASSOCIATED; } @@ -554,12 +550,12 @@ namespace return STATUS_SUCCESS; } - static std::vector resolve_endpoints(windows_emulator& win_emu, - const std::span handles) + static std::vector resolve_endpoints(windows_emulator& win_emu, + const std::span handles) { auto& proc = win_emu.process; - std::vector endpoints{}; + std::vector endpoints{}; endpoints.reserve(handles.size()); for (const auto& handle : handles) @@ -576,7 +572,7 @@ namespace throw std::runtime_error("Invalid AFD endpoint!"); } - endpoints.push_back(*endpoint->s_); + endpoints.push_back(endpoint->s_.get()); } return endpoints; @@ -635,17 +631,14 @@ namespace } network::address from{}; - auto from_length = from.get_max_size(); - - std::vector data{}; + std::vector data{}; data.resize(buffer.len); - const auto recevied_data = recvfrom(*this->s_, data.data(), static_cast(data.size()), 0, - &from.get_addr(), &from_length); + const auto recevied_data = this->s_->recvfrom(from, data); if (recevied_data < 0) { - const auto error = GET_SOCKET_ERROR(); + const auto error = this->s_->get_last_error(); if (error == SERR(EWOULDBLOCK)) { this->delay_ioctrl(c, {}, true); @@ -655,8 +648,6 @@ namespace return STATUS_UNSUCCESSFUL; } - assert(from.get_size() == from_length); - const auto data_size = std::min(data.size(), static_cast(recevied_data)); emu.write_memory(buffer.buf, data.data(), data_size); @@ -704,13 +695,10 @@ namespace const auto target = convert_to_host_address(win_emu, address_buffer); const auto data = emu.read_memory(buffer.buf, buffer.len); - const auto sent_data = - sendto(*this->s_, reinterpret_cast(data.data()), static_cast(data.size()), - 0 /* TODO */, &target.get_addr(), target.get_size()); - + const auto sent_data = this->s_->sendto(target, data); if (sent_data < 0) { - const auto error = GET_SOCKET_ERROR(); + const auto error = this->s_->get_last_error(); if (error == SERR(EWOULDBLOCK)) { this->delay_ioctrl(c, {}, false); diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index 05adfcae..e2e28995 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -8,6 +8,11 @@ #include +namespace network +{ + struct socket_factory; +} + // TODO: Replace with pointer handling structure for future 32 bit support using emulator_pointer = uint64_t; @@ -51,6 +56,7 @@ using memory_manager_wrapper = object_wrapper; using module_manager_wrapper = object_wrapper; using process_context_wrapper = object_wrapper; using windows_emulator_wrapper = object_wrapper; +using socket_factory_wrapper = object_wrapper; template class emulator_object diff --git a/src/windows-emulator/network/i_socket.hpp b/src/windows-emulator/network/i_socket.hpp new file mode 100644 index 00000000..9b8615a1 --- /dev/null +++ b/src/windows-emulator/network/i_socket.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +namespace network +{ + struct i_socket + { + virtual ~i_socket() = default; + + virtual void set_blocking(bool blocking) = 0; + + virtual int get_last_error() = 0; + + virtual bool is_ready(bool in_poll) = 0; + + virtual bool bind(const address& addr) = 0; + + virtual sent_size send(std::span data) = 0; + virtual sent_size sendto(const address& destination, std::span data) = 0; + + virtual sent_size recv(std::span data) = 0; + virtual sent_size recvfrom(address& source, std::span data) = 0; + }; +} diff --git a/src/windows-emulator/network/socket_factory.cpp b/src/windows-emulator/network/socket_factory.cpp new file mode 100644 index 00000000..fb954ad3 --- /dev/null +++ b/src/windows-emulator/network/socket_factory.cpp @@ -0,0 +1,55 @@ +#include "socket_factory.hpp" +#include "socket_wrapper.hpp" + +namespace network +{ + socket_factory::socket_factory() + { + initialize_wsa(); + } + + std::unique_ptr socket_factory::create_socket(int af, int type, int protocol) + { + return std::make_unique(af, type, protocol); + } + + int socket_factory::poll_sockets(const std::span entries) + { + std::vector poll_data{}; + poll_data.reserve(entries.size()); + + for (const auto& entry : entries) + { + if (!entry.s) + { + throw std::runtime_error("Bad socket given!"); + } + + const auto* wrapper = dynamic_cast(entry.s); + if (!wrapper) + { + throw std::runtime_error("Socket was not created using the given factory"); + } + + pollfd fd{}; + fd.fd = wrapper->get().get_socket(); + fd.events = entry.events; + fd.revents = entry.revents; + + poll_data.push_back(fd); + } + + const auto res = poll(poll_data.data(), static_cast(poll_data.size()), 0); + + for (size_t i = 0; i < poll_data.size() && i < entries.size(); ++i) + { + auto& entry = entries[i]; + const auto& fd = poll_data[i]; + + entry.events = fd.events; + entry.revents = fd.revents; + } + + return res; + } +} diff --git a/src/windows-emulator/network/socket_factory.hpp b/src/windows-emulator/network/socket_factory.hpp new file mode 100644 index 00000000..5460c54c --- /dev/null +++ b/src/windows-emulator/network/socket_factory.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "i_socket.hpp" + +#include + +namespace network +{ + struct poll_entry + { + i_socket* s{}; + int16_t events{}; + int16_t revents{}; + }; + + struct socket_factory + { + socket_factory(); + virtual ~socket_factory() = default; + + virtual std::unique_ptr create_socket(int af, int type, int protocol); + virtual int poll_sockets(std::span entries); + }; +} diff --git a/src/windows-emulator/network/socket_wrapper.cpp b/src/windows-emulator/network/socket_wrapper.cpp new file mode 100644 index 00000000..60ee4828 --- /dev/null +++ b/src/windows-emulator/network/socket_wrapper.cpp @@ -0,0 +1,59 @@ +#include "socket_wrapper.hpp" +#include + +namespace network +{ + socket_wrapper::socket_wrapper(const int af, const int type, const int protocol) + : socket_(af, type, protocol) + { + } + + void socket_wrapper::set_blocking(const bool blocking) + { + this->socket_.set_blocking(blocking); + } + + int socket_wrapper::get_last_error() + { + return GET_SOCKET_ERROR(); + } + + bool socket_wrapper::is_ready(const bool in_poll) + { + return this->socket_.is_ready(in_poll); + } + + bool socket_wrapper::bind(const address& addr) + { + return this->socket_.bind(addr); + } + + sent_size socket_wrapper::send(const std::span data) + { + return ::send(this->socket_.get_socket(), reinterpret_cast(data.data()), + static_cast(data.size()), 0); + } + + sent_size socket_wrapper::sendto(const address& destination, const std::span data) + { + return ::sendto(this->socket_.get_socket(), reinterpret_cast(data.data()), + static_cast(data.size()), 0, &destination.get_addr(), destination.get_size()); + } + + sent_size socket_wrapper::recv(std::span data) + { + return ::recv(this->socket_.get_socket(), reinterpret_cast(data.data()), + static_cast(data.size()), 0); + } + + sent_size socket_wrapper::recvfrom(address& source, std::span data) + { + auto source_length = source.get_max_size(); + const auto res = ::recvfrom(this->socket_.get_socket(), reinterpret_cast(data.data()), + static_cast(data.size()), 0, &source.get_addr(), &source_length); + + assert(source.get_size() == source_length); + + return res; + } +} diff --git a/src/windows-emulator/network/socket_wrapper.hpp b/src/windows-emulator/network/socket_wrapper.hpp new file mode 100644 index 00000000..569e170c --- /dev/null +++ b/src/windows-emulator/network/socket_wrapper.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "i_socket.hpp" + +namespace network +{ + class socket_wrapper : public i_socket + { + public: + socket_wrapper(int af, int type, int protocol); + ~socket_wrapper() override = default; + + void set_blocking(bool blocking) override; + + int get_last_error() override; + + bool is_ready(bool in_poll) override; + + bool bind(const address& addr) override; + + sent_size send(std::span data) override; + sent_size sendto(const address& destination, std::span data) override; + + sent_size recv(std::span data) override; + sent_size recvfrom(address& source, std::span data) override; + + const socket& get() const + { + return this->socket_; + } + + private: + socket socket_{}; + }; +} diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 0a58c31a..8a837876 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -179,8 +179,14 @@ namespace } }; - std::unique_ptr get_clock(const uint64_t& instructions, const bool use_relative_time) + std::unique_ptr get_clock(emulator_interfaces& interfaces, const uint64_t& instructions, + const bool use_relative_time) { + if (interfaces.clock) + { + return std::move(interfaces.clock); + } + if (use_relative_time) { return std::make_unique(instructions); @@ -188,6 +194,15 @@ namespace return std::make_unique(); } + std::unique_ptr get_socket_factory(emulator_interfaces& interfaces) + { + if (interfaces.socket_factory) + { + return std::move(interfaces.socket_factory); + } + + return std::make_unique(); + } } std::unique_ptr create_default_x64_emulator() @@ -196,8 +211,9 @@ std::unique_ptr create_default_x64_emulator() } windows_emulator::windows_emulator(application_settings app_settings, const emulator_settings& settings, - emulator_callbacks callbacks, std::unique_ptr emu) - : windows_emulator(settings, std::move(emu)) + emulator_callbacks callbacks, emulator_interfaces interfaces, + std::unique_ptr emu) + : windows_emulator(settings, std::move(interfaces), std::move(emu)) { this->callbacks = std::move(callbacks); @@ -205,9 +221,11 @@ windows_emulator::windows_emulator(application_settings app_settings, const emul this->setup_process(app_settings); } -windows_emulator::windows_emulator(const emulator_settings& settings, std::unique_ptr emu) +windows_emulator::windows_emulator(const emulator_settings& settings, emulator_interfaces interfaces, + std::unique_ptr emu) : emu_(std::move(emu)), - clock_(get_clock(this->executed_instructions_, settings.use_relative_time)), + clock_(get_clock(interfaces, this->executed_instructions_, settings.use_relative_time)), + socket_factory_(get_socket_factory(interfaces)), emulation_root{settings.emulation_root.empty() ? settings.emulation_root : absolute(settings.emulation_root)}, file_sys(emulation_root.empty() ? emulation_root : emulation_root / "filesys"), memory(*this->emu_), @@ -556,6 +574,10 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) return clock_wrapper{this->clock()}; // }); + buffer.register_factory([this] { + return socket_factory_wrapper{this->socket_factory()}; // + }); + buffer.read(this->executed_instructions_); buffer.read(this->switch_thread_); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 8d5eed04..e1ad9533 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -11,6 +11,7 @@ #include "file_system.hpp" #include "memory_manager.hpp" #include "module/module_manager.hpp" +#include "network/socket_factory.hpp" std::unique_ptr create_default_x64_emulator(); @@ -45,12 +46,19 @@ struct emulator_settings std::set> modules{}; }; +struct emulator_interfaces +{ + std::unique_ptr clock{}; + std::unique_ptr socket_factory{}; +}; + class windows_emulator { uint64_t executed_instructions_{0}; std::unique_ptr emu_{}; std::unique_ptr clock_{}; + std::unique_ptr socket_factory_{}; public: std::filesystem::path emulation_root{}; @@ -63,10 +71,10 @@ class windows_emulator process_context process; syscall_dispatcher dispatcher; - windows_emulator(const emulator_settings& settings = {}, + windows_emulator(const emulator_settings& settings = {}, emulator_interfaces interfaces = {}, std::unique_ptr emu = create_default_x64_emulator()); windows_emulator(application_settings app_settings, const emulator_settings& settings = {}, - emulator_callbacks callbacks = {}, + emulator_callbacks callbacks = {}, emulator_interfaces interfaces = {}, std::unique_ptr emu = create_default_x64_emulator()); windows_emulator(windows_emulator&&) = delete; @@ -96,6 +104,16 @@ class windows_emulator return *this->clock_; } + network::socket_factory& socket_factory() + { + return *this->socket_factory_; + } + + const network::socket_factory& socket_factory() const + { + return *this->socket_factory_; + } + emulator_thread& current_thread() const { if (!this->process.active_thread)