From cfa18525cfb302ccfdc7de6fd8066c28756913ee Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 21 Feb 2020 09:45:03 -0800 Subject: [PATCH] update Config --- src/config.cpp | 76 ++++++++++++++++++++++++++++------------------- src/pvxs/client.h | 3 +- src/pvxs/server.h | 37 +++++++++++++++-------- src/server.cpp | 14 +++++++++ 4 files changed, 85 insertions(+), 45 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 63b03e8..019a19d 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -24,14 +24,14 @@ DEFINE_LOGGER(config, "pvxs.config"); namespace pvxs { namespace { -void split_addr_into(const char* name, std::vector& out, const char *inp) +void split_addr_into(const char* name, std::vector& out, const char *inp, uint16_t defaultPort) { std::regex word("\\s*(\\S+)(.*)"); std::cmatch M; while(*inp && std::regex_match(inp, M, word)) { sockaddr_in addr = {}; - if(aToIPAddr(M[1].str().c_str(), 0, &addr)) { + if(aToIPAddr(M[1].str().c_str(), defaultPort, &addr)) { log_err_printf(config, "%s ignoring invalid '%s'\n", name, M[1].str().c_str()); continue; } @@ -123,28 +123,9 @@ namespace server { Config Config::from_env() { Config ret; - ret.udp_port = 5076; const char* name; - if(const char *env = pickenv(&name, {"EPICS_PVAS_INTF_ADDR_LIST"})) { - split_addr_into(name, ret.interfaces, env); - } - - if(auto env = pickenv(&name, {"EPICS_PVAS_BEACON_ADDR_LIST", "EPICS_PVA_ADDR_LIST"})) { - split_addr_into(name, ret.beaconDestinations, env); - } - - if(const char *env = pickenv(&name, {"EPICS_PVAS_AUTO_BEACON_ADDR_LIST", "EPICS_PVA_AUTO_ADDR_LIST"})) { - if(epicsStrCaseCmp(env, "YES")==0) { - ret.auto_beacon = true; - } else if(epicsStrCaseCmp(env, "NO")==0) { - ret.auto_beacon = false; - } else { - log_err_printf(serversetup, "%s invalid bool value (YES/NO)", name); - } - } - if(const char *env = pickenv(&name, {"EPICS_PVAS_SERVER_PORT", "EPICS_PVA_SERVER_PORT"})) { try { ret.tcp_port = lexical_cast(env); @@ -161,6 +142,37 @@ Config Config::from_env() } } + if(const char *env = pickenv(&name, {"EPICS_PVAS_INTF_ADDR_LIST"})) { + split_addr_into(name, ret.interfaces, env, ret.tcp_port); + } + + if(auto env = pickenv(&name, {"EPICS_PVAS_BEACON_ADDR_LIST", "EPICS_PVA_ADDR_LIST"})) { + split_addr_into(name, ret.beaconDestinations, env, ret.udp_port); + } + + if(const char *env = pickenv(&name, {"EPICS_PVAS_AUTO_BEACON_ADDR_LIST", "EPICS_PVA_AUTO_ADDR_LIST"})) { + if(epicsStrCaseCmp(env, "YES")==0) { + ret.auto_beacon = true; + } else if(epicsStrCaseCmp(env, "NO")==0) { + ret.auto_beacon = false; + } else { + log_err_printf(serversetup, "%s invalid bool value (YES/NO)", name); + } + } + + return ret; +} + +Config Config::localhost() +{ + Config ret; + + ret.udp_port = 0u; + ret.tcp_port = 0u; + ret.interfaces.emplace_back("127.0.0.1"); + ret.auto_beacon = false; + ret.beaconDestinations.emplace_back("127.0.0.1"); + return ret; } @@ -226,8 +238,20 @@ Config Config::from_env() const char* name; + if(const char *env = pickenv(&name, {"EPICS_PVA_BROADCAST_PORT"})) { + try { + ret.udp_port = lexical_cast(env); + }catch(std::exception& e) { + log_err_printf(serversetup, "%s invalid integer : %s", name, e.what()); + } + } + if(ret.udp_port==0u) { + log_err_printf(serversetup, "ignoring EPICS_PVA_BROADCAST_PORT=%d", 0); + ret.udp_port = 5076; + } + if(const char *env = pickenv(&name, {"EPICS_PVA_ADDR_LIST"})) { - split_addr_into(name, ret.addressList, env); + split_addr_into(name, ret.addressList, env, ret.udp_port); } if(const char *env = pickenv(&name, {"EPICS_PVA_AUTO_ADDR_LIST"})) { @@ -240,14 +264,6 @@ Config Config::from_env() } } - if(const char *env = pickenv(&name, {"EPICS_PVA_BROADCAST_PORT"})) { - try { - ret.udp_port = lexical_cast(env); - }catch(std::exception& e) { - log_err_printf(serversetup, "%s invalid integer : %s", name, e.what()); - } - } - return ret; } diff --git a/src/pvxs/client.h b/src/pvxs/client.h index 05e7517..427c41c 100644 --- a/src/pvxs/client.h +++ b/src/pvxs/client.h @@ -216,8 +216,7 @@ struct PVXS_API Config { //! Create a new client Context using the current configuration. inline Context build() const { - Context ret(*this); - return ret; + return Context(*this); } }; diff --git a/src/pvxs/server.h b/src/pvxs/server.h index b313c17..2364b8d 100644 --- a/src/pvxs/server.h +++ b/src/pvxs/server.h @@ -22,6 +22,9 @@ #include namespace pvxs { +namespace client { +struct Config; +} namespace server { struct SharedPV; @@ -72,6 +75,10 @@ public: //! effective config const Config& config() const; + //! Create a client configuration which can communicate with this Server. + //! Suitable for use in self-contained unit-tests. + client::Config clientConfig() const; + //! Add a SharedPV to the builtin StaticSource Server& addPV(const std::string& name, const SharedPV& pv); //! Remove a SharedPV from the builtin StaticSource @@ -115,31 +122,35 @@ struct PVXS_API Config { //! Supplimented iif auto_beacon==true std::vector beaconDestinations; //! TCP port to bind. Default is 5075. May be zero. - unsigned short tcp_port; + unsigned short tcp_port = 5075; //! UDP port to bind. Default is 5076. May be zero, cf. Server::config() to find allocated port. - unsigned short udp_port; + unsigned short udp_port = 5076; //! Whether to populate the beacon address list automatically. (recommended) - bool auto_beacon; + bool auto_beacon = true; //! Server unique ID. Only meaningful in readback via Server::config() - std::array guid; + std::array guid{}; //! Default configuration using process environment static Config from_env(); - //! Empty config - Config() :tcp_port(5075), udp_port(5076), auto_beacon(true), guid{} {} + //! Configuration limited to the local loopback interface on a randomly choosen port. + //! Suitable for use in self-contained unit-tests. + static Config localhost(); - //! Apply rules to translate current requested configuration - //! into one which can actually be loaded. - //! @post auto_beacon==false - //! @post !interfaces.empty() + /** Apply rules to translate current requested configuration + * into one which can actually be loaded based on current host network configuration. + * + * Explicit use of expand() is optional as the Context ctor expands any Config given. + * expand() is provided as a aid to help understand how Context::effective() is arrived at. + * + * @post autoAddrList==false + */ void expand(); - //! Short-hand for @code Server(std::move(*this)) @endcode. + //! Create a new Server using the current configuration. inline Server build() const { - Server ret(*this); - return ret; + return Server(*this); } }; diff --git a/src/server.cpp b/src/server.cpp index 17018eb..19fef6e 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include "evhelper.h" #include "serverconn.h" @@ -139,6 +140,19 @@ const Config& Server::config() const return pvt->effective; } +client::Config Server::clientConfig() const +{ + if(!pvt) + throw std::logic_error("NULL Server"); + + client::Config ret; + ret.udp_port = pvt->effective.udp_port; + ret.addressList = pvt->effective.interfaces; + ret.autoAddrList = false; + + return ret; +} + Server& Server::addPV(const std::string& name, const SharedPV& pv) { if(!pvt)