/** * Copyright - See the COPYRIGHT that is included with this distribution. * pvxs is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ #include #include #include #include #include #include #include #include #include "serverconn.h" #include "clientimpl.h" #include "evhelper.h" DEFINE_LOGGER(serversetup, "pvxs.server.setup"); DEFINE_LOGGER(config, "pvxs.config"); namespace pvxs { namespace { void split_addr_into(const char* name, std::vector& out, const std::string& inp, uint16_t defaultPort, bool required=false) { size_t pos=0u; while(pos>24)&0xff)<<'.'<<((ip>>16)&0xff)<<'.'<<((ip>>8)&0xff)<<'.'<<((ip>>0)&0xff); if(addr.sin_port) strm<<':'<& in) { std::ostringstream strm; bool first=true; for(auto& addr : in) { if(first) first = false; else strm<<' '; strm<& defs; bool useenv; std::string name, val; bool operator()(std::initializer_list names) { for(auto candidate : names) { if(useenv) { if(auto eval = getenv(candidate)) { name = candidate; val = eval; return true; } } else { auto it = defs.find(candidate); if(it!=defs.end()) { name = candidate; val = it->second; return true; } } } return false; } }; template struct cleaner { Fn fn; ~cleaner() { fn(); } }; template cleaner make_cleaner(Fn&& fn) { return cleaner{std::move(fn)}; } // Fill out address list by appending broadcast addresses // of any and all local interface addresses already included void expandAddrList(const std::vector& ifaces, std::vector& addrs) { evsocket dummy(AF_INET, SOCK_DGRAM, 0); std::vector bcasts; for(auto& addr : ifaces) { ELLLIST blist = ELLLIST_INIT; auto bclean = make_cleaner([&blist] { ellFree(&blist); }); SockAddr saddr(AF_INET); try { saddr.setAddress(addr.c_str()); }catch(std::runtime_error& e){ log_warn_printf(config, "%s Ignoring...\n", e.what()); continue; } osiSockAddr match = {}; match.ia = saddr->in; osiSockDiscoverBroadcastAddresses(&blist, dummy.sock, &match); while(ELLNODE *cur = ellGet(&blist)) { osiSockAddrNode *node = CONTAINER(cur, osiSockAddrNode, node); SockAddr temp(&node->addr.sa, sizeof(node->addr.ia)); free(node); temp.setPort(0u); bcasts.push_back(temp.tostring()); } } addrs.reserve(addrs.size()+bcasts.size()); for(auto& bcast : bcasts) { addrs.push_back(std::move(bcast)); } } void removeDups(std::vector& addrs) { addrs.erase(std::unique(addrs.begin(), addrs.end()), addrs.end()); } } // namespace namespace server { static void _fromDefs(Config& self, const std::map& defs, bool useenv) { PickOne pickone{defs, useenv}; if(pickone({"EPICS_PVAS_SERVER_PORT", "EPICS_PVA_SERVER_PORT"})) { try { self.tcp_port = parseTo(pickone.val); }catch(std::exception& e) { log_err_printf(serversetup, "%s invalid integer : %s", pickone.name.c_str(), e.what()); } } if(pickone({"EPICS_PVAS_BROADCAST_PORT", "EPICS_PVA_BROADCAST_PORT"})) { try { self.udp_port = parseTo(pickone.val); }catch(std::exception& e) { log_err_printf(serversetup, "%s invalid integer : %s", pickone.name.c_str(), e.what()); } } if(pickone({"EPICS_PVAS_INTF_ADDR_LIST"})) { split_addr_into(pickone.name.c_str(), self.interfaces, pickone.val, self.tcp_port, true); } if(pickone({"EPICS_PVAS_BEACON_ADDR_LIST", "EPICS_PVA_ADDR_LIST"})) { split_addr_into(pickone.name.c_str(), self.beaconDestinations, pickone.val, self.udp_port); } if(pickone({"EPICS_PVAS_AUTO_BEACON_ADDR_LIST", "EPICS_PVA_AUTO_ADDR_LIST"})) { parse_bool(self.auto_beacon, pickone.name, pickone.val); } } Config& Config::applyEnv() { _fromDefs(*this, std::map(), true); return *this; } Config Config::isolated() { 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; } Config& Config::applyDefs(const std::map& defs) { _fromDefs(*this, defs, false); return *this; } void Config::updateDefs(defs_t& defs) const { defs["EPICS_PVA_BROADCAST_PORT"] = defs["EPICS_PVAS_BROADCAST_PORT"] = SB()<(pickone.val); }catch(std::exception& e) { log_err_printf(serversetup, "%s invalid integer : %s", pickone.name.c_str(), e.what()); } } if(self.udp_port==0u) { log_err_printf(serversetup, "ignoring EPICS_PVA_BROADCAST_PORT=%d", 0); self.udp_port = 5076; } if(pickone({"EPICS_PVA_ADDR_LIST"})) { split_addr_into(pickone.name.c_str(), self.addressList, pickone.val, self.udp_port); } if(pickone({"EPICS_PVA_AUTO_ADDR_LIST"})) { parse_bool(self.autoAddrList, pickone.name, pickone.val); } if(pickone({"EPICS_PVA_INTF_ADDR_LIST"})) { split_addr_into(pickone.name.c_str(), self.interfaces, pickone.val, 0); } } Config& Config::applyEnv() { _fromDefs(*this, std::map(), true); return *this; } Config& Config::applyDefs(const std::map& defs) { _fromDefs(*this, defs, false); return *this; } void Config::updateDefs(defs_t& defs) const { defs["EPICS_PVA_BROADCAST_PORT"] = SB()<