From a2a12084b0d95e9f48216a8c90e1c06b722d4a7a Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 27 Jul 2022 23:43:31 +0200 Subject: [PATCH 1/2] uds wip --- src/proxyfmu/client/proxy_slave.cpp | 26 +++--- src/proxyfmu/process_helper.hpp | 30 +++--- tool/booter/boot_service_handler.cpp | 8 +- tool/proxyfmu.cpp | 132 +++++++++++++++++++++------ 4 files changed, 139 insertions(+), 57 deletions(-) diff --git a/src/proxyfmu/client/proxy_slave.cpp b/src/proxyfmu/client/proxy_slave.cpp index fcddc95..7fb0eca 100644 --- a/src/proxyfmu/client/proxy_slave.cpp +++ b/src/proxyfmu/client/proxy_slave.cpp @@ -51,20 +51,23 @@ proxy_slave::proxy_slave( : fmilibcpp::slave(instanceName) , modelDescription_(std::move(modelDescription)) { - int port = -1; - std::string host; + std::shared_ptr socket; if (!remote) { - host = "localhost"; std::mutex mtx; std::condition_variable cv; - thread_ = std::make_unique(&start_process, fmuPath, instanceName, std::ref(port), std::ref(mtx), std::ref(cv)); + std::string bind; + thread_ = std::make_unique(&start_process, fmuPath, instanceName, std::ref(bind), std::ref(mtx), std::ref(cv), true); std::unique_lock lck(mtx); - while (port == -1) cv.wait(lck); + while (bind.empty()) cv.wait(lck); + if (bind != "-") { + socket = std::make_shared(bind); + } + } else { - host = remote->host; - std::shared_ptr socket(new TSocket(host, remote->port)); - auto transport = std::make_shared(socket); + std::string host = remote->host; + std::shared_ptr tmp_socket(new TSocket(host, remote->port)); + auto transport = std::make_shared(tmp_socket); std::shared_ptr protocol(new TBinaryProtocol(transport)); auto client = std::make_shared(protocol); transport->open(); @@ -73,16 +76,17 @@ proxy_slave::proxy_slave( read_data(fmuPath.string(), data); const std::string fmuName = proxyfmu::filesystem::path(fmuPath).stem().string(); - port = client->loadFromBinaryData(fmuName, instanceName, data); + int port = client->loadFromBinaryData(fmuName, instanceName, data); transport->close(); + + socket = std::make_shared("localhost", port); } - if (port == -999) { + if (!socket) { if (thread_) thread_->join(); throw std::runtime_error("[proxyfmu] Unable to bind to external proxy process!"); } - std::shared_ptr socket(new TSocket(host, port)); transport_ = std::make_shared(socket); std::shared_ptr protocol(new TBinaryProtocol(transport_)); client_ = std::make_shared(protocol); diff --git a/src/proxyfmu/process_helper.hpp b/src/proxyfmu/process_helper.hpp index 72ec7f9..4d19840 100644 --- a/src/proxyfmu/process_helper.hpp +++ b/src/proxyfmu/process_helper.hpp @@ -16,12 +16,17 @@ namespace proxyfmu { +std::string boolToStr(bool b) { + return b ? "true" : "false"; +} + void start_process( const proxyfmu::filesystem::path& fmuPath, const std::string& instanceName, - int& port, + std::string& bind, std::mutex& mtx, - std::condition_variable& cv) + std::condition_variable& cv, + bool localhost) { proxyfmu::filesystem::path executable; @@ -31,16 +36,6 @@ void start_process( executable = "proxyfmu.exe"; #endif - if (!proxyfmu::filesystem::exists(executable)) { - boost::dll::fs::error_code ec; - boost::dll::fs::path loc = boost::dll::program_location(ec); - if (!ec.failed()) { - executable = loc.parent_path().string() / executable; - } else { - std::cerr << "[proxyfmu] Error, unable to locate parent executable" << std::endl; - } - } - if (!proxyfmu::filesystem::exists(executable)) { auto execPath = proxyfmu::filesystem::absolute(executable).string(); throw std::runtime_error("[proxyfmu] No proxyfmu executable found. " + execPath + " does not exist!"); @@ -59,7 +54,7 @@ void start_process( std::cout << "\n"; std::cout << "[proxyfmu] Booting FMU instance '" << instanceName << "'.." << std::endl; - std::string cmd(execStr + " --fmu \"" + fmuPath.string() + "\" --instanceName " + instanceName); + std::string cmd(execStr + " --fmu \"" + fmuPath.string() + "\" --instanceName " + instanceName + " --localhost " + boolToStr(localhost)); boost::process::ipstream pipe_stream; boost::process::child c(cmd, boost::process::std_out > pipe_stream); @@ -70,8 +65,11 @@ void start_process( if (!bound && line.substr(0, 16) == "[proxyfmu] port=") { { std::lock_guard lck(mtx); - port = std::stoi(line.substr(16)); - std::cout << "[proxyfmu] FMU instance '" << instanceName << "' instantiated using port " << port << std::endl; + bind = line.substr(16); + if (bind.back() == '\r' || bind.back() == '\n') { + bind.pop_back(); + } + std::cout << "[proxyfmu] FMU instance '" << instanceName << "' instantiated and bound to " << bind << std::endl; } cv.notify_one(); bound = true; @@ -92,7 +90,7 @@ void start_process( << instanceName << "' returned with status " << std::to_string(status) << ". Unable to bind.." << std::endl; std::lock_guard lck(mtx); - port = -999; + bind = "-"; cv.notify_one(); } diff --git a/tool/booter/boot_service_handler.cpp b/tool/booter/boot_service_handler.cpp index 1be3241..15db967 100644 --- a/tool/booter/boot_service_handler.cpp +++ b/tool/booter/boot_service_handler.cpp @@ -27,17 +27,17 @@ int32_t boot_service_handler::loadFromBinaryData(const std::string& fmuName, con write_data(fmuPath, data); - int port = -1; + std::string bind; std::mutex mtx; std::condition_variable cv; - auto t = std::make_unique(&start_process, fmuPath, instanceName, std::ref(port), std::ref(mtx), std::ref(cv)); + auto t = std::make_unique(&start_process, fmuPath, instanceName, std::ref(bind), std::ref(mtx), std::ref(cv) , false); processes_.emplace_back(std::move(t)); dirs_.emplace_back(std::move(tmp)); std::unique_lock lck(mtx); - while (port == -1) cv.wait(lck); + while (bind.empty()) cv.wait(lck); - return port; + return std::stoi(bind); } boot_service_handler::~boot_service_handler() diff --git a/tool/proxyfmu.cpp b/tool/proxyfmu.cpp index 7c41410..74e6787 100644 --- a/tool/proxyfmu.cpp +++ b/tool/proxyfmu.cpp @@ -4,14 +4,18 @@ #include #include #include +#include #include #include -#include +#include #include #include +#include #include +#include +#include #include using namespace proxyfmu::thrift; @@ -25,6 +29,61 @@ using namespace ::apache::thrift::transport; namespace { +class raii_path +{ + +public: + explicit raii_path(proxyfmu::filesystem::path path) + : path_(std::move(path)) + { } + + [[nodiscard]] std::string string() const + { + return path_.string(); + } + + ~raii_path() + { + proxyfmu::filesystem::remove_all(path_); + } + +private: + proxyfmu::filesystem::path path_; +}; + +std::string generate_uuid() +{ + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_int_distribution<> dis(0, 15); + static std::uniform_int_distribution<> dis2(8, 11); + + int i; + std::stringstream ss; + ss << std::hex; + for (i = 0; i < 8; i++) { + ss << dis(gen); + } + ss << "-"; + for (i = 0; i < 4; i++) { + ss << dis(gen); + } + ss << "-4"; + for (i = 0; i < 3; i++) { + ss << dis(gen); + } + ss << "-"; + ss << dis2(gen); + for (i = 0; i < 3; i++) { + ss << dis(gen); + } + ss << "-"; + for (i = 0; i < 12; i++) { + ss << dis(gen); + } + return ss.str(); +} + class ServerReadyEventHandler : public TServerEventHandler { @@ -51,7 +110,7 @@ const int SUCCESS = 0; const int COMMANDLINE_ERROR = 1; const int UNHANDLED_ERROR = 2; -int run_application(const std::string& fmu, const std::string& instanceName) +int run_application(const std::string& fmu, const std::string& instanceName, bool localhost) { std::unique_ptr server; auto stop = [&]() { @@ -63,40 +122,60 @@ int run_application(const std::string& fmu, const std::string& instanceName) std::shared_ptr transportFactory(new TFramedTransportFactory()); std::shared_ptr protocolFactory(new TBinaryProtocolFactory()); - proxyfmu::fixed_range_random_generator rng(port_range_min, port_range_max); + if (!localhost) { + proxyfmu::fixed_range_random_generator rng(port_range_min, port_range_max); + + int port; + int final_port = -1; + for (auto i = 0; i < max_port_retries; i++) { + port = rng.next(); + + std::shared_ptr serverTransport(new TServerSocket(port)); + server = std::make_unique(processor, serverTransport, transportFactory, protocolFactory); + server->setServerEventHandler(std::make_shared([port, &final_port] { + final_port = port; + std::cout << "[proxyfmu] port=" << std::to_string(final_port) << std::endl; + })); + + try { - int port; - int final_port = -1; - for (auto i = 0; i < max_port_retries; i++) { - port = rng.next(); + server->serve(); + break; + + } catch (TTransportException& ex) { + std::cout << "[proxyfmu] " << ex.what() + << ". Failed to bind to port " << std::to_string(port) + << ". Retrying with another one. Attempt " << std::to_string(i + 1) + << " of " << std::to_string(max_port_retries) << ".." << std::endl; + } + } + + if (final_port != -1) { + return SUCCESS; + } else { + std::cerr << "[proxyfmu] Unable to bind after max number of retries.." << std::endl; + return UNHANDLED_ERROR; + } - std::shared_ptr serverTransport(new TServerSocket(port)); + } else { + + raii_path uds{"uds_" + generate_uuid() + ".binary.thrift"}; + std::shared_ptr serverTransport(new TServerSocket(uds.string())); server = std::make_unique(processor, serverTransport, transportFactory, protocolFactory); - server->setServerEventHandler(std::make_shared([port, &final_port] { - final_port = port; - std::cout << "[proxyfmu] port=" << std::to_string(final_port) << std::endl; + + server->setServerEventHandler(std::make_shared([&uds] { + std::cout << "[proxyfmu] port=" << uds.string() << std::endl; })); try { - server->serve(); - break; + return SUCCESS; } catch (TTransportException& ex) { - std::cout << "[proxyfmu] " << ex.what() - << ". Failed to bind to port " << std::to_string(port) - << ". Retrying with another one. Attempt " << std::to_string(i + 1) - << " of " << std::to_string(max_port_retries) << ".." << std::endl; + std::cerr << "[proxyfmu] " << ex.what() << std::endl; + return UNHANDLED_ERROR; } } - - if (final_port != -1) { - return SUCCESS; - } else { - std::cerr << "[proxyfmu] Unable to bind after max number of retries.." << std::endl; - return UNHANDLED_ERROR; - } - } int printHelp(boost::program_options::options_description& desc) @@ -125,6 +204,7 @@ int main(int argc, char** argv) desc.add_options()("version,v", "Print program version."); desc.add_options()("fmu", po::value()->required(), "Location of the fmu to load."); desc.add_options()("instanceName", po::value()->required(), "Name of the slave instance."); + desc.add_options()("localhost", po::value()->required(), "Running on localhost?"); if (argc == 1) { return printHelp(desc); @@ -161,7 +241,7 @@ int main(int argc, char** argv) const auto instanceName = vm["instanceName"].as(); - return run_application(fmu, instanceName); + return run_application(fmu, instanceName, vm["localhost"].as()); } catch (const std::exception& e) { std::cerr << "[proxyfmu] Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << std::endl; From 287fa173619a22f331f44fe91796d2609ef1b1f0 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 6 Aug 2022 22:24:27 +0200 Subject: [PATCH 2/2] refactor --- include/proxyfmu/lib_info.hpp | 2 +- src/CMakeLists.txt | 2 -- src/proxyfmu/client/proxy_fmu.cpp | 4 +++- src/proxyfmu/client/proxy_slave.cpp | 2 +- src/proxyfmu/lib_info.cpp.in | 2 +- src/proxyfmu/process_helper.hpp | 3 ++- tool/booter/boot_service_handler.hpp | 6 +++--- .../proxyfmu => tool}/fixed_range_random_generator.hpp | 0 tool/proxyfmu.cpp | 10 ++++------ {include/proxyfmu => tool}/temp_dir.hpp | 2 +- 10 files changed, 16 insertions(+), 17 deletions(-) rename {include/proxyfmu => tool}/fixed_range_random_generator.hpp (100%) rename {include/proxyfmu => tool}/temp_dir.hpp (96%) diff --git a/include/proxyfmu/lib_info.hpp b/include/proxyfmu/lib_info.hpp index 65882a7..c9ee227 100644 --- a/include/proxyfmu/lib_info.hpp +++ b/include/proxyfmu/lib_info.hpp @@ -13,7 +13,7 @@ struct version int patch = 0; }; -/// Returns the version of the libcosim library. +/// Returns the version of the proxyfmu library. version library_version(); } // namespace proxyfmu diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1529fd9..c3b05dc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,11 +9,9 @@ set(generatedSourcesDir "${CMAKE_BINARY_DIR}/generated") set(commonPublicHeaders - "proxyfmu/fixed_range_random_generator.hpp" "proxyfmu/fs_portability.hpp" "proxyfmu/lib_info.hpp" "proxyfmu/remote_info.hpp" - "proxyfmu/temp_dir.hpp" ) diff --git a/src/proxyfmu/client/proxy_fmu.cpp b/src/proxyfmu/client/proxy_fmu.cpp index 1f74604..b12f79a 100644 --- a/src/proxyfmu/client/proxy_fmu.cpp +++ b/src/proxyfmu/client/proxy_fmu.cpp @@ -17,7 +17,9 @@ proxy_fmu::proxy_fmu(const filesystem::path& fmuPath, std::optional , remote_(std::move(remote)) , modelDescription_(fmilibcpp::loadFmu(fmuPath)->get_model_description()) { - if (!exists(fmuPath)) throw std::runtime_error("No such file: " + filesystem::absolute(fmuPath).string() + "!"); + if (!exists(fmuPath)) { + throw std::runtime_error("No such file: " + filesystem::absolute(fmuPath).string() + "!"); + } } const fmilibcpp::model_description& proxy_fmu::get_model_description() const diff --git a/src/proxyfmu/client/proxy_slave.cpp b/src/proxyfmu/client/proxy_slave.cpp index 7fb0eca..acfa2dc 100644 --- a/src/proxyfmu/client/proxy_slave.cpp +++ b/src/proxyfmu/client/proxy_slave.cpp @@ -87,7 +87,7 @@ proxy_slave::proxy_slave( throw std::runtime_error("[proxyfmu] Unable to bind to external proxy process!"); } - transport_ = std::make_shared(socket); + transport_ = std::make_shared(socket); std::shared_ptr protocol(new TBinaryProtocol(transport_)); client_ = std::make_shared(protocol); transport_->open(); diff --git a/src/proxyfmu/lib_info.cpp.in b/src/proxyfmu/lib_info.cpp.in index 3f1d0cc..8081c78 100644 --- a/src/proxyfmu/lib_info.cpp.in +++ b/src/proxyfmu/lib_info.cpp.in @@ -11,4 +11,4 @@ version library_version() // clang-format on } -} \ No newline at end of file +} diff --git a/src/proxyfmu/process_helper.hpp b/src/proxyfmu/process_helper.hpp index 4d19840..6f63e54 100644 --- a/src/proxyfmu/process_helper.hpp +++ b/src/proxyfmu/process_helper.hpp @@ -16,7 +16,8 @@ namespace proxyfmu { -std::string boolToStr(bool b) { +std::string boolToStr(bool b) +{ return b ? "true" : "false"; } diff --git a/tool/booter/boot_service_handler.hpp b/tool/booter/boot_service_handler.hpp index 3cf9548..c746a47 100644 --- a/tool/booter/boot_service_handler.hpp +++ b/tool/booter/boot_service_handler.hpp @@ -2,9 +2,9 @@ #ifndef PROXYFMU_BOOT_SERVICE_HANDLER_HPP #define PROXYFMU_BOOT_SERVICE_HANDLER_HPP -#include -#include -#include +#include "../temp_dir.hpp" + +#include "proxyfmu/thrift/BootService.h" #include #include diff --git a/include/proxyfmu/fixed_range_random_generator.hpp b/tool/fixed_range_random_generator.hpp similarity index 100% rename from include/proxyfmu/fixed_range_random_generator.hpp rename to tool/fixed_range_random_generator.hpp diff --git a/tool/proxyfmu.cpp b/tool/proxyfmu.cpp index 74e6787..08cd893 100644 --- a/tool/proxyfmu.cpp +++ b/tool/proxyfmu.cpp @@ -1,10 +1,9 @@ +#include "fixed_range_random_generator.hpp" #include "fmu_service_handler.hpp" -#include -#include -#include -#include +#include "proxyfmu/fs_portability.hpp" +#include "proxyfmu/lib_info.hpp" #include #include @@ -15,7 +14,6 @@ #include #include #include -#include #include using namespace proxyfmu::thrift; @@ -119,7 +117,7 @@ int run_application(const std::string& fmu, const std::string& instanceName, boo std::shared_ptr handler(new fmu_service_handler(fmu, instanceName, stop)); std::shared_ptr processor(new FmuServiceProcessor(handler)); - std::shared_ptr transportFactory(new TFramedTransportFactory()); + std::shared_ptr transportFactory(new TBufferedTransportFactory()); std::shared_ptr protocolFactory(new TBinaryProtocolFactory()); if (!localhost) { diff --git a/include/proxyfmu/temp_dir.hpp b/tool/temp_dir.hpp similarity index 96% rename from include/proxyfmu/temp_dir.hpp rename to tool/temp_dir.hpp index e338485..c184c81 100644 --- a/include/proxyfmu/temp_dir.hpp +++ b/tool/temp_dir.hpp @@ -4,7 +4,7 @@ #include "fixed_range_random_generator.hpp" -#include +#include "proxyfmu/fs_portability.hpp" #include #include