From 9f76c2f03bc62f44dc4c90b949fd1210476268f8 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 24 Jan 2024 15:56:17 -0600 Subject: [PATCH 01/82] add ability to connect to server channels when UDP search is not feasible (e.g., if the connection has to go through firewalls); this can be done in those cases where server address is simply known, using combination of EPICS_PVA_ADDR_LIST and EPICS_PVA_SERVER_PORT variables --- src/remoteClient/clientContextImpl.cpp | 39 ++++++++++++++++++-------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index eff79d4a..39a8c009 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -3087,7 +3087,7 @@ class InternalClientContextImpl : ChannelRequester::shared_pointer const & channelRequester, short priority) OVERRIDE FINAL { - return createChannel(channelName, channelRequester, priority, std::string()); + return createChannel(channelName, channelRequester, priority, m_addressList); } virtual Channel::shared_pointer createChannel( @@ -3097,7 +3097,7 @@ class InternalClientContextImpl : std::string const & addressesStr) OVERRIDE FINAL { InetAddrVector addresses; - getSocketAddressList(addresses, addressesStr, PVA_SERVER_PORT); + getSocketAddressList(addresses, addressesStr, m_serverPort); Channel::shared_pointer channel = createChannelInternal(channelName, channelRequester, priority, addresses); if (channel.get()) @@ -3567,6 +3567,7 @@ class InternalClientContextImpl : #define STATIC_SEARCH_BASE_DELAY_SEC 5 #define STATIC_SEARCH_MAX_MULTIPLIER 10 +#define STATIC_SEARCH_MIN_DELAY_SEC 1 /** * Initiate search (connect) procedure. @@ -3577,21 +3578,28 @@ class InternalClientContextImpl : m_allowCreation = true; - if (m_addresses.empty()) - { - m_context->getChannelSearchManager()->registerSearchInstance(internal_from_this(), penalize); - } - else - { - m_context->getTimer()->scheduleAfterDelay(internal_from_this(), - (m_addressIndex / m_addresses.size())*STATIC_SEARCH_BASE_DELAY_SEC); + if (!m_addresses.empty()) { + char strBuffer[24]; + int index = m_addressIndex % m_addresses.size(); + osiSockAddr* serverAddress = &m_addresses[index]; + ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); + double delay = (m_addressIndex / m_addresses.size())*STATIC_SEARCH_BASE_DELAY_SEC+STATIC_SEARCH_MIN_DELAY_SEC; + LOG(logLevelDebug, "Scheduling channel search for address %s with delay of %.3f seconds.", strBuffer, delay); + m_context->getTimer()->scheduleAfterDelay(internal_from_this(), delay); } + m_context->getChannelSearchManager()->registerSearchInstance(internal_from_this(), penalize); } virtual void callback() OVERRIDE FINAL { // TODO cancellaction?! // TODO not in this timer thread !!! // TODO boost when a server (from address list) is started!!! IP vs address !!! + Transport::shared_pointer transport(m_transport); + if (transport) { + LOG(logLevelDebug, "Transport for channel %s is already active, channel search cancelled.", transport->getRemoteName().c_str()); + return; + } + int ix = m_addressIndex % m_addresses.size(); m_addressIndex++; if (m_addressIndex >= static_cast(m_addresses.size()*(STATIC_SEARCH_MAX_MULTIPLIER+1))) @@ -3610,6 +3618,8 @@ class InternalClientContextImpl : virtual void searchResponse(const ServerGUID & guid, int8 minorRevision, osiSockAddr* serverAddress) OVERRIDE FINAL { // Hack. Prevent Transport from being dtor'd while m_channelMutex is held Transport::shared_pointer old_transport; + char strBuffer[24]; + ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); Lock guard(m_channelMutex); Transport::shared_pointer transport(m_transport); @@ -3957,7 +3967,7 @@ class InternalClientContextImpl : static size_t num_instances; InternalClientContextImpl(const Configuration::shared_pointer& conf) : - m_addressList(""), m_autoAddressList(true), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), + m_addressList(""), m_autoAddressList(true), m_serverPort(PVA_SERVER_PORT), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), m_broadcastPort(PVA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), m_lastCID(0x10203040), m_lastIOID(0x80706050), @@ -4019,6 +4029,7 @@ class InternalClientContextImpl : out << "VERSION : " << m_version.getVersionString() << std::endl; out << "ADDR_LIST : " << m_addressList << std::endl; out << "AUTO_ADDR_LIST : " << (m_autoAddressList ? "true" : "false") << std::endl; + out << "SERVER_PORT : " << m_serverPort << std::endl; out << "CONNECTION_TIMEOUT : " << m_connectionTimeout << std::endl; out << "BEACON_PERIOD : " << m_beaconPeriod << std::endl; out << "BROADCAST_PORT : " << m_broadcastPort << std::endl;; @@ -4111,6 +4122,7 @@ class InternalClientContextImpl : m_addressList = m_configuration->getPropertyAsString("EPICS_PVA_ADDR_LIST", m_addressList); m_autoAddressList = m_configuration->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", m_autoAddressList); + m_serverPort = m_configuration->getPropertyAsInteger("EPICS_PVA_SERVER_PORT", m_serverPort); m_connectionTimeout = m_configuration->getPropertyAsFloat("EPICS_PVA_CONN_TMO", m_connectionTimeout); m_beaconPeriod = m_configuration->getPropertyAsFloat("EPICS_PVA_BEACON_PERIOD", m_beaconPeriod); m_broadcastPort = m_configuration->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", m_broadcastPort); @@ -4430,6 +4442,11 @@ class InternalClientContextImpl : */ bool m_autoAddressList; + /** + * Define server port + */ + int m_serverPort; + /** * If the context doesn't see a beacon from a server that it is connected to for * connectionTimeout seconds then a state-of-health message is sent to the server over TCP/IP. From 63548a1c6b3ca3e468db83e6d5ee692ebd1defe6 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 24 Jan 2024 16:01:30 -0600 Subject: [PATCH 02/82] remove un-needed code --- src/remoteClient/clientContextImpl.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 39a8c009..01c166dc 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -3618,8 +3618,6 @@ class InternalClientContextImpl : virtual void searchResponse(const ServerGUID & guid, int8 minorRevision, osiSockAddr* serverAddress) OVERRIDE FINAL { // Hack. Prevent Transport from being dtor'd while m_channelMutex is held Transport::shared_pointer old_transport; - char strBuffer[24]; - ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); Lock guard(m_channelMutex); Transport::shared_pointer transport(m_transport); From 99bfee2b241a48ae3ed073dc8699d8937e3c8569 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 25 Jan 2024 10:12:35 -0600 Subject: [PATCH 03/82] allow control of the UDP sender port via the EPICS_PVA_UDP_SENDER_PORT environment variable on both server and client side --- src/pva/pv/pvaConstants.h | 3 +++ src/remote/blockingUDPTransport.cpp | 3 ++- src/remote/pv/blockingUDP.h | 1 + src/remoteClient/clientContextImpl.cpp | 9 ++++++++- src/server/pv/serverContext.h | 6 ++++++ src/server/pv/serverContextImpl.h | 11 +++++++++++ src/server/serverContext.cpp | 14 +++++++++++++- 7 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/pva/pv/pvaConstants.h b/src/pva/pv/pvaConstants.h index 5aafe1e1..c4548991 100644 --- a/src/pva/pv/pvaConstants.h +++ b/src/pva/pv/pvaConstants.h @@ -43,6 +43,9 @@ const epics::pvData::int32 PVA_SERVER_PORT = 5075; /** Default PVA beacon port. */ const epics::pvData::int32 PVA_BROADCAST_PORT = 5076; +/** Default UDP sender port. */ +const epics::pvData::int32 PVA_UDP_SENDER_PORT = 0; + /** PVA protocol message header size. */ const epics::pvData::int16 PVA_MESSAGE_HEADER_SIZE = 8; diff --git a/src/remote/blockingUDPTransport.cpp b/src/remote/blockingUDPTransport.cpp index 81d741d4..2f9d86f0 100644 --- a/src/remote/blockingUDPTransport.cpp +++ b/src/remote/blockingUDPTransport.cpp @@ -580,6 +580,7 @@ void initializeUDPTransports(bool serverFlag, const ResponseHandler::shared_pointer& responseHandler, BlockingUDPTransport::shared_pointer& sendTransport, int32& listenPort, + int32& senderPort, bool autoAddressList, const std::string& addressList, const std::string& ignoreAddressList) @@ -595,7 +596,7 @@ void initializeUDPTransports(bool serverFlag, osiSockAddr anyAddress; memset(&anyAddress, 0, sizeof(anyAddress)); anyAddress.ia.sin_family = AF_INET; - anyAddress.ia.sin_port = htons(0); + anyAddress.ia.sin_port = htons(senderPort); anyAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY); sendTransport = connector.connect(responseHandler, anyAddress, protoVer); diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index 97cedeb7..c0a26646 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -401,6 +401,7 @@ void initializeUDPTransports( const ResponseHandler::shared_pointer& responseHandler, BlockingUDPTransport::shared_pointer& sendTransport, epics::pvData::int32& listenPort, + epics::pvData::int32& senderPort, bool autoAddressList, const std::string& addressList, const std::string& ignoreAddressList); diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index eff79d4a..85d081e4 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -4022,6 +4022,7 @@ class InternalClientContextImpl : out << "CONNECTION_TIMEOUT : " << m_connectionTimeout << std::endl; out << "BEACON_PERIOD : " << m_beaconPeriod << std::endl; out << "BROADCAST_PORT : " << m_broadcastPort << std::endl;; + out << "UDP_SENDER_PORT : " << m_senderPort << std::endl;; out << "RCV_BUFFER_SIZE : " << m_receiveBufferSize << std::endl; out << "STATE : "; switch (m_contextState) @@ -4114,6 +4115,7 @@ class InternalClientContextImpl : m_connectionTimeout = m_configuration->getPropertyAsFloat("EPICS_PVA_CONN_TMO", m_connectionTimeout); m_beaconPeriod = m_configuration->getPropertyAsFloat("EPICS_PVA_BEACON_PERIOD", m_beaconPeriod); m_broadcastPort = m_configuration->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", m_broadcastPort); + m_senderPort = m_configuration->getPropertyAsInteger("EPICS_PVA_UDP_SENDER_PORT", m_senderPort); m_receiveBufferSize = m_configuration->getPropertyAsInteger("EPICS_PVA_MAX_ARRAY_BYTES", m_receiveBufferSize); } @@ -4150,7 +4152,7 @@ class InternalClientContextImpl : epicsSocketDestroy (socket); initializeUDPTransports(false, m_udpTransports, ifaceList, m_responseHandler, m_searchTransport, - m_broadcastPort, m_autoAddressList, m_addressList, std::string()); + m_broadcastPort, m_senderPort, m_autoAddressList, m_addressList, std::string()); } @@ -4448,6 +4450,11 @@ class InternalClientContextImpl : */ int32 m_broadcastPort; + /** + * UDP sender port + */ + int32 m_senderPort; + /** * Receive buffer size (max size of payload). */ diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index bbe361fb..1dd442bd 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -82,6 +82,12 @@ class epicsShareClass ServerContext */ virtual epics::pvData::int32 getBroadcastPort() = 0; + /** + * Get UDP sender port. + * @return UDP sender port. + */ + virtual epics::pvData::int32 getSenderPort() = 0; + /** Return a Configuration with the actual values being used, * including defaults used, and bounds limits applied. */ diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index c148c18b..b23f265f 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -88,6 +88,12 @@ class ServerContextImpl : */ epics::pvData::int32 getBroadcastPort() OVERRIDE FINAL; + /** + * Get UDP sender port. + * @return UDP sender port. + */ + epics::pvData::int32 getSenderPort() OVERRIDE FINAL; + /** * Get registered beacon server status provider. * @return registered beacon server status provider. @@ -162,6 +168,11 @@ class ServerContextImpl : */ epics::pvData::int32 _broadcastPort; + /** + * UDP sender port. + */ + epics::pvData::int32 _senderPort; + /** * Port number for the server to listen to. */ diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 82151e9f..6902b29a 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -37,6 +37,7 @@ ServerContextImpl::ServerContextImpl(): _autoBeaconAddressList(true), _beaconPeriod(15.0), _broadcastPort(PVA_BROADCAST_PORT), + _senderPort(PVA_UDP_SENDER_PORT), _serverPort(PVA_SERVER_PORT), _receiveBufferSize(MAX_TCP_RECV), _timer(new Timer("PVAS timers", lowerPriority)), @@ -142,6 +143,8 @@ void ServerContextImpl::loadConfiguration() _broadcastPort = config->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", _broadcastPort); _broadcastPort = config->getPropertyAsInteger("EPICS_PVAS_BROADCAST_PORT", _broadcastPort); + _senderPort = config->getPropertyAsInteger("EPICS_PVA_UDP_SENDER_PORT", _senderPort); + _senderPort = config->getPropertyAsInteger("EPICS_PVAS_UDP_SENDER_PORT", _senderPort); _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVA_MAX_ARRAY_BYTES", _receiveBufferSize); _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVAS_MAX_ARRAY_BYTES", _receiveBufferSize); @@ -246,6 +249,9 @@ ServerContextImpl::getCurrentConfig() SET("EPICS_PVAS_BROADCAST_PORT", getBroadcastPort()); SET("EPICS_PVA_BROADCAST_PORT", getBroadcastPort()); + SET("EPICS_PVAS_UDP_SENDER_PORT", getSenderPort()); + SET("EPICS_PVA_UDP_SENDER_PORT", getSenderPort()); + SET("EPICS_PVAS_MAX_ARRAY_BYTES", getReceiveBufferSize()); SET("EPICS_PVA_MAX_ARRAY_BYTES", getReceiveBufferSize()); @@ -278,7 +284,7 @@ void ServerContextImpl::initialize() // setup broadcast UDP transport initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, - _broadcastPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); + _broadcastPort, _senderPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); _beaconEmitter.reset(new BeaconEmitter("tcp", _broadcastTransport, thisServerContext)); @@ -380,6 +386,7 @@ void ServerContextImpl::printInfo(ostream& str, int lvl) SHOW(EPICS_PVAS_AUTO_BEACON_ADDR_LIST) SHOW(EPICS_PVAS_BEACON_PERIOD) SHOW(EPICS_PVAS_BROADCAST_PORT) + SHOW(EPICS_PVAS_UDP_SENDER_PORT) SHOW(EPICS_PVAS_SERVER_PORT) SHOW(EPICS_PVAS_PROVIDER_NAMES) #undef SHOW @@ -485,6 +492,11 @@ int32 ServerContextImpl::getBroadcastPort() return _broadcastPort; } +int32 ServerContextImpl::getSenderPort() +{ + return _senderPort; +} + BeaconServerStatusProvider::shared_pointer ServerContextImpl::getBeaconServerStatusProvider() { return _beaconServerStatusProvider; From a0c436f268f3282b17a8e70a1716d89d3026f5d3 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 15:52:14 -0500 Subject: [PATCH 04/82] add tests for udp search, name server search, and direct connection --- testApp/remote/channelDiscoveryTest.cpp | 106 +++++++++++++++++++++ testApp/remote/channelDiscoveryTest.h | 33 +++++++ testApp/remote/dcChannelDiscoveryTest.cpp | 62 ++++++++++++ testApp/remote/nsChannelDiscoveryTest.cpp | 62 ++++++++++++ testApp/remote/udpChannelDiscoveryTest.cpp | 61 ++++++++++++ 5 files changed, 324 insertions(+) create mode 100644 testApp/remote/channelDiscoveryTest.cpp create mode 100644 testApp/remote/channelDiscoveryTest.h create mode 100644 testApp/remote/dcChannelDiscoveryTest.cpp create mode 100644 testApp/remote/nsChannelDiscoveryTest.cpp create mode 100644 testApp/remote/udpChannelDiscoveryTest.cpp diff --git a/testApp/remote/channelDiscoveryTest.cpp b/testApp/remote/channelDiscoveryTest.cpp new file mode 100644 index 00000000..4c0ddb3c --- /dev/null +++ b/testApp/remote/channelDiscoveryTest.cpp @@ -0,0 +1,106 @@ +// disable buggy boost enable_shared_from_this assert code +#define BOOST_DISABLE_ASSERTS + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "channelDiscoveryTest.h" + +namespace TR1 = std::tr1; +namespace EPVA = epics::pvAccess; + +// int value, increment on process +const std::string ChannelDiscoveryTest::TEST_SIMPLECOUNTER_CHANNEL_NAME = "testSimpleCounter"; + +int ChannelDiscoveryTest::runAllTests() { + + testPlan(1); + m_provider = ChannelProviderRegistry::clients()->getProvider("pva"); + test_channelDiscovery(); + return testDone(); +} + +Channel::shared_pointer ChannelDiscoveryTest::createChannel(string channelName, bool debug ) +{ + + TR1::shared_ptr channelReq(new SyncChannelRequesterImpl(debug)); + Channel::shared_pointer channel = getChannelProvider()->createChannel(channelName, channelReq); + return channel; +} + +Channel::shared_pointer ChannelDiscoveryTest::syncCreateChannel(string channelName, bool debug ) +{ + + TR1::shared_ptr channelReq(new SyncChannelRequesterImpl(debug)); + Channel::shared_pointer channel = getChannelProvider()->createChannel(channelName, channelReq); + bool isConnected = channelReq->waitUntilConnected(getTimeoutSec()); + if (!isConnected) { + std::cerr << "[" << channelName << "] failed to connect to the channel. " << std::endl; + return TR1::shared_ptr(); + } + + return channel; +} + + +SyncChannelGetRequesterImpl::shared_pointer ChannelDiscoveryTest::syncCreateChannelGet( + Channel::shared_pointer const & channel, string const & request, bool debug ) +{ + + TR1::shared_ptr + channelGetReq(new SyncChannelGetRequesterImpl(channel->getChannelName(), debug)); + + PVStructure::shared_pointer pvRequest = createRequest(request); + + ChannelGet::shared_pointer op(channel->createChannelGet(channelGetReq,pvRequest)); + bool succStatus = channelGetReq->waitUntilGetDone(getTimeoutSec()); + if (!succStatus) { + std::cerr << "[" << channel->getChannelName() << "] failed to get. " << std::endl; + return TR1::shared_ptr(); + } + return channelGetReq; +} + +void ChannelDiscoveryTest::test_channelGetInt(Channel::shared_pointer channel, + string const & testMethodName) { + + string request = "record[process=true]field(value)"; + + SyncChannelGetRequesterImpl::shared_pointer channelGetReq = syncCreateChannelGet(channel, request); + if (!channelGetReq.get()) { + testFail("%s: channel get not created ", testMethodName.c_str()); + return; + } + + TR1::shared_ptr value = channelGetReq->getPVStructure()->getSubField("value"); + int previousValue = value->get(); + epicsThreadSleep(1.0); + bool succStatus = channelGetReq->syncGet(false, getTimeoutSec()); + if (!succStatus) { + testFail("%s: sync get failed ", testMethodName.c_str()); + return; + } + testOk((previousValue +1) == value->get(), "%s: testing the counter value change %d == %d", testMethodName.c_str(), previousValue +1, (int)value->get()); + channelGetReq->getChannelGet()->destroy(); + channel->destroy(); +} + +void ChannelDiscoveryTest::test_channelDiscovery() { + testDiag("BEGIN TEST %s:", CURRENT_FUNCTION); + Channel::shared_pointer channel = syncCreateChannel(TEST_SIMPLECOUNTER_CHANNEL_NAME); + if (!channel.get()) { + testFail("%s: channel not created ", CURRENT_FUNCTION); + return; + } + test_channelGetInt(channel, CURRENT_FUNCTION); +} diff --git a/testApp/remote/channelDiscoveryTest.h b/testApp/remote/channelDiscoveryTest.h new file mode 100644 index 00000000..f3660e08 --- /dev/null +++ b/testApp/remote/channelDiscoveryTest.h @@ -0,0 +1,33 @@ +#ifndef CHANNEL_DISCOVERY_H +#define CHANNEL_DISCOVERY_H + +#include +#include "syncTestRequesters.h" + +class ChannelDiscoveryTest { + +public: + + int runAllTests(); + virtual ~ChannelDiscoveryTest() {} + +protected: + + static const std::string TEST_SIMPLECOUNTER_CHANNEL_NAME; + + ChannelProvider::shared_pointer getChannelProvider() { return m_provider; } + long getTimeoutSec() {return 5;} + bool isLocal() {return false;} + + Channel::shared_pointer createChannel(std::string channelName, bool debug=false); + Channel::shared_pointer syncCreateChannel(std::string channelName, bool debug=false); + SyncChannelGetRequesterImpl::shared_pointer syncCreateChannelGet(Channel::shared_pointer const & channel, std::string const & request, bool debug=false); + +private: + ChannelProvider::shared_pointer m_provider; + + void test_channelGetInt(Channel::shared_pointer channel, std::string const & testMethodName); + void test_channelDiscovery(); +}; + +#endif diff --git a/testApp/remote/dcChannelDiscoveryTest.cpp b/testApp/remote/dcChannelDiscoveryTest.cpp new file mode 100644 index 00000000..9ed67b87 --- /dev/null +++ b/testApp/remote/dcChannelDiscoveryTest.cpp @@ -0,0 +1,62 @@ +// Test direct channel connection + +#include +#include + +#include +#include +#include + +#include +#include + +#include "channelDiscoveryTest.cpp" + +#define TESTSERVERNOMAIN +#include "testServer.cpp" + +namespace EPVA = epics::pvAccess; + + +int runAllTests() { + + EPVA::Configuration::shared_pointer baseConfig(ConfigurationBuilder() + .add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1") + .add("EPICS_PVA_SERVER_PORT", "0") + .add("EPICS_PVAS_BROADCAST_PORT", "0") + .push_map() + .build()); + + EPVA::Configuration::shared_pointer serverConfig(ConfigurationBuilder() + .push_config(baseConfig) + .push_map() + .build()); + + TestServer::shared_pointer testServer(new TestServer(serverConfig)); + std::ostringstream portStr; + portStr << "127.0.0.1:" << testServer->getServerPort(); + EPVA::Configuration::shared_pointer clientConfig(ConfigurationBuilder() + .push_config(baseConfig) + .add("EPICS_PVA_ADDR_LIST", portStr.str()) + .push_map() + .build()); + + ConfigurationFactory::registerConfiguration("pvAccess-client", clientConfig); + epics::pvAccess::ClientFactory::start(); + + ChannelDiscoveryTest cdTest; + return cdTest.runAllTests(); +} + +MAIN(testDcChannelDiscovery) +{ + try{ + SET_LOG_LEVEL(logLevelDebug); + return runAllTests(); + } + catch(std::exception& e) { + PRINT_EXCEPTION(e); + std::cerr << "Unhandled exception: " << e.what() << "\n"; + return 1; + } +} diff --git a/testApp/remote/nsChannelDiscoveryTest.cpp b/testApp/remote/nsChannelDiscoveryTest.cpp new file mode 100644 index 00000000..bc2b3d69 --- /dev/null +++ b/testApp/remote/nsChannelDiscoveryTest.cpp @@ -0,0 +1,62 @@ +// Test channel discovery using name server search + +#include +#include + +#include +#include +#include + +#include +#include + +#include "channelDiscoveryTest.cpp" + +#define TESTSERVERNOMAIN +#include "testServer.cpp" + +namespace EPVA = epics::pvAccess; + + +int runAllTests() { + + EPVA::Configuration::shared_pointer baseConfig(ConfigurationBuilder() + .add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1") + .add("EPICS_PVA_SERVER_PORT", "0") + .add("EPICS_PVAS_BROADCAST_PORT", "0") + .push_map() + .build()); + + EPVA::Configuration::shared_pointer serverConfig(ConfigurationBuilder() + .push_config(baseConfig) + .push_map() + .build()); + + TestServer::shared_pointer testServer(new TestServer(serverConfig)); + std::ostringstream portStr; + portStr << "127.0.0.1:" << testServer->getSearchServerPort(); + EPVA::Configuration::shared_pointer clientConfig(ConfigurationBuilder() + .push_config(baseConfig) + .add("EPICS_PVA_NAME_SERVERS", portStr.str()) + .push_map() + .build()); + + ConfigurationFactory::registerConfiguration("pvAccess-client", clientConfig); + epics::pvAccess::ClientFactory::start(); + + ChannelDiscoveryTest cdTest; + return cdTest.runAllTests(); +} + +MAIN(testNsChannelDiscovery) +{ + try{ + SET_LOG_LEVEL(logLevelError); + return runAllTests(); + } + catch(std::exception& e) { + PRINT_EXCEPTION(e); + std::cerr << "Unhandled exception: " << e.what() << "\n"; + return 1; + } +} diff --git a/testApp/remote/udpChannelDiscoveryTest.cpp b/testApp/remote/udpChannelDiscoveryTest.cpp new file mode 100644 index 00000000..be26d76a --- /dev/null +++ b/testApp/remote/udpChannelDiscoveryTest.cpp @@ -0,0 +1,61 @@ +// Test channel discovery over UDP + +#include + +#include +#include +#include + +#include +#include + +#include "channelDiscoveryTest.cpp" + +#define TESTSERVERNOMAIN +#include "testServer.cpp" + +namespace EPVA = epics::pvAccess; + + +int runAllTests() { + + EPVA::Configuration::shared_pointer baseConfig(ConfigurationBuilder() + .add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1") + .add("EPICS_PVA_ADDR_LIST", "127.0.0.1") + .add("EPICS_PVA_AUTO_ADDR_LIST","0") + .add("EPICS_PVA_SERVER_PORT", "0") + .add("EPICS_PVA_BROADCAST_PORT", "0") + .push_map() + .build()); + + EPVA::Configuration::shared_pointer serverConfig(ConfigurationBuilder() + .push_config(baseConfig) + .push_map() + .build()); + + TestServer::shared_pointer testServer(new TestServer(serverConfig)); + EPVA::Configuration::shared_pointer clientConfig(ConfigurationBuilder() + .push_config(baseConfig) + .add("EPICS_PVA_BROADCAST_PORT", testServer->getBroadcastPort()) + .push_map() + .build()); + + ConfigurationFactory::registerConfiguration("pvAccess-client", clientConfig); + epics::pvAccess::ClientFactory::start(); + + ChannelDiscoveryTest cdTest; + return cdTest.runAllTests(); +} + +MAIN(testUdpChannelDiscovery) +{ + try{ + SET_LOG_LEVEL(logLevelError); + return runAllTests(); + } + catch(std::exception& e) { + PRINT_EXCEPTION(e); + std::cerr << "Unhandled exception: " << e.what() << "\n"; + return 1; + } +} From 6e7420ae04d5521baaff6480471a691c40f2b33e Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 15:55:10 -0500 Subject: [PATCH 05/82] set connected status on state change --- testApp/remote/syncTestRequesters.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/testApp/remote/syncTestRequesters.h b/testApp/remote/syncTestRequesters.h index 0781cea1..d61f8aff 100644 --- a/testApp/remote/syncTestRequesters.h +++ b/testApp/remote/syncTestRequesters.h @@ -223,6 +223,14 @@ class SyncChannelRequesterImpl : public epics::pvAccess::ChannelRequester, publi { Lock lock(m_pointerMutex); m_stateChangeCount++; + if (connectionState == Channel::CONNECTED) + { + setConnectedStatus(true); + } + else + { + setConnectedStatus(false); + } } signalEvent(); From 4de9a83a0d19e2a95ba9b000077a1cd042f6a62f Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 15:55:56 -0500 Subject: [PATCH 06/82] add method for retrieving search server port --- testApp/remote/testServer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index 2e0c157a..ec7901a6 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -2731,6 +2731,11 @@ struct TestServer { return context->getServerPort(); } + // Use with EPICS_PVA_BROADCAST_PORT==0 for dynamic port (unit-tests) + unsigned short getSearchServerPort() + { + return context->getSearchServerPort(); + } unsigned short getBroadcastPort() { return context->getBroadcastPort(); From 6976fdc895c1b9d1abd510c40106983ca08c938e Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 15:56:25 -0500 Subject: [PATCH 07/82] add new tests to Makefile --- testApp/remote/Makefile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/testApp/remote/Makefile b/testApp/remote/Makefile index c4f47289..7c349153 100644 --- a/testApp/remote/Makefile +++ b/testApp/remote/Makefile @@ -9,6 +9,21 @@ ifneq (RTEMS,$(OS_CLASS)) TESTS += testChannelAccess endif +TESTPROD_HOST += testUdpChannelDiscovery +TESTPROD_HOST += testNsChannelDiscovery +TESTPROD_HOST += testDcChannelDiscovery +testUdpChannelDiscovery_SRCS = udpChannelDiscoveryTest.cpp +testNsChannelDiscovery_SRCS = nsChannelDiscoveryTest.cpp +testDcChannelDiscovery_SRCS = dcChannelDiscoveryTest.cpp +testHarness_SRCS += udpChannelDiscoveryTest.cpp +testHarness_SRCS += nsChannelDiscoveryTest.cpp +testHarness_SRCS += dcChannelDiscoveryTest.cpp +ifneq (RTEMS,$(OS_CLASS)) +TESTS += testUdpChannelDiscovery +TESTS += testNsChannelDiscovery +TESTS += testDcChannelDiscovery +endif + TESTPROD_HOST += testCodec testCodec_SRCS = testCodec testHarness_SRCS += testCodec.cpp From 6fe5a7967f314313fd82eec740834b9f058f1b56 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 15:59:26 -0500 Subject: [PATCH 08/82] fix typo --- src/remote/blockingUDPTransport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/remote/blockingUDPTransport.cpp b/src/remote/blockingUDPTransport.cpp index 81d741d4..34a58070 100644 --- a/src/remote/blockingUDPTransport.cpp +++ b/src/remote/blockingUDPTransport.cpp @@ -714,7 +714,7 @@ void initializeUDPTransports(bool serverFlag, getSocketAddressList(ignoreAddressVector, ignoreAddressList, 0, 0); // - // Setup UDP trasport(s) (per interface) + // Setup UDP transport(s) (per interface) // InetAddrVector tappedNIF; From 8af89e7af7e383bdbbbf092644cef2df75c10348 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 16:01:04 -0500 Subject: [PATCH 09/82] add name server search --- src/remote/channelSearchManager.cpp | 76 +++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/src/remote/channelSearchManager.cpp b/src/remote/channelSearchManager.cpp index 6dd9b33e..04767716 100644 --- a/src/remote/channelSearchManager.cpp +++ b/src/remote/channelSearchManager.cpp @@ -82,7 +82,8 @@ ChannelSearchManager::ChannelSearchManager(Context::shared_pointer const & conte m_lastTimeSent(), m_channelMutex(), m_userValueMutex(), - m_mutex() + m_mutex(), + m_nsTransport() { // initialize random seed with some random value srand ( time(NULL) ); @@ -135,6 +136,7 @@ void ChannelSearchManager::registerSearchInstance(SearchInstance::shared_pointer if (m_canceled.get()) return; + LOG(logLevelDebug, "Registering search instance: %s", channel->getSearchInstanceName().c_str()); bool immediateTrigger; { Lock guard(m_channelMutex); @@ -154,6 +156,7 @@ void ChannelSearchManager::registerSearchInstance(SearchInstance::shared_pointer void ChannelSearchManager::unregisterSearchInstance(SearchInstance::shared_pointer const & channel) { + LOG(logLevelDebug, "Unregistering search instance: %s", channel->getSearchInstanceName().c_str()); Lock guard(m_channelMutex); pvAccessID id = channel->getSearchInstanceID(); m_channels.erase(id); @@ -188,6 +191,22 @@ void ChannelSearchManager::searchResponse(const ServerGUID & guid, pvAccessID ci if(si) si->searchResponse(guid, minorRevision, serverAddress); } + + // Cleanup name server search + if(m_nsTransport && m_channels.size() == 0) + { + closeNameServerTransport(); + } +} + +void ChannelSearchManager::closeNameServerTransport() +{ + if(m_nsTransport) + { + LOG(logLevelDebug, "Closing name server transport"); + m_nsTransport->close(); + m_nsTransport.reset(); + } } void ChannelSearchManager::newServerDetected() @@ -196,6 +215,46 @@ void ChannelSearchManager::newServerDetected() callback(); } +void ChannelSearchManager::send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) +{ + control->startMessage(CMD_SEARCH, 4+1+3+16+2+1+4); + buffer->putInt(m_sequenceNumber); + buffer->putByte((int8_t)QOS_REPLY_REQUIRED); // CAST_POSITION + buffer->putByte((int8_t)0); // reserved + buffer->putShort((int16_t)0); // reserved + + osiSockAddr anyAddress; + memset(&anyAddress, 0, sizeof(anyAddress)); + anyAddress.ia.sin_family = AF_INET; + anyAddress.ia.sin_port = htons(0); + anyAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY); + encodeAsIPv6Address(buffer, &anyAddress); + buffer->putShort((int16_t)ntohs(anyAddress.ia.sin_port)); + buffer->putByte((int8_t)1); + SerializeHelper::serializeString(PVA_TCP_PROTOCOL, buffer, control); + buffer->putShort((int16_t)0); // initial channel count + + vector toSend; + { + Lock guard(m_channelMutex); + toSend.reserve(m_channels.size()); + + for(m_channels_t::iterator channelsIter = m_channels.begin(); + channelsIter != m_channels.end(); channelsIter++) + { + SearchInstance::shared_pointer inst(channelsIter->second.lock()); + if(!inst) continue; + toSend.push_back(inst); + } + } + + vector::iterator siter = toSend.begin(); + for (; siter != toSend.end(); siter++) + { + generateSearchRequestMessage(*siter, buffer, control); + } +} + void ChannelSearchManager::initializeSendBuffer() { // for now OK, since it is only set here @@ -228,7 +287,7 @@ void ChannelSearchManager::initializeSendBuffer() m_sendBuffer.putByte((int8_t)1); MockTransportSendControl control; - SerializeHelper::serializeString("tcp", &m_sendBuffer, &control); + SerializeHelper::serializeString(PVA_TCP_PROTOCOL, &m_sendBuffer, &control); m_sendBuffer.putShort((int16_t)0); // count } @@ -245,6 +304,16 @@ void ChannelSearchManager::flushSendBuffer() m_sendBuffer.putByte(CAST_POSITION, (int8_t)0x00); // b/m-cast, no reply required ut->send(&m_sendBuffer, inetAddressType_broadcast_multicast); + // Name server search + if(!m_nsTransport) + { + m_nsTransport = m_context.lock()->getNameServerSearchTransport(); + } + if(m_nsTransport) + { + LOG(logLevelDebug, "Initiating name server search"); + m_nsTransport->enqueueSendRequest(shared_from_this()); + } initializeSendBuffer(); } @@ -253,7 +322,6 @@ bool ChannelSearchManager::generateSearchRequestMessage(SearchInstance::shared_p ByteBuffer* requestMessage, TransportSendControl* control) { epics::pvData::int16 dataCount = requestMessage->getShort(DATA_COUNT_POSITION); - dataCount++; /* @@ -262,6 +330,8 @@ bool ChannelSearchManager::generateSearchRequestMessage(SearchInstance::shared_p */ const std::string& name(channel->getSearchInstanceName()); + LOG(logLevelDebug, "Searching for channel: %s", name.c_str()); + // not nice... const int addedPayloadSize = sizeof(int32)/sizeof(int8) + (1 + sizeof(int32)/sizeof(int8) + name.length()); if(((int)requestMessage->getRemaining()) < addedPayloadSize) From 7caa5d33067343eab97bb98e1d73f3902034503a Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 16:01:37 -0500 Subject: [PATCH 10/82] add protocol constants --- src/remote/codec.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 7d4b9a16..75febd27 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -58,6 +58,9 @@ struct BreakTransport : TransportSender namespace epics { namespace pvAccess { +const std::string PVA_TCP_PROTOCOL("tcp"); +const std::string PVA_UDP_PROTOCOL("udp"); + /* HACK! * RTEMS allows blocking sockets to be interrupted by shutdown() (aka. esscimqi_socketBothShutdownRequired). * However, a concurrent close() is a race which can leave a send()/recv() call permanently stuck! From 424090fcb4ca3a5912188637323b1f937e58361a Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 16:02:20 -0500 Subject: [PATCH 11/82] use constant for type --- src/remote/pv/blockingUDP.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index 97cedeb7..71af2870 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -76,7 +76,7 @@ class BlockingUDPTransport : } virtual std::string getType() const OVERRIDE FINAL { - return std::string("udp"); + return PVA_UDP_PROTOCOL; } virtual std::size_t getReceiveBufferSize() const OVERRIDE FINAL { From 57c03c895bfee3573572886985050cafa9af46e5 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 16:02:56 -0500 Subject: [PATCH 12/82] support for name server search --- src/remote/pv/channelSearchManager.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/remote/pv/channelSearchManager.h b/src/remote/pv/channelSearchManager.h index 5d8b5bb8..ad59b21e 100644 --- a/src/remote/pv/channelSearchManager.h +++ b/src/remote/pv/channelSearchManager.h @@ -53,6 +53,7 @@ class SearchInstance { class ChannelSearchManager : public epics::pvData::TimerCallback, + public TransportSender, public std::tr1::enable_shared_from_this { public: @@ -99,6 +100,9 @@ class ChannelSearchManager : /// Timer stooped callback. virtual void timerStopped() OVERRIDE FINAL; + // Transport sender interface. + virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) OVERRIDE FINAL; + /** * Private constructor. * @param context @@ -106,6 +110,9 @@ class ChannelSearchManager : ChannelSearchManager(Context::shared_pointer const & context); void activate(); + // Closes name server transport. + void closeNameServerTransport(); + private: bool generateSearchRequestMessage(SearchInstance::shared_pointer const & channel, bool allowNewFrame, bool flush); @@ -170,6 +177,11 @@ class ChannelSearchManager : * m_channels mutex. */ epics::pvData::Mutex m_mutex; + + /** + * Name server trasnport. + */ + Transport::shared_pointer m_nsTransport; }; } From 291d97f1f028d30d190f5ba17deec88de977cfde Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 16:03:42 -0500 Subject: [PATCH 13/82] use constant for tcp transport --- src/remote/pv/codec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index 32e86410..4bdff568 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -303,7 +303,7 @@ class BlockingTCPTransportCodec: virtual void invalidDataStreamHandler() OVERRIDE FINAL; virtual std::string getType() const OVERRIDE FINAL { - return std::string("tcp"); + return PVA_TCP_PROTOCOL; } virtual void processControlMessage() OVERRIDE FINAL { From 03feff93e201ccfe0fd3b4ad30ebf18c895f225c Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 16:04:48 -0500 Subject: [PATCH 14/82] add interface for getting name server transport --- src/remote/pv/remote.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index b70b0e38..6f5e51f4 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -40,6 +40,12 @@ namespace epics { namespace pvAccess { +/** + * String constants. + */ +epicsShareExtern const std::string PVA_TCP_PROTOCOL; +epicsShareExtern const std::string PVA_UDP_PROTOCOL; + class TransportRegistry; class ClientChannelImpl; @@ -305,6 +311,7 @@ class Context { virtual std::tr1::shared_ptr getChannel(pvAccessID id) = 0; virtual Transport::shared_pointer getSearchTransport() = 0; + virtual Transport::shared_pointer getNameServerSearchTransport() = 0; }; /** From f1bdbb2eefe7e017061432dc2b6f3e55a2518e15 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 11 Mar 2024 17:01:03 -0500 Subject: [PATCH 15/82] add support for tcp search --- src/server/pv/responseHandlers.h | 33 +++++++++- src/server/responseHandlers.cpp | 109 +++++++++++++++++++++++++++---- 2 files changed, 128 insertions(+), 14 deletions(-) diff --git a/src/server/pv/responseHandlers.h b/src/server/pv/responseHandlers.h index fb17a6d0..86c0d51b 100644 --- a/src/server/pv/responseHandlers.h +++ b/src/server/pv/responseHandlers.h @@ -148,7 +148,7 @@ class ServerChannelFindRequesterImpl: virtual ~ServerChannelFindRequesterImpl() {} void clear(); ServerChannelFindRequesterImpl* set(std::string _name, epics::pvData::int32 searchSequenceId, - epics::pvData::int32 cid, osiSockAddr const & sendTo, bool responseRequired, bool serverSearch); + epics::pvData::int32 cid, osiSockAddr const & sendTo, Transport::shared_pointer const & transport, bool responseRequired, bool serverSearch); virtual void channelFindResult(const epics::pvData::Status& status, ChannelFind::shared_pointer const & channelFind, bool wasFound) OVERRIDE FINAL; virtual std::tr1::shared_ptr getPeerInfo() OVERRIDE FINAL; @@ -163,6 +163,7 @@ class ServerChannelFindRequesterImpl: epics::pvData::int32 _searchSequenceId; epics::pvData::int32 _cid; osiSockAddr _sendTo; + Transport::shared_pointer _transport; bool _responseRequired; bool _wasFound; const ServerContextImpl::shared_pointer _context; @@ -838,6 +839,36 @@ class ServerResponseHandler : public ResponseHandler { }; +/** + * PVAS search request handler + */ +class ServerSearchResponseHandler : public ResponseHandler { +public: + ServerSearchResponseHandler(ServerContextImpl::shared_pointer const & context); + + virtual ~ServerSearchResponseHandler() {} + + virtual void handleResponse(osiSockAddr* responseFrom, + Transport::shared_pointer const & transport, epics::pvData::int8 version, epics::pvData::int8 command, + std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE FINAL; +private: + ServerBadResponse handle_bad; + + ServerNoopResponse handle_beacon; + ServerConnectionValidationHandler handle_validation; + ServerEchoHandler handle_echo; + ServerSearchHandler handle_search; + AuthNZHandler handle_authnz; + ServerCreateChannelHandler handle_create; + ServerDestroyChannelHandler handle_destroy; + ServerRPCHandler handle_rpc; + /** + * Table of response handlers for each command ID. + */ + std::vector m_handlerTable; + +}; + } } diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index daa22b99..f00fc6b5 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -123,7 +123,6 @@ ServerResponseHandler::ServerResponseHandler(ServerContextImpl::shared_pointer c ,handle_cancel(context) ,m_handlerTable(CMD_CANCEL_REQUEST+1, &handle_bad) { - m_handlerTable[CMD_BEACON] = &handle_beacon; /* 0 */ m_handlerTable[CMD_CONNECTION_VALIDATION] = &handle_validation; /* 1 */ m_handlerTable[CMD_ECHO] = &handle_echo; /* 2 */ @@ -173,6 +172,68 @@ void ServerResponseHandler::handleResponse(osiSockAddr* responseFrom, version, command, payloadSize, payloadBuffer); } +ServerSearchResponseHandler::ServerSearchResponseHandler(ServerContextImpl::shared_pointer const & context) + :ResponseHandler(context.get(), "ServerSearchResponseHandler") + ,handle_bad(context) + ,handle_beacon(context, "Beacon") + ,handle_validation(context) + ,handle_echo(context) + ,handle_search(context) + ,handle_authnz(context.get()) + ,handle_create(context) + ,handle_destroy(context) + ,handle_rpc(context) + ,m_handlerTable(CMD_CANCEL_REQUEST+1, &handle_bad) +{ + m_handlerTable[CMD_BEACON] = &handle_bad; /* 0 */ + m_handlerTable[CMD_CONNECTION_VALIDATION] = &handle_validation; /* 1 */ + m_handlerTable[CMD_ECHO] = &handle_echo; /* 2 */ + m_handlerTable[CMD_SEARCH] = &handle_search; /* 3 */ + m_handlerTable[CMD_SEARCH_RESPONSE] = &handle_bad; + m_handlerTable[CMD_AUTHNZ] = &handle_authnz; /* 5 */ + m_handlerTable[CMD_ACL_CHANGE] = &handle_bad; /* 6 - access right change */ + m_handlerTable[CMD_CREATE_CHANNEL] = &handle_create; /* 7 */ + m_handlerTable[CMD_DESTROY_CHANNEL] = &handle_destroy; /* 8 */ + m_handlerTable[CMD_CONNECTION_VALIDATED] = &handle_bad; /* 9 */ + + m_handlerTable[CMD_GET] = &handle_bad; /* 10 - get response */ + m_handlerTable[CMD_PUT] = &handle_bad; /* 11 - put response */ + m_handlerTable[CMD_PUT_GET] = &handle_bad; /* 12 - put-get response */ + m_handlerTable[CMD_MONITOR] = &handle_bad; /* 13 - monitor response */ + m_handlerTable[CMD_ARRAY] = &handle_bad; /* 14 - array response */ + m_handlerTable[CMD_DESTROY_REQUEST] = &handle_bad; /* 15 - destroy request */ + m_handlerTable[CMD_PROCESS] = &handle_bad; /* 16 - process response */ + m_handlerTable[CMD_GET_FIELD] = &handle_bad; /* 17 - get field response */ + m_handlerTable[CMD_MESSAGE] = &handle_bad; /* 18 - message to Requester */ + m_handlerTable[CMD_MULTIPLE_DATA] = &handle_bad; /* 19 - grouped monitors */ + + m_handlerTable[CMD_RPC] = &handle_rpc; /* 20 - RPC response */ + m_handlerTable[CMD_CANCEL_REQUEST] = &handle_bad; /* 21 - cancel request */ +} + +void ServerSearchResponseHandler::handleResponse(osiSockAddr* responseFrom, + Transport::shared_pointer const & transport, int8 version, int8 command, + size_t payloadSize, ByteBuffer* payloadBuffer) +{ + if(command<0||command>=(int8)m_handlerTable.size()) + { + LOG(logLevelError, + "Invalid (or unsupported) command: %x.", (0xFF&command)); + + if(IS_LOGGABLE(logLevelError)) { + std::ios::fmtflags initialflags = std::cerr.flags(); + std::cerr<<"Invalid (or unsupported) command: "<handleResponse(responseFrom, transport, + version, command, payloadSize, payloadBuffer); +} + void ServerConnectionValidationHandler::handleResponse( osiSockAddr* responseFrom, Transport::shared_pointer const & transport, int8 version, int8 command, size_t payloadSize, @@ -237,7 +298,7 @@ void ServerEchoHandler::handleResponse(osiSockAddr* responseFrom, /****************************************************************************************/ -const std::string ServerSearchHandler::SUPPORTED_PROTOCOL = "tcp"; +const std::string ServerSearchHandler::SUPPORTED_PROTOCOL = PVA_TCP_PROTOCOL; ServerSearchHandler::ServerSearchHandler(ServerContextImpl::shared_pointer const & context) : AbstractServerResponseHandler(context, "Search request") @@ -250,6 +311,9 @@ void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer const & transport, int8 version, int8 command, size_t payloadSize, ByteBuffer* payloadBuffer) { + char strBuffer[24]; + ipAddrToDottedIP(&responseFrom->ia, strBuffer, sizeof(strBuffer)); + LOG(logLevelDebug, "Server search handler is handling request from %s", strBuffer); AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); @@ -277,7 +341,15 @@ void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, // NOTE: htons might be a macro (e.g. vxWorks) int16 port = payloadBuffer->getShort(); - responseAddress.ia.sin_port = htons(port); + if (port) + { + responseAddress.ia.sin_port = htons(port); + } + else + { + LOG(logLevelDebug, "Server search handler is reusing connection port %d", ntohs(responseFrom->ia.sin_port)); + responseAddress.ia.sin_port = responseFrom->ia.sin_port; + } size_t protocolsCount = SerializeHelper::readSize(payloadBuffer, transport.get()); bool allowed = (protocolsCount == 0); @@ -289,7 +361,6 @@ void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, } // NOTE: we do not stop reading the buffer - transport->ensureData(2); const int32 count = payloadBuffer->getShort() & 0xFFFF; @@ -298,9 +369,9 @@ void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, const bool responseRequired = (QOS_REPLY_REQUIRED & qosCode) != 0; // - // locally broadcast if unicast (qosCode & 0x80 == 0x80) via UDP + // locally broadcast if unicast (qosCode & QOS_GET_PUT == QOS_GET_PUT) via UDP // - if ((qosCode & 0x80) == 0x80) + if ((qosCode & QOS_GET_PUT) == QOS_GET_PUT) { BlockingUDPTransport::shared_pointer bt = dynamic_pointer_cast(transport); if (bt && bt->hasLocalMulticastAddress()) @@ -350,14 +421,14 @@ void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, const int32 cid = payloadBuffer->getInt(); const string name = SerializeHelper::deserializeString(payloadBuffer, transport.get()); // no name check here... - + LOG(logLevelDebug, "Search for channel %s, cid %d", name.c_str(), cid); if (allowed) { const std::vector& _providers = _context->getChannelProviders(); int providerCount = _providers.size(); std::tr1::shared_ptr tp(new ServerChannelFindRequesterImpl(_context, info, providerCount)); - tp->set(name, searchSequenceId, cid, responseAddress, responseRequired, false); + tp->set(name, searchSequenceId, cid, responseAddress, transport, responseRequired, false); for (int i = 0; i < providerCount; i++) _providers[i]->channelFind(name, tp); @@ -375,7 +446,7 @@ void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, delay = delay*0.1 + 0.05; std::tr1::shared_ptr tp(new ServerChannelFindRequesterImpl(_context, info, 1)); - tp->set("", searchSequenceId, 0, responseAddress, true, true); + tp->set("", searchSequenceId, 0, responseAddress, transport, true, true); TimerCallback::shared_pointer tc = tp; _context->getTimer()->scheduleAfterDelay(tc, delay); @@ -414,6 +485,7 @@ void ServerChannelFindRequesterImpl::timerStopped() } ServerChannelFindRequesterImpl* ServerChannelFindRequesterImpl::set(std::string name, int32 searchSequenceId, int32 cid, osiSockAddr const & sendTo, + Transport::shared_pointer const & transport, bool responseRequired, bool serverSearch) { Lock guard(_mutex); @@ -421,6 +493,7 @@ ServerChannelFindRequesterImpl* ServerChannelFindRequesterImpl::set(std::string _searchSequenceId = searchSequenceId; _cid = cid; _sendTo = sendTo; + _transport = transport; _responseRequired = responseRequired; _serverSearch = serverSearch; return this; @@ -455,12 +528,19 @@ void ServerChannelFindRequesterImpl::channelFindResult(const Status& /*status*/, _context->s_channelNameToProvider[_name] = channelFind->getChannelProvider(); } _wasFound = wasFound; - - BlockingUDPTransport::shared_pointer bt = _context->getBroadcastTransport(); - if (bt) + if (_transport && _transport->getType() == PVA_TCP_PROTOCOL) { TransportSender::shared_pointer thisSender = shared_from_this(); - bt->enqueueSendRequest(thisSender); + _transport->enqueueSendRequest(thisSender); + } + else + { + BlockingUDPTransport::shared_pointer bt = _context->getBroadcastTransport(); + if (bt) + { + TransportSender::shared_pointer thisSender = shared_from_this(); + bt->enqueueSendRequest(thisSender); + } } } } @@ -472,6 +552,9 @@ std::tr1::shared_ptr ServerChannelFindRequesterImpl::getPeerInfo void ServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) { + char ipAddrStr[24]; + ipAddrToDottedIP(&_sendTo.ia, ipAddrStr, sizeof(ipAddrStr)); + LOG(logLevelDebug, "Search response will be sent to %s", ipAddrStr); control->startMessage(CMD_SEARCH_RESPONSE, 12+4+16+2); Lock guard(_mutex); From c5dc3af13ba718379259194fe77a697aeca0388c Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Tue, 12 Mar 2024 08:07:12 -0500 Subject: [PATCH 16/82] add support for name server channel discovery --- src/remoteClient/clientContextImpl.cpp | 236 +++++++++++++++++++++--- src/remoteClient/pv/clientContextImpl.h | 5 +- 2 files changed, 211 insertions(+), 30 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 01c166dc..995dd87e 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -2584,20 +2584,35 @@ class SearchResponseHandler : public AbstractClientResponseHandler { // NOTE: htons might be a macro (e.g. vxWorks) int16 port = payloadBuffer->getShort(); serverAddress.ia.sin_port = htons(port); + char strBuffer[24]; + ipAddrToDottedIP(&serverAddress.ia, strBuffer, sizeof(strBuffer)); + LOG(logLevelDebug, "Server address decoded as %s, transport type is %s", strBuffer, transport->getType().c_str()); /*string protocol =*/ SerializeHelper::deserializeString(payloadBuffer, transport.get()); + // Get channel search manager + ClientContextImpl::shared_pointer context(_context.lock()); + if(!context) + { + return; + } + std::tr1::shared_ptr csm = context->getChannelSearchManager(); + + // Did we find anything? transport->ensureData(1); bool found = payloadBuffer->getByte() != 0; if (!found) + { + if (transport->getType() == PVA_TCP_PROTOCOL) + { + LOG(logLevelDebug, "No channels found, closing name server transport"); + csm->closeNameServerTransport(); + } return; + } // reads CIDs // TODO optimize - ClientContextImpl::shared_pointer context(_context.lock()); - if(!context) - return; - std::tr1::shared_ptr csm = context->getChannelSearchManager(); int16 count = payloadBuffer->getShort(); for (int i = 0; i < count; i++) { @@ -2742,7 +2757,7 @@ class BeaconResponseHandler : public AbstractClientResponseHandler { serverAddress.ia.sin_port = htons(port); string protocol(SerializeHelper::deserializeString(payloadBuffer, transport.get())); - if(protocol!="tcp") + if(protocol != PVA_TCP_PROTOCOL) return; // TODO optimize @@ -2999,7 +3014,8 @@ class ClientResponseHandler : public ResponseHandler { { if (command < 0 || command >= (int8)m_handlerTable.size()) { - if(IS_LOGGABLE(logLevelError)) { + if(IS_LOGGABLE(logLevelError)) + { std::ios::fmtflags initialflags = std::cerr.flags(); std::cerr<<"Invalid (or unsupported) command: "< m_handlerTable; +public: + virtual ~NameServerClientResponseHandler() {} + /** + * @param context + */ + NameServerClientResponseHandler(ClientContextImpl::shared_pointer const & context) + :ResponseHandler(context.get(), "NameServerClientResponseHandler") + { + ResponseHandler::shared_pointer ignoreResponse(new NoopResponse(context, "Ignore")); + + m_handlerTable.resize(CMD_CANCEL_REQUEST+1); + + m_handlerTable[CMD_BEACON] = ignoreResponse; /* 0 */ + m_handlerTable[CMD_CONNECTION_VALIDATION].reset(new ClientConnectionValidationHandler(context)); /* 1 */ + m_handlerTable[CMD_ECHO] = ignoreResponse; /* 2 */ + m_handlerTable[CMD_SEARCH] = ignoreResponse; /* 3 */ + m_handlerTable[CMD_SEARCH_RESPONSE].reset(new SearchResponseHandler(context)); /* 4 */ + m_handlerTable[CMD_AUTHNZ].reset(new AuthNZHandler(context.get())); /* 5 */ + m_handlerTable[CMD_ACL_CHANGE] = ignoreResponse; /* 6 */ + m_handlerTable[CMD_CREATE_CHANNEL] = ignoreResponse; /* 7 */ + m_handlerTable[CMD_DESTROY_CHANNEL] = ignoreResponse; /* 8 */ + m_handlerTable[CMD_CONNECTION_VALIDATED].reset(new ClientConnectionValidatedHandler(context)); /* 9 */ + m_handlerTable[CMD_GET] = ignoreResponse; /* 10 */ + m_handlerTable[CMD_PUT] = ignoreResponse; /* 11 */ + m_handlerTable[CMD_PUT_GET] = ignoreResponse; /* 12 */ + m_handlerTable[CMD_MONITOR] = ignoreResponse; /* 13 */ + m_handlerTable[CMD_ARRAY] = ignoreResponse; /* 14 */ + m_handlerTable[CMD_DESTROY_REQUEST] = ignoreResponse; /* 15 */ + m_handlerTable[CMD_PROCESS] = ignoreResponse; /* 16 */ + m_handlerTable[CMD_GET_FIELD] = ignoreResponse; /* 17 */ + m_handlerTable[CMD_MESSAGE] = ignoreResponse; /* 18 */ + m_handlerTable[CMD_MULTIPLE_DATA] = ignoreResponse; /* 19 */ + m_handlerTable[CMD_RPC] = ignoreResponse; /* 20 */ + m_handlerTable[CMD_CANCEL_REQUEST] = ignoreResponse; /* 21 */ + } + + virtual void handleResponse(osiSockAddr* responseFrom, + Transport::shared_pointer const & transport, int8 version, int8 command, + size_t payloadSize, ByteBuffer* payloadBuffer) OVERRIDE FINAL + { + if (command < 0 || command >= (int8)m_handlerTable.size()) + { + if(IS_LOGGABLE(logLevelError)) + { + std::ios::fmtflags initialflags = std::cerr.flags(); + std::cerr<<"Invalid (or unsupported) command: "<handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); + } +}; /** * Context state enum. @@ -3037,9 +3118,6 @@ enum ContextState { CONTEXT_DESTROYED }; - - - class InternalClientContextImpl : public ClientContextImpl, public ChannelProvider @@ -3098,8 +3176,9 @@ class InternalClientContextImpl : { InetAddrVector addresses; getSocketAddressList(addresses, addressesStr, m_serverPort); + bool initiateSearch = true; - Channel::shared_pointer channel = createChannelInternal(channelName, channelRequester, priority, addresses); + Channel::shared_pointer channel = createChannelInternal(channelName, channelRequester, priority, addresses, initiateSearch); if (channel.get()) channelRequester->channelCreated(Status::Ok, channel); return channel; @@ -3213,7 +3292,7 @@ class InternalClientContextImpl : Mutex m_channelMutex; private: /** - * Flag indicting what message to send. + * Flag indicating what message to send. */ bool m_issueCreateMessage; @@ -3225,6 +3304,11 @@ class InternalClientContextImpl : */ ServerGUID m_guid; + /** + * Initiate search flag + */ + bool m_initiateSearch; + public: static size_t num_instances; static size_t num_active; @@ -3243,7 +3327,7 @@ class InternalClientContextImpl : string const & name, ChannelRequester::shared_pointer const & requester, short priority, - const InetAddrVector& addresses) : + const InetAddrVector& addresses, bool initiateSearch) : m_context(context), m_channelID(channelID), m_name(name), @@ -3255,7 +3339,8 @@ class InternalClientContextImpl : m_needSubscriptionUpdate(false), m_allowCreation(true), m_serverChannelID(0xFFFFFFFF), - m_issueCreateMessage(true) + m_issueCreateMessage(true), + m_initiateSearch(initiateSearch) { REFTRACE_INCREMENT(num_instances); } @@ -3278,10 +3363,11 @@ class InternalClientContextImpl : string const & name, ChannelRequester::shared_pointer requester, short priority, - const InetAddrVector& addresses) + const InetAddrVector& addresses, + bool initiateSearch) { std::tr1::shared_ptr internal( - new InternalChannelImpl(context, channelID, name, requester, priority, addresses)), + new InternalChannelImpl(context, channelID, name, requester, priority, addresses, initiateSearch)), external(internal.get(), epics::pvAccess::Destroyable::cleaner(internal)); const_cast(internal->m_internal_this) = internal; const_cast(internal->m_external_this) = external; @@ -3308,9 +3394,12 @@ class InternalClientContextImpl : m_getfield.reset(); - // stop searching... shared_pointer thisChannelPointer = internal_from_this(); - m_context->getChannelSearchManager()->unregisterSearchInstance(thisChannelPointer); + // stop searching... + if (m_initiateSearch) + { + m_context->getChannelSearchManager()->unregisterSearchInstance(thisChannelPointer); + } disconnectPendingIO(true); @@ -3530,9 +3619,13 @@ class InternalClientContextImpl : if (m_connectionState != CONNECTED) return; - if (!initiateSearch) { - // stop searching... - m_context->getChannelSearchManager()->unregisterSearchInstance(internal_from_this()); + if (!initiateSearch) + { + if (m_initiateSearch) + { + // stop searching... + m_context->getChannelSearchManager()->unregisterSearchInstance(internal_from_this()); + } } setConnectionState(DISCONNECTED); @@ -3575,6 +3668,11 @@ class InternalClientContextImpl : void initiateSearch(bool penalize = false) { Lock guard(m_channelMutex); + if (!m_initiateSearch) + { + LOG(logLevelDebug, "Search will not be initiated for channel %s", m_name.c_str()); + return; + } m_allowCreation = true; @@ -3584,7 +3682,7 @@ class InternalClientContextImpl : osiSockAddr* serverAddress = &m_addresses[index]; ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); double delay = (m_addressIndex / m_addresses.size())*STATIC_SEARCH_BASE_DELAY_SEC+STATIC_SEARCH_MIN_DELAY_SEC; - LOG(logLevelDebug, "Scheduling channel search for address %s with delay of %.3f seconds.", strBuffer, delay); + LOG(logLevelDebug, "Scheduling direct channel connection attempt for address %s with delay of %.3f seconds.", strBuffer, delay); m_context->getTimer()->scheduleAfterDelay(internal_from_this(), delay); } m_context->getChannelSearchManager()->registerSearchInstance(internal_from_this(), penalize); @@ -3596,7 +3694,7 @@ class InternalClientContextImpl : // TODO boost when a server (from address list) is started!!! IP vs address !!! Transport::shared_pointer transport(m_transport); if (transport) { - LOG(logLevelDebug, "Transport for channel %s is already active, channel search cancelled.", transport->getRemoteName().c_str()); + LOG(logLevelDebug, "Transport for channel %s is already active.", transport->getRemoteName().c_str()); return; } @@ -3965,7 +4063,7 @@ class InternalClientContextImpl : static size_t num_instances; InternalClientContextImpl(const Configuration::shared_pointer& conf) : - m_addressList(""), m_autoAddressList(true), m_serverPort(PVA_SERVER_PORT), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), + m_addressList(""), m_autoAddressList(true), m_serverPort(PVA_SERVER_PORT), m_nsAddressList(""), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), m_broadcastPort(PVA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), m_lastCID(0x10203040), m_lastIOID(0x80706050), @@ -4007,6 +4105,41 @@ class InternalClientContextImpl : return m_searchTransport; } + virtual Transport::shared_pointer getNameServerSearchTransport() + { + if (!m_nsAddresses.size()) + { + return Transport::shared_pointer(); + } + createNameServerConnector(); + + if (!m_nsConnector) + { + return Transport::shared_pointer(); + } + + for (unsigned int i = 0; i < m_nsAddresses.size(); i++) + { + char strBuffer[24]; + m_nsAddressIndex = (m_nsAddressIndex+1) % m_nsAddresses.size(); + osiSockAddr* serverAddress = &m_nsAddresses[m_nsAddressIndex]; + ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); + LOG(logLevelDebug, "Getting name server transport for address %s", strBuffer); + + try + { + Transport::shared_pointer t = m_nsConnector->connect(m_nsChannel, m_nsResponseHandler, *serverAddress, EPICS_PVA_MINOR_VERSION, 0); + LOG(logLevelDebug, "Got name server transport for address %s", strBuffer); + return t; + } + catch (std::exception& e) + { + LOG(logLevelDebug, "Could not get name server transport for %s: %s", strBuffer, e.what()); + } + } + return Transport::shared_pointer(); + } + virtual void initialize() OVERRIDE FINAL { Lock lock(m_contextMutex); @@ -4028,6 +4161,7 @@ class InternalClientContextImpl : out << "ADDR_LIST : " << m_addressList << std::endl; out << "AUTO_ADDR_LIST : " << (m_autoAddressList ? "true" : "false") << std::endl; out << "SERVER_PORT : " << m_serverPort << std::endl; + out << "NAME_SERVERS : " << m_nsAddressList << std::endl; out << "CONNECTION_TIMEOUT : " << m_connectionTimeout << std::endl; out << "BEACON_PERIOD : " << m_beaconPeriod << std::endl; out << "BROADCAST_PORT : " << m_broadcastPort << std::endl;; @@ -4121,10 +4255,29 @@ class InternalClientContextImpl : m_addressList = m_configuration->getPropertyAsString("EPICS_PVA_ADDR_LIST", m_addressList); m_autoAddressList = m_configuration->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", m_autoAddressList); m_serverPort = m_configuration->getPropertyAsInteger("EPICS_PVA_SERVER_PORT", m_serverPort); + LOG(logLevelDebug, "Configured server port: %d", m_serverPort); + m_nsAddressList = m_configuration->getPropertyAsString("EPICS_PVA_NAME_SERVERS", m_nsAddressList); + LOG(logLevelDebug, "Configured name server address list: %s", m_nsAddressList.c_str()); m_connectionTimeout = m_configuration->getPropertyAsFloat("EPICS_PVA_CONN_TMO", m_connectionTimeout); m_beaconPeriod = m_configuration->getPropertyAsFloat("EPICS_PVA_BEACON_PERIOD", m_beaconPeriod); m_broadcastPort = m_configuration->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", m_broadcastPort); + LOG(logLevelDebug, "Configured broadcast port: %d", m_broadcastPort); m_receiveBufferSize = m_configuration->getPropertyAsInteger("EPICS_PVA_MAX_ARRAY_BYTES", m_receiveBufferSize); + getSocketAddressList(m_nsAddresses, m_nsAddressList, m_serverPort); + } + + void createNameServerConnector() + { + if (!m_nsConnector && m_nsAddresses.size()) + { + LOG(logLevelDebug, "Creating internal name server channel and connector"); + InetAddrVector nsAddresses; // avoid direct connection attempts + InternalClientContextImpl::shared_pointer thisPointer(internal_from_this()); + std::string nsChannelName = "__NS_CHANNEL__"; + bool initiateSearch = false; + m_nsChannel = createChannelInternal(nsChannelName, DefaultChannelRequester::build(), 0, nsAddresses, initiateSearch); + m_nsConnector.reset(new BlockingTCPConnector(thisPointer, m_receiveBufferSize, m_connectionTimeout)); + } } void internalInitialize() { @@ -4137,6 +4290,7 @@ class InternalClientContextImpl : // stores many weak_ptr m_responseHandler.reset(new ClientResponseHandler(thisPointer)); + m_nsResponseHandler.reset(new NameServerClientResponseHandler(thisPointer)); m_channelSearchManager.reset(new ChannelSearchManager(thisPointer)); @@ -4395,8 +4549,7 @@ class InternalClientContextImpl : */ // TODO no minor version with the addresses // TODO what if there is an channel with the same name, but on different host! - ClientChannelImpl::shared_pointer createChannelInternal(std::string const & name, ChannelRequester::shared_pointer const & requester, short priority, - const InetAddrVector& addresses) OVERRIDE FINAL { // TODO addresses + ClientChannelImpl::shared_pointer createChannelInternal(std::string const & name, ChannelRequester::shared_pointer const & requester, short priority, const InetAddrVector& addresses, bool initiateSearch) OVERRIDE FINAL { // TODO addresses checkState(); checkChannelName(name); @@ -4414,7 +4567,7 @@ class InternalClientContextImpl : * as our channels. */ pvAccessID cid = generateCID(); - return InternalChannelImpl::create(internal_from_this(), cid, name, requester, priority, addresses); + return InternalChannelImpl::create(internal_from_this(), cid, name, requester, priority, addresses, initiateSearch); } catch(std::exception& e) { LOG(logLevelError, "createChannelInternal() exception: %s\n", e.what()); return ClientChannelImpl::shared_pointer(); @@ -4445,6 +4598,32 @@ class InternalClientContextImpl : */ int m_serverPort; + /** + * A space-separated list of name server addresses for process variable name resolution. + * Each address must be of the form: ip.number:port or host.name:port + */ + string m_nsAddressList; + + /** + * List of name server addresses. + */ + InetAddrVector m_nsAddresses; + + /** + * Index of currently used name server address (rollover pointer in a list). + */ + int m_nsAddressIndex; + + /** + * Name server channel + */ + ClientChannelImpl::shared_pointer m_nsChannel; + + /** + * Name server connector + */ + epics::auto_ptr m_nsConnector; + /** * If the context doesn't see a beacon from a server that it is connected to for * connectionTimeout seconds then a state-of-health message is sent to the server over TCP/IP. @@ -4499,6 +4678,11 @@ class InternalClientContextImpl : */ ClientResponseHandler::shared_pointer m_responseHandler; + /** + * Name server search response handler. + */ + NameServerClientResponseHandler::shared_pointer m_nsResponseHandler; + /** * Map of channels (keys are CIDs). */ diff --git a/src/remoteClient/pv/clientContextImpl.h b/src/remoteClient/pv/clientContextImpl.h index 77fe1e49..a713e471 100644 --- a/src/remoteClient/pv/clientContextImpl.h +++ b/src/remoteClient/pv/clientContextImpl.h @@ -94,10 +94,7 @@ class ClientContextImpl : public Context virtual void registerChannel(ClientChannelImpl::shared_pointer const & channel) = 0; virtual void unregisterChannel(ClientChannelImpl::shared_pointer const & channel) = 0; - virtual ClientChannelImpl::shared_pointer createChannelInternal(std::string const &name, - ChannelRequester::shared_pointer const & requester, - short priority, - const InetAddrVector& addresses) = 0; + virtual ClientChannelImpl::shared_pointer createChannelInternal(std::string const &name, ChannelRequester::shared_pointer const & requester, short priority, const InetAddrVector& addresses, bool initiateSearch) = 0; virtual ResponseRequest::shared_pointer getResponseRequest(pvAccessID ioid) = 0; virtual pvAccessID registerResponseRequest(ResponseRequest::shared_pointer const & request) = 0; From 8b32dba086d92a792aaf788b332a0ab6e7633429 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Tue, 12 Mar 2024 08:09:08 -0500 Subject: [PATCH 17/82] add tcp acceptor for channel search --- src/server/serverContext.cpp | 42 +++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 82151e9f..dde98716 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -38,11 +38,13 @@ ServerContextImpl::ServerContextImpl(): _beaconPeriod(15.0), _broadcastPort(PVA_BROADCAST_PORT), _serverPort(PVA_SERVER_PORT), + _searchServerPort(PVA_BROADCAST_PORT), _receiveBufferSize(MAX_TCP_RECV), _timer(new Timer("PVAS timers", lowerPriority)), _beaconEmitter(), _acceptor(), _transportRegistry(), + _searchAcceptor(), _channelProviders(), _beaconServerStatusProvider(), _startTime() @@ -146,6 +148,12 @@ void ServerContextImpl::loadConfiguration() _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVA_MAX_ARRAY_BYTES", _receiveBufferSize); _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVAS_MAX_ARRAY_BYTES", _receiveBufferSize); + // TCP search + memset(&_searchIfaceAddr, 0, sizeof(_searchIfaceAddr)); + _searchIfaceAddr.ia.sin_family = AF_INET; + _searchIfaceAddr.ia.sin_addr.s_addr = _ifaceAddr.ia.sin_addr.s_addr; + _searchIfaceAddr.ia.sin_port = htons(_broadcastPort); + if(_channelProviders.empty()) { std::string providers = config->getPropertyAsString("EPICS_PVAS_PROVIDER_NAMES", PVACCESS_DEFAULT_PROVIDER); @@ -272,15 +280,21 @@ void ServerContextImpl::initialize() ServerContextImpl::shared_pointer thisServerContext = shared_from_this(); // we create reference cycles here which are broken by our shutdown() method, _responseHandler.reset(new ServerResponseHandler(thisServerContext)); + _searchResponseHandler.reset(new ServerSearchResponseHandler(thisServerContext)); _acceptor.reset(new BlockingTCPAcceptor(thisServerContext, _responseHandler, _ifaceAddr, _receiveBufferSize)); _serverPort = ntohs(_acceptor->getBindAddress()->ia.sin_port); + LOG(logLevelDebug, "Server port: %d", _serverPort); + + // TCP search listener + _searchAcceptor.reset(new BlockingTCPAcceptor(thisServerContext, _searchResponseHandler, _searchIfaceAddr, MAX_TCP_RECV)); + _searchServerPort = ntohs(_searchAcceptor->getBindAddress()->ia.sin_port); + LOG(logLevelDebug, "Search server port: %d", _searchServerPort); // setup broadcast UDP transport - initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, - _broadcastPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); + initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, _broadcastPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); - _beaconEmitter.reset(new BeaconEmitter("tcp", _broadcastTransport, thisServerContext)); + _beaconEmitter.reset(new BeaconEmitter(PVA_TCP_PROTOCOL, _broadcastTransport, thisServerContext)); _beaconEmitter->start(); } @@ -349,12 +363,23 @@ void ServerContextImpl::shutdown() // this will also destroy all channels _transportRegistry.clear(); + // clear search acceptor + if (_searchAcceptor) + { + _searchAcceptor->destroy(); + LEAK_CHECK(_searchAcceptor, "_searchAcceptor") + _searchAcceptor.reset(); + } + // drop timer queue LEAK_CHECK(_timer, "_timer") _timer.reset(); // response handlers hold strong references to us, // so must break the cycles + LEAK_CHECK(_searchResponseHandler, "_searchResponseHandler") + _searchResponseHandler.reset(); + LEAK_CHECK(_responseHandler, "_responseHandler") _responseHandler.reset(); @@ -480,6 +505,11 @@ int32 ServerContextImpl::getServerPort() return _serverPort; } +int32 ServerContextImpl::getSearchServerPort() +{ + return _searchServerPort; +} + int32 ServerContextImpl::getBroadcastPort() { return _broadcastPort; @@ -531,6 +561,12 @@ Transport::shared_pointer ServerContextImpl::getSearchTransport() return Transport::shared_pointer(); } +Transport::shared_pointer ServerContextImpl::getNameServerSearchTransport() +{ + // not used + return Transport::shared_pointer(); +} + void ServerContextImpl::newServerDetected() { // not used From bcaa79400c5457aaa4c9a8b6351998f6f3db468a Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Tue, 12 Mar 2024 08:11:05 -0500 Subject: [PATCH 18/82] support for tcp channel search --- src/server/pv/serverContext.h | 6 ++++++ src/server/pv/serverContextImpl.h | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index bbe361fb..13f8dce3 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -76,6 +76,12 @@ class epicsShareClass ServerContext */ virtual epics::pvData::int32 getServerPort() = 0; + /** + * Get search server port. + * @return search server port. + */ + virtual epics::pvData::int32 getSearchServerPort() = 0; + /** * Get broadcast port. * @return broadcast port. diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index c148c18b..5494dc42 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -49,6 +49,7 @@ class ServerContextImpl : epics::pvData::Timer::shared_pointer getTimer() OVERRIDE FINAL; Channel::shared_pointer getChannel(pvAccessID id) OVERRIDE FINAL; Transport::shared_pointer getSearchTransport() OVERRIDE FINAL; + Transport::shared_pointer getNameServerSearchTransport() OVERRIDE FINAL; Configuration::const_shared_pointer getConfiguration() OVERRIDE FINAL; TransportRegistry* getTransportRegistry() OVERRIDE FINAL; @@ -82,6 +83,12 @@ class ServerContextImpl : */ epics::pvData::int32 getServerPort() OVERRIDE FINAL; + /** + * Get search server port. + * @return search server port. + */ + epics::pvData::int32 getSearchServerPort() OVERRIDE FINAL; + /** * Get broadcast port. * @return broadcast port. @@ -140,6 +147,7 @@ class ServerContextImpl : IfaceNodeVector _ifaceList; osiSockAddr _ifaceAddr; + osiSockAddr _searchIfaceAddr; /** * A space-separated list of address from which to ignore name resolution requests. @@ -167,6 +175,11 @@ class ServerContextImpl : */ epics::pvData::int32 _serverPort; + /** + * Search server port. + */ + epics::pvData::int32 _searchServerPort; + /** * Length in bytes of the maximum buffer (payload) size that may pass through PVA. */ @@ -197,7 +210,16 @@ class ServerContextImpl : */ TransportRegistry _transportRegistry; + /** + * TCP search acceptor + */ + BlockingTCPAcceptor::shared_pointer _searchAcceptor; + + /** + * Response handlers + */ ResponseHandler::shared_pointer _responseHandler; + ResponseHandler::shared_pointer _searchResponseHandler; // const after loadConfiguration() std::vector _channelProviders; From 48fb8397eea01aba82b7b60a4ace1668956ac887 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 13 Mar 2024 14:37:37 -0500 Subject: [PATCH 19/82] introduce new interfaces for managing tcp transport --- src/remote/codec.cpp | 7 ++++++- src/remote/pv/blockingUDP.h | 5 +++++ src/remote/pv/codec.h | 7 +++++++ src/remote/pv/remote.h | 6 ++++++ src/server/pv/serverContextImpl.h | 1 + src/server/serverContext.cpp | 10 +++++++--- testApp/remote/testCodec.cpp | 4 +++- 7 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 75febd27..3e61f075 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -1764,7 +1764,7 @@ bool BlockingClientTCPTransportCodec::acquire(ClientChannelImpl::shared_pointer if (IS_LOGGABLE(logLevelDebug)) { - LOG(logLevelDebug, "Acquiring transport to %s.", _socketName.c_str()); + LOG(logLevelDebug, "Acquiring transport to %s for channel cid %d.", _socketName.c_str(), client->getID()); } _owners[client->getID()] = ClientChannelImpl::weak_pointer(client); @@ -1831,6 +1831,11 @@ void BlockingClientTCPTransportCodec::release(pvAccessID clientID) { } } +bool BlockingClientTCPTransportCodec::isUsed() +{ + return (_owners.size() > 0); +} + void BlockingClientTCPTransportCodec::send(ByteBuffer* buffer, TransportSendControl* control) { diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index 71af2870..fd146ad3 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -196,6 +196,11 @@ class BlockingUDPTransport : virtual void release(pvAccessID /*clientId*/) OVERRIDE FINAL {} + virtual bool isUsed() OVERRIDE FINAL + { + return false; + } + /** * Set ignore list. * @param address list of ignored addresses. diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index 4bdff568..0c8495c4 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -477,6 +477,11 @@ class BlockingServerTCPTransportCodec : virtual void release(pvAccessID /*clientId*/) OVERRIDE FINAL {} + virtual bool isUsed() OVERRIDE FINAL + { + return false; + } + pvAccessID preallocateChannelSID(); void depreallocateChannelSID(pvAccessID /*sid*/) {} @@ -612,6 +617,8 @@ class BlockingClientTCPTransportCodec : virtual void release(pvAccessID clientId) OVERRIDE FINAL; + virtual bool isUsed() OVERRIDE FINAL; + virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) OVERRIDE FINAL; diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 6f5e51f4..564736c1 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -191,6 +191,11 @@ class epicsShareClass Transport : public epics::pvData::DeserializableControl { */ virtual void release(pvAccessID clientId) = 0; + /** + * Is transport used + */ + virtual bool isUsed() = 0; + /** * Get protocol type (tcp, udp, ssl, etc.). * @return protocol type. @@ -312,6 +317,7 @@ class Context { virtual std::tr1::shared_ptr getChannel(pvAccessID id) = 0; virtual Transport::shared_pointer getSearchTransport() = 0; virtual Transport::shared_pointer getNameServerSearchTransport() = 0; + virtual void releaseNameServerSearchTransport() = 0; }; /** diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 5494dc42..39d163ee 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -50,6 +50,7 @@ class ServerContextImpl : Channel::shared_pointer getChannel(pvAccessID id) OVERRIDE FINAL; Transport::shared_pointer getSearchTransport() OVERRIDE FINAL; Transport::shared_pointer getNameServerSearchTransport() OVERRIDE FINAL; + void releaseNameServerSearchTransport() OVERRIDE FINAL; Configuration::const_shared_pointer getConfiguration() OVERRIDE FINAL; TransportRegistry* getTransportRegistry() OVERRIDE FINAL; diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index dde98716..03665fb9 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -360,9 +360,6 @@ void ServerContextImpl::shutdown() _acceptor.reset(); } - // this will also destroy all channels - _transportRegistry.clear(); - // clear search acceptor if (_searchAcceptor) { @@ -371,6 +368,9 @@ void ServerContextImpl::shutdown() _searchAcceptor.reset(); } + // this will also destroy all channels + _transportRegistry.clear(); + // drop timer queue LEAK_CHECK(_timer, "_timer") _timer.reset(); @@ -567,6 +567,10 @@ Transport::shared_pointer ServerContextImpl::getNameServerSearchTransport() return Transport::shared_pointer(); } +void ServerContextImpl::releaseNameServerSearchTransport() +{ +} + void ServerContextImpl::newServerDetected() { // not used diff --git a/testApp/remote/testCodec.cpp b/testApp/remote/testCodec.cpp index ce99443f..10833de9 100644 --- a/testApp/remote/testCodec.cpp +++ b/testApp/remote/testCodec.cpp @@ -345,9 +345,11 @@ class TestCodec: public AbstractCodec { void release(pvAccessID clientId) {} + bool isUsed() {return false;} + std::string getType() const { - return std::string("TCP"); + return PVA_TCP_PROTOCOL; } const osiSockAddr& getRemoteAddress() const { From d78b5a168c703c314b4150242aed5411aef23bc1 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 13 Mar 2024 15:31:15 -0500 Subject: [PATCH 20/82] use different channel priority for name server searches; move name server transport to channel context --- src/remote/channelSearchManager.cpp | 30 ++++++---------- src/remote/pv/channelSearchManager.h | 9 ++--- src/remoteClient/clientContextImpl.cpp | 48 ++++++++++++++++++++++---- 3 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/remote/channelSearchManager.cpp b/src/remote/channelSearchManager.cpp index 04767716..5290b479 100644 --- a/src/remote/channelSearchManager.cpp +++ b/src/remote/channelSearchManager.cpp @@ -82,8 +82,7 @@ ChannelSearchManager::ChannelSearchManager(Context::shared_pointer const & conte m_lastTimeSent(), m_channelMutex(), m_userValueMutex(), - m_mutex(), - m_nsTransport() + m_mutex() { // initialize random seed with some random value srand ( time(NULL) ); @@ -183,6 +182,7 @@ void ChannelSearchManager::searchResponse(const ServerGUID & guid, pvAccessID ci SearchInstance::shared_pointer si(channelsIter->second.lock()); // remove from search list + LOG(logLevelDebug, "Removing cid %d from the channel map", cid); m_channels.erase(cid); guard.unlock(); @@ -191,21 +191,14 @@ void ChannelSearchManager::searchResponse(const ServerGUID & guid, pvAccessID ci if(si) si->searchResponse(guid, minorRevision, serverAddress); } - - // Cleanup name server search - if(m_nsTransport && m_channels.size() == 0) - { - closeNameServerTransport(); - } + releaseNameServerTransport(); } -void ChannelSearchManager::closeNameServerTransport() +void ChannelSearchManager::releaseNameServerTransport() { - if(m_nsTransport) + if(m_channels.size() == 0) { - LOG(logLevelDebug, "Closing name server transport"); - m_nsTransport->close(); - m_nsTransport.reset(); + m_context.lock()->releaseNameServerSearchTransport(); } } @@ -305,14 +298,11 @@ void ChannelSearchManager::flushSendBuffer() ut->send(&m_sendBuffer, inetAddressType_broadcast_multicast); // Name server search - if(!m_nsTransport) - { - m_nsTransport = m_context.lock()->getNameServerSearchTransport(); - } - if(m_nsTransport) + Transport::shared_pointer nsTransport = m_context.lock()->getNameServerSearchTransport(); + if(nsTransport) { - LOG(logLevelDebug, "Initiating name server search"); - m_nsTransport->enqueueSendRequest(shared_from_this()); + LOG(logLevelDebug, "Initiating name server search for %lu channels", m_channels.size()); + nsTransport->enqueueSendRequest(shared_from_this()); } initializeSendBuffer(); } diff --git a/src/remote/pv/channelSearchManager.h b/src/remote/pv/channelSearchManager.h index ad59b21e..0aa7789a 100644 --- a/src/remote/pv/channelSearchManager.h +++ b/src/remote/pv/channelSearchManager.h @@ -110,8 +110,8 @@ class ChannelSearchManager : ChannelSearchManager(Context::shared_pointer const & context); void activate(); - // Closes name server transport. - void closeNameServerTransport(); + // Releases name server transport. + void releaseNameServerTransport(); private: @@ -177,11 +177,6 @@ class ChannelSearchManager : * m_channels mutex. */ epics::pvData::Mutex m_mutex; - - /** - * Name server trasnport. - */ - Transport::shared_pointer m_nsTransport; }; } diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 995dd87e..9fb939ae 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -43,6 +43,8 @@ //#include +#define PVA_CHANNEL_SEARCH_PRIORITY 98 + using std::tr1::dynamic_pointer_cast; using std::tr1::static_pointer_cast; @@ -2605,8 +2607,8 @@ class SearchResponseHandler : public AbstractClientResponseHandler { { if (transport->getType() == PVA_TCP_PROTOCOL) { - LOG(logLevelDebug, "No channels found, closing name server transport"); - csm->closeNameServerTransport(); + LOG(logLevelDebug, "No channels found, releasing name server transport"); + csm->releaseNameServerTransport(); } return; } @@ -2614,10 +2616,12 @@ class SearchResponseHandler : public AbstractClientResponseHandler { // reads CIDs // TODO optimize int16 count = payloadBuffer->getShort(); + LOG(logLevelDebug, "Found %hd channels", count); for (int i = 0; i < count; i++) { transport->ensureData(4); pvAccessID cid = payloadBuffer->getInt(); + LOG(logLevelDebug, "Invoking search response for channel cid: %d", cid); csm->searchResponse(guid, cid, searchSequenceId, version, &serverAddress); } @@ -4063,7 +4067,7 @@ class InternalClientContextImpl : static size_t num_instances; InternalClientContextImpl(const Configuration::shared_pointer& conf) : - m_addressList(""), m_autoAddressList(true), m_serverPort(PVA_SERVER_PORT), m_nsAddressList(""), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), + m_addressList(""), m_autoAddressList(true), m_serverPort(PVA_SERVER_PORT), m_nsAddressList(""), m_nsAddressIndex(0), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), m_broadcastPort(PVA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), m_lastCID(0x10203040), m_lastIOID(0x80706050), @@ -4107,6 +4111,11 @@ class InternalClientContextImpl : virtual Transport::shared_pointer getNameServerSearchTransport() { + if (m_nsTransport) + { + return m_nsTransport; + } + if (!m_nsAddresses.size()) { return Transport::shared_pointer(); @@ -4121,16 +4130,16 @@ class InternalClientContextImpl : for (unsigned int i = 0; i < m_nsAddresses.size(); i++) { char strBuffer[24]; - m_nsAddressIndex = (m_nsAddressIndex+1) % m_nsAddresses.size(); osiSockAddr* serverAddress = &m_nsAddresses[m_nsAddressIndex]; ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "Getting name server transport for address %s", strBuffer); + m_nsAddressIndex = (m_nsAddressIndex+1) % m_nsAddresses.size(); try { - Transport::shared_pointer t = m_nsConnector->connect(m_nsChannel, m_nsResponseHandler, *serverAddress, EPICS_PVA_MINOR_VERSION, 0); + m_nsTransport = m_nsConnector->connect(m_nsChannel, m_nsResponseHandler, *serverAddress, EPICS_PVA_MINOR_VERSION, PVA_CHANNEL_SEARCH_PRIORITY); LOG(logLevelDebug, "Got name server transport for address %s", strBuffer); - return t; + return m_nsTransport; } catch (std::exception& e) { @@ -4140,6 +4149,26 @@ class InternalClientContextImpl : return Transport::shared_pointer(); } + virtual void releaseNameServerSearchTransport() + { + if (!m_nsTransport) + { + return; + } + LOG(logLevelDebug, "Releasing transport used for name server channel %d", m_nsChannel->getID()); + m_nsTransport->release(m_nsChannel->getID()); + if (m_nsTransport->isUsed()) + { + LOG(logLevelDebug, "Name server transport is still in use by other clients"); + } + else + { + LOG(logLevelDebug, "Closing name server transport"); + m_nsTransport->close(); + m_nsTransport.reset(); + } + } + virtual void initialize() OVERRIDE FINAL { Lock lock(m_contextMutex); @@ -4275,7 +4304,7 @@ class InternalClientContextImpl : InternalClientContextImpl::shared_pointer thisPointer(internal_from_this()); std::string nsChannelName = "__NS_CHANNEL__"; bool initiateSearch = false; - m_nsChannel = createChannelInternal(nsChannelName, DefaultChannelRequester::build(), 0, nsAddresses, initiateSearch); + m_nsChannel = createChannelInternal(nsChannelName, DefaultChannelRequester::build(), PVA_CHANNEL_SEARCH_PRIORITY, nsAddresses, initiateSearch); m_nsConnector.reset(new BlockingTCPConnector(thisPointer, m_receiveBufferSize, m_connectionTimeout)); } } @@ -4624,6 +4653,11 @@ class InternalClientContextImpl : */ epics::auto_ptr m_nsConnector; + /** + * Name server transport + */ + Transport::shared_pointer m_nsTransport; + /** * If the context doesn't see a beacon from a server that it is connected to for * connectionTimeout seconds then a state-of-health message is sent to the server over TCP/IP. From 98ec0bced10f61ab6a7b9c1282a7f96b82e11bc0 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 13 Mar 2024 15:55:22 -0500 Subject: [PATCH 21/82] stop search if channel is found via direct connection --- src/remoteClient/clientContextImpl.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 9fb939ae..6e857e82 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -3777,7 +3777,12 @@ class InternalClientContextImpl : old_transport.swap(m_transport); m_transport.swap(transport); - m_transport->enqueueSendRequest(internal_from_this()); + shared_pointer thisChannelPointer = internal_from_this(); + m_transport->enqueueSendRequest(thisChannelPointer); + if (m_initiateSearch) + { + m_context->getChannelSearchManager()->unregisterSearchInstance(thisChannelPointer); + } } } From 9425a18f67030d11b30165e9dd15175b4b69b0a0 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 15 Mar 2024 16:56:48 -0500 Subject: [PATCH 22/82] use default address list if provided string is empty --- src/remoteClient/clientContextImpl.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 6e857e82..c45fcd46 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -3169,7 +3169,7 @@ class InternalClientContextImpl : ChannelRequester::shared_pointer const & channelRequester, short priority) OVERRIDE FINAL { - return createChannel(channelName, channelRequester, priority, m_addressList); + return createChannel(channelName, channelRequester, priority, std::string()); } virtual Channel::shared_pointer createChannel( @@ -3179,7 +3179,16 @@ class InternalClientContextImpl : std::string const & addressesStr) OVERRIDE FINAL { InetAddrVector addresses; - getSocketAddressList(addresses, addressesStr, m_serverPort); + if (addressesStr.empty()) + { + LOG(logLevelDebug, "Creating channel using default address list: %s", m_addressList.c_str()); + getSocketAddressList(addresses, m_addressList, m_serverPort); + } + else + { + LOG(logLevelDebug, "Creating channel using address list: %s", addressesStr.c_str()); + getSocketAddressList(addresses, addressesStr, m_serverPort); + } bool initiateSearch = true; Channel::shared_pointer channel = createChannelInternal(channelName, channelRequester, priority, addresses, initiateSearch); @@ -4287,6 +4296,7 @@ class InternalClientContextImpl : SET_LOG_LEVEL(logLevelDebug); m_addressList = m_configuration->getPropertyAsString("EPICS_PVA_ADDR_LIST", m_addressList); + LOG(logLevelDebug, "Configured PVA address list: %s", m_addressList.c_str()); m_autoAddressList = m_configuration->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", m_autoAddressList); m_serverPort = m_configuration->getPropertyAsInteger("EPICS_PVA_SERVER_PORT", m_serverPort); LOG(logLevelDebug, "Configured server port: %d", m_serverPort); From bac2944b94a44dc4684b8b5576cd905a5119d847 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 18 Mar 2024 16:49:08 -0500 Subject: [PATCH 23/82] allow initializing server context with different set of response handlers --- src/server/Makefile | 5 ++++ src/server/pv/serverContext.h | 3 +++ src/server/pv/serverContextImpl.h | 4 ++- src/server/serverContext.cpp | 43 ++++++++++++++++++++++++++++--- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/server/Makefile b/src/server/Makefile index 4a5fd934..5c1c80e5 100644 --- a/src/server/Makefile +++ b/src/server/Makefile @@ -4,6 +4,11 @@ SRC_DIRS += $(PVACCESS_SRC)/server INC += pv/serverContext.h INC += pv/beaconServerStatusProvider.h +INC += pv/responseHandlers.h +INC += pv/serverContextImpl.h +INC += pv/serverChannelImpl.h +INC += pv/baseChannelRequester.h +INC += pv/beaconEmitter.h INC += pva/server.h INC += pva/sharedstate.h diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index 13f8dce3..e41700a7 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -118,6 +119,8 @@ class epicsShareClass ServerContext Config& providers(const std::vector& p) { _providers = p; return *this; } //! short hand for providers() with a length 1 vector. Config& provider(const ChannelProvider::shared_pointer& p) { _providers.push_back(p); return *this; } + Configuration::const_shared_pointer getConfiguration() const {return _conf;}; + std::vector getProviders() const {return _providers;} }; /** Start a new PVA server diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 39d163ee..82e37b23 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -37,10 +37,11 @@ class ServerContextImpl : ServerContextImpl(); virtual ~ServerContextImpl(); + void initialize(const ResponseHandler::shared_pointer& responseHandler = ResponseHandler::shared_pointer(), const ResponseHandler::shared_pointer& searchResponseHandler = ResponseHandler::shared_pointer()); + //**************** derived from ServerContext ****************// const ServerGUID& getGUID() OVERRIDE FINAL; const Version& getVersion() OVERRIDE FINAL; - void initialize(); void run(epics::pvData::uint32 seconds) OVERRIDE FINAL; void shutdown() OVERRIDE FINAL; void printInfo(std::ostream& str, int lvl) OVERRIDE FINAL; @@ -53,6 +54,7 @@ class ServerContextImpl : void releaseNameServerSearchTransport() OVERRIDE FINAL; Configuration::const_shared_pointer getConfiguration() OVERRIDE FINAL; TransportRegistry* getTransportRegistry() OVERRIDE FINAL; + static ServerContextImpl::shared_pointer create(const Config& conf = Config()); virtual void newServerDetected() OVERRIDE FINAL; diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 03665fb9..d489b7d0 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -270,7 +270,7 @@ bool ServerContextImpl::isChannelProviderNamePreconfigured() return config->hasProperty("EPICS_PVAS_PROVIDER_NAMES"); } -void ServerContextImpl::initialize() +void ServerContextImpl::initialize(const ResponseHandler::shared_pointer& responseHandler, const ResponseHandler::shared_pointer& searchResponseHandler) { Lock guard(_mutex); @@ -279,8 +279,22 @@ void ServerContextImpl::initialize() ServerContextImpl::shared_pointer thisServerContext = shared_from_this(); // we create reference cycles here which are broken by our shutdown() method, - _responseHandler.reset(new ServerResponseHandler(thisServerContext)); - _searchResponseHandler.reset(new ServerSearchResponseHandler(thisServerContext)); + if (responseHandler) + { + _responseHandler = responseHandler; + } + else + { + _responseHandler.reset(new ServerResponseHandler(thisServerContext)); + } + if (searchResponseHandler) + { + _searchResponseHandler = searchResponseHandler; + } + else + { + _searchResponseHandler.reset(new ServerSearchResponseHandler(thisServerContext)); + } _acceptor.reset(new BlockingTCPAcceptor(thisServerContext, _responseHandler, _ifaceAddr, _receiveBufferSize)); _serverPort = ntohs(_acceptor->getBindAddress()->ia.sin_port); @@ -615,6 +629,29 @@ struct shutdown_dtor { }; } +ServerContextImpl::shared_pointer ServerContextImpl::create(const Config &conf) +{ + ServerContextImpl::shared_pointer ret(new ServerContextImpl()); + ret->configuration = conf.getConfiguration(); + ret->_channelProviders = conf.getProviders(); + + if (!ret->configuration) + { + ConfigurationProvider::shared_pointer configurationProvider = ConfigurationFactory::getProvider(); + ret->configuration = configurationProvider->getConfiguration("pvAccess-server"); + if (!ret->configuration) + { + ret->configuration = configurationProvider->getConfiguration("system"); + } + } + if(!ret->configuration) { + ret->configuration = ConfigurationBuilder().push_env().build(); + } + + ret->loadConfiguration(); + return ret; +} + ServerContext::shared_pointer ServerContext::create(const Config &conf) { ServerContextImpl::shared_pointer ret(new ServerContextImpl()); From 581f611608974625deefc6076fb6245ad649f18c Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 18 Mar 2024 16:49:47 -0500 Subject: [PATCH 24/82] expose additional header --- src/remote/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/remote/Makefile b/src/remote/Makefile index 89f43613..a7520056 100644 --- a/src/remote/Makefile +++ b/src/remote/Makefile @@ -3,6 +3,7 @@ SRC_DIRS += $(PVACCESS_SRC)/remote INC += pv/security.h +INC += pv/remote.h INC += pv/serializationHelper.h pvAccess_SRCS += blockingUDPTransport.cpp From 0cc8c2bb2a3412b77935fcb685f512b1361d28a7 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Tue, 19 Mar 2024 13:45:31 -0500 Subject: [PATCH 25/82] fix logging typo --- src/server/responseHandlers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index f00fc6b5..997a04b6 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -509,7 +509,7 @@ void ServerChannelFindRequesterImpl::channelFindResult(const Status& /*status*/, { if ((_responseCount+1) == _expectedResponseCount) { - LOG(logLevelDebug,"[ServerChannelFindRequesterImpl::channelFindResult] More responses received than expected fpr channel '%s'!", _name.c_str()); + LOG(logLevelDebug,"[ServerChannelFindRequesterImpl::channelFindResult] More responses received than expected for channel '%s'!", _name.c_str()); } return; } From 53e15c40be0011f23b6fd8bd01836985e86c8ad4 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 20 Mar 2024 11:41:01 -0500 Subject: [PATCH 26/82] add utility function to convert string to inet address --- src/utils/inetAddressUtil.cpp | 16 ++++++++++++++++ src/utils/pv/inetAddressUtil.h | 16 ++++++++++++++++ testApp/utils/testInetAddressUtils.cpp | 20 +++++++++++++++++--- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/utils/inetAddressUtil.cpp b/src/utils/inetAddressUtil.cpp index 1bf9f307..9b7af7b8 100644 --- a/src/utils/inetAddressUtil.cpp +++ b/src/utils/inetAddressUtil.cpp @@ -129,6 +129,22 @@ string inetAddressToString(const osiSockAddr &addr, return saddr.str(); } +bool stringToInetAddress(const std::string& addrStr, osiSockAddr& addr) { + + if (addrStr.empty()) { + return false; + } + unsigned short defaultPort = 0; + if(addr.sa.sa_family == AF_INET) { + defaultPort = ntohs(addr.ia.sin_port); + } + addr.ia.sin_family = AF_INET; + if (aToIPAddr(addrStr.c_str(), defaultPort, &addr.ia)) { + return false; + } + return true; +} + ifaceNode::ifaceNode() { memset(&addr, 0, sizeof(addr)); diff --git a/src/utils/pv/inetAddressUtil.h b/src/utils/pv/inetAddressUtil.h index ecdcd216..05229dc2 100644 --- a/src/utils/pv/inetAddressUtil.h +++ b/src/utils/pv/inetAddressUtil.h @@ -66,9 +66,25 @@ epicsShareFunc bool isMulticastAddress(const osiSockAddr* address); epicsShareFunc void getSocketAddressList(InetAddrVector& ret, const std::string & list, int defaultPort, const InetAddrVector* appendList = NULL); +/** + * Convert socket address to string. + * @param addr inet address + * @param displayPort flag to display port number (default: true) + * @param displayHex flag to display hex format (default: false) + * @return inet address string + */ epicsShareFunc std::string inetAddressToString(const osiSockAddr &addr, bool displayPort = true, bool displayHex = false); +/** + * Convert string to socket address + * @param addrStr input address[:port] string + * @param addr resulting inet address + * @return true if conversion was successful, false otherwise + */ +epicsShareFunc bool stringToInetAddress(const std::string& addrStr, + osiSockAddr& addr); + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // comparators for osiSockAddr diff --git a/testApp/utils/testInetAddressUtils.cpp b/testApp/utils/testInetAddressUtils.cpp index 94176799..f296e4ec 100644 --- a/testApp/utils/testInetAddressUtils.cpp +++ b/testApp/utils/testInetAddressUtils.cpp @@ -39,25 +39,39 @@ void test_getSocketAddressList() testOk1(static_cast(3) == vec.size()); osiSockAddr addr; + osiSockAddr addr2; addr = vec.at(0); testOk1(AF_INET == addr.ia.sin_family); testOk1(htons(555) == addr.ia.sin_port); testOk1(htonl(0x7F000001) == addr.ia.sin_addr.s_addr); testOk1("127.0.0.1:555" == inetAddressToString(addr)); + testOk1(stringToInetAddress("127.0.0.1:555", addr2)); + testOk1(AF_INET == addr2.ia.sin_family); + testOk1(htons(555) == addr2.ia.sin_port); + testOk1(htonl(0x7F000001) == addr2.ia.sin_addr.s_addr); + testOk1(sockAddrAreIdentical(&addr2, &addr)); addr = vec.at(1); testOk1(AF_INET == addr.ia.sin_family); testOk1(htons(1234) == addr.ia.sin_port); testOk1(htonl(0x0A0A0C0B) == addr.ia.sin_addr.s_addr); testOk1("10.10.12.11:1234" == inetAddressToString(addr)); + testOk1(stringToInetAddress("10.10.12.11:1234", addr2)); + testOk1(AF_INET == addr2.ia.sin_family); + testOk1(htons(1234) == addr2.ia.sin_port); + testOk1(htonl(0x0A0A0C0B) == addr2.ia.sin_addr.s_addr); + testOk1(sockAddrAreIdentical(&addr2, &addr)); addr = vec.at(2); testOk1(AF_INET == addr.ia.sin_family); testOk1(htons(555) == addr.ia.sin_port); testOk1(htonl(0xC0A80304) == addr.ia.sin_addr.s_addr); testOk1("192.168.3.4:555" == inetAddressToString(addr)); - - + testOk1(stringToInetAddress("192.168.3.4:555", addr2)); + testOk1(AF_INET == addr2.ia.sin_family); + testOk1(htons(555) == addr2.ia.sin_port); + testOk1(htonl(0xC0A80304) == addr2.ia.sin_addr.s_addr); + testOk1(sockAddrAreIdentical(&addr2, &addr)); InetAddrVector vec1; @@ -359,7 +373,7 @@ void test_discoverInterfaces() MAIN(testInetAddressUtils) { - testPlan(65); + testPlan(80); testDiag("Tests for InetAddress utils"); test_getSocketAddressList(); From b3cb0d70f423b27cb11312538c57ba3c090542fd Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 20 Mar 2024 14:43:45 -0500 Subject: [PATCH 27/82] move utility functions to pvutils.cpp --- pvtoolsSrc/Makefile | 2 + pvtoolsSrc/pvlist.cpp | 494 ++--------------------------------------- pvtoolsSrc/pvutils.cpp | 432 +++++++++++++++++++++++++++++++++++ pvtoolsSrc/pvutils.h | 18 ++ 4 files changed, 470 insertions(+), 476 deletions(-) diff --git a/pvtoolsSrc/Makefile b/pvtoolsSrc/Makefile index 9b904e07..002a891e 100644 --- a/pvtoolsSrc/Makefile +++ b/pvtoolsSrc/Makefile @@ -4,6 +4,7 @@ include $(TOP)/configure/CONFIG USR_CPPFLAGS += -I$(TOP)/src/utils USR_CPPFLAGS += -I$(TOP)/src/remote +USR_CPPFLAGS += -I$(TOP)/src/remoteClient PROD_DEFAULT += pvget pvget_SRCS += pvget.cpp @@ -27,6 +28,7 @@ pvinfo_SRCS += pvutils.cpp PROD_DEFAULT += pvlist pvlist_SRCS += pvlist.cpp +pvlist_SRCS += pvutils.cpp PROD_LIBS += pvAccessCA pvAccess pvData ca Com diff --git a/pvtoolsSrc/pvlist.cpp b/pvtoolsSrc/pvlist.cpp index 28df5a6c..bb3ef719 100644 --- a/pvtoolsSrc/pvlist.cpp +++ b/pvtoolsSrc/pvlist.cpp @@ -20,15 +20,12 @@ #include #include -#include -#include -#include -#include #include #include #include -#include + +#include "pvutils.h" #if defined(_WIN32) && !defined(_MINGW) FILE *popen(const char *command, const char *mode) { @@ -46,437 +43,6 @@ using namespace epics::pvAccess; namespace { -/// Byte to hexchar mapping. -static const char lookup[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' -}; - -/// Get hex representation of byte. -string toHex(int8* ba, size_t len) { - string sb; - - for (size_t i = 0; i < len; i++) - { - int8 b = ba[i]; - - int upper = (b>>4)&0x0F; - sb += lookup[upper]; - - int lower = b&0x0F; - sb += lookup[lower]; - } - - return sb; -} - - -std::size_t readSize(ByteBuffer* buffer) { - int8 b = buffer->getByte(); - if(b==-1) - return -1; - else if(b==-2) { - int32 s = buffer->getInt(); - if(s<0) THROW_BASE_EXCEPTION("negative size"); - return s; - } - else - return (std::size_t)(b<0 ? b+256 : b); -} - -string deserializeString(ByteBuffer* buffer) { - - std::size_t size = /*SerializeHelper::*/readSize(buffer); - if(size!=(size_t)-1) // TODO null strings check, to be removed in the future - { - // entire string is in buffer, simply create a string out of it (copy) - std::size_t pos = buffer->getPosition(); - string str(buffer->getBuffer()+pos, size); - buffer->setPosition(pos+size); - return str; - } - else - return std::string(); -} - -struct ServerEntry { - string guid; - string protocol; - vector addresses; - int8 version; -}; - - -typedef map ServerMap; -static ServerMap serverMap; - -// return true if new server response is recevived -bool processSearchResponse(osiSockAddr const & responseFrom, ByteBuffer & receiveBuffer) -{ - // first byte is PVA_MAGIC - int8 magic = receiveBuffer.getByte(); - if(magic != PVA_MAGIC) - return false; - - // second byte version - int8 version = receiveBuffer.getByte(); - if(version == 0) { - // 0 -> 1 included incompatible changes - return false; - } - - // only data for UDP - int8 flags = receiveBuffer.getByte(); - if (flags < 0) - { - // 7-bit set - receiveBuffer.setEndianess(EPICS_ENDIAN_BIG); - } - else - { - receiveBuffer.setEndianess(EPICS_ENDIAN_LITTLE); - } - - // command ID and paylaod - int8 command = receiveBuffer.getByte(); - if (command != (int8)0x04) - return false; - - size_t payloadSize = receiveBuffer.getInt(); - if (payloadSize < (12+4+16+2)) - return false; - - - epics::pvAccess::ServerGUID guid; - receiveBuffer.get(guid.value, 0, sizeof(guid.value)); - - /*int32 searchSequenceId = */receiveBuffer.getInt(); - - osiSockAddr serverAddress; - memset(&serverAddress, 0, sizeof(serverAddress)); - serverAddress.ia.sin_family = AF_INET; - - // 128-bit IPv6 address - if (!decodeAsIPv6Address(&receiveBuffer, &serverAddress)) - return false; - - // accept given address if explicitly specified by sender - if (serverAddress.ia.sin_addr.s_addr == INADDR_ANY) - serverAddress.ia.sin_addr = responseFrom.ia.sin_addr; - - // NOTE: htons might be a macro (e.g. vxWorks) - int16 port = receiveBuffer.getShort(); - serverAddress.ia.sin_port = htons(port); - - string protocol = /*SerializeHelper::*/deserializeString(&receiveBuffer); - - /*bool found =*/ receiveBuffer.getByte(); // != 0; - - - string guidString = toHex((int8*)guid.value, sizeof(guid.value)); - - ServerMap::iterator iter = serverMap.find(guidString); - if (iter != serverMap.end()) - { - bool found = false; - vector& vec = iter->second.addresses; - for (vector::const_iterator ai = vec.begin(); - ai != vec.end(); - ai++) - if (sockAddrAreIdentical(&(*ai), &serverAddress)) - { - found = true; - break; - } - - if (!found) - { - vec.push_back(serverAddress); - return true; - } - else - return false; - } - else - { - ServerEntry serverEntry; - serverEntry.guid = guidString; - serverEntry.protocol = protocol; - serverEntry.addresses.push_back(serverAddress); - serverEntry.version = version; - - serverMap[guidString] = serverEntry; - - return true; - } -} - -bool discoverServers(double timeOut) -{ - osiSockAttach(); - - SOCKET socket = epicsSocketCreate(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (socket == INVALID_SOCKET) - { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Failed to create a socket: %s\n", errStr); - return false; - } - - // - // read config - // - - Configuration::shared_pointer configuration(new SystemConfigurationImpl()); - - string addressList = configuration->getPropertyAsString("EPICS_PVA_ADDR_LIST", ""); - bool autoAddressList = configuration->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", true); - int broadcastPort = configuration->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", PVA_BROADCAST_PORT); - - // quary broadcast addresses of all IFs - InetAddrVector broadcastAddresses; - { - IfaceNodeVector ifaces; - if(discoverInterfaces(ifaces, socket, 0)) { - fprintf(stderr, "Unable to populate interface list\n"); - return false; - } - - for(IfaceNodeVector::const_iterator it(ifaces.begin()), end(ifaces.end()); it!=end; ++it) - { - if(it->validBcast && it->bcast.sa.sa_family == AF_INET) { - osiSockAddr bcast = it->bcast; - bcast.ia.sin_port = htons(broadcastPort); - broadcastAddresses.push_back(bcast); - } - } - } - - // set broadcast address list - if (!addressList.empty()) - { - // if auto is true, add it to specified list - InetAddrVector* appendList = 0; - if (autoAddressList) - appendList = &broadcastAddresses; - - InetAddrVector list; - getSocketAddressList(list, addressList, broadcastPort, appendList); - if (!list.empty()) { - // delete old list and take ownership of a new one - broadcastAddresses = list; - } - } - - for (size_t i = 0; i < broadcastAddresses.size(); i++) - LOG(logLevelDebug, - "Broadcast address #%zu: %s.", i, inetAddressToString(broadcastAddresses[i]).c_str()); - - // --- - - int optval = 1; - int status = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)); - if (status) - { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Error setting SO_BROADCAST: %s\n", errStr); - epicsSocketDestroy (socket); - return false; - } - - osiSockAddr bindAddr; - memset(&bindAddr, 0, sizeof(bindAddr)); - bindAddr.ia.sin_family = AF_INET; - bindAddr.ia.sin_port = htons(0); - bindAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY); - - status = ::bind(socket, (sockaddr*)&(bindAddr.sa), sizeof(sockaddr)); - if (status) - { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Failed to bind: %s\n", errStr); - epicsSocketDestroy(socket); - return false; - } - - // set timeout -#ifdef _WIN32 - // ms - DWORD timeout = 250; -#else - struct timeval timeout; - memset(&timeout, 0, sizeof(struct timeval)); - timeout.tv_sec = 0; - timeout.tv_usec = 250000; -#endif - status = ::setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, - (char*)&timeout, sizeof(timeout)); - if (status) - { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Error setting SO_RCVTIMEO: %s\n", errStr); - return false; - } - - osiSockAddr responseAddress; - osiSocklen_t sockLen = sizeof(sockaddr); - // read the actual socket info - status = ::getsockname(socket, &responseAddress.sa, &sockLen); - if (status) { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Failed to get local socket address: %s.", errStr); - return false; - } - - char buffer[1024]; - ByteBuffer sendBuffer(buffer, sizeof(buffer)/sizeof(char)); - - sendBuffer.putByte(PVA_MAGIC); - sendBuffer.putByte(PVA_CLIENT_PROTOCOL_REVISION); - sendBuffer.putByte((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) ? 0x80 : 0x00); // data + 7-bit endianess - sendBuffer.putByte((int8_t)CMD_SEARCH); // search - sendBuffer.putInt(4+1+3+16+2+1+2); // "zero" payload - - sendBuffer.putInt(0); // sequenceId - sendBuffer.putByte((int8_t)0x81); // reply required // TODO unicast vs multicast; for now we mark ourselves as unicast - sendBuffer.putByte((int8_t)0); // reserved - sendBuffer.putShort((int16_t)0); // reserved - - // NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0 - encodeAsIPv6Address(&sendBuffer, &responseAddress); - sendBuffer.putShort((int16_t)ntohs(responseAddress.ia.sin_port)); - - sendBuffer.putByte((int8_t)0x00); // protocol count - sendBuffer.putShort((int16_t)0); // name count - - bool oneOK = false; - for (size_t i = 0; i < broadcastAddresses.size(); i++) - { - if(pvAccessIsLoggable(logLevelDebug)) { - char strBuffer[64]; - sockAddrToDottedIP(&broadcastAddresses[i].sa, strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "UDP Tx (%zu) -> %s", sendBuffer.getPosition(), strBuffer); - } - - status = ::sendto(socket, sendBuffer.getBuffer(), sendBuffer.getPosition(), 0, - &broadcastAddresses[i].sa, sizeof(sockaddr)); - if (status < 0) - { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Send error: %s\n", errStr); - } - else - oneOK = true; - } - - if (!oneOK) - return false; - - - char rxbuff[1024]; - ByteBuffer receiveBuffer(rxbuff, sizeof(rxbuff)/sizeof(char)); - - osiSockAddr fromAddress; - osiSocklen_t addrStructSize = sizeof(sockaddr); - - int sendCount = 0; - - while (true) - { - receiveBuffer.clear(); - - // receive packet from socket - int bytesRead = ::recvfrom(socket, (char*)receiveBuffer.getBuffer(), - receiveBuffer.getRemaining(), 0, - (sockaddr*)&fromAddress, &addrStructSize); - - if (bytesRead > 0) - { - if(pvAccessIsLoggable(logLevelDebug)) { - char strBuffer[64]; - sockAddrToDottedIP(&fromAddress.sa, strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "UDP Rx (%d) <- %s", bytesRead, strBuffer); - } - receiveBuffer.setPosition(bytesRead); - receiveBuffer.flip(); - - processSearchResponse(fromAddress, receiveBuffer); - - } - else - { - if (bytesRead == -1) - { - int socketError = SOCKERRNO; - - // interrupted or timeout - if (socketError == SOCK_EINTR || - socketError == EAGAIN || // no alias in libCom - // windows times out with this - socketError == SOCK_ETIMEDOUT || - socketError == SOCK_EWOULDBLOCK) - { - // OK - } - else if (socketError == SOCK_ECONNREFUSED || // avoid spurious ECONNREFUSED in Linux - socketError == SOCK_ECONNRESET) // or ECONNRESET in Windows - { - // OK - } - else - { - // unexpected error - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Socket recv error: %s\n", errStr); - break; - } - - } - - if (++sendCount < 3) - { - // TODO duplicate code - bool oneOK = false; - for (size_t i = 0; i < broadcastAddresses.size(); i++) - { - // send the packet - status = ::sendto(socket, sendBuffer.getBuffer(), sendBuffer.getPosition(), 0, - &broadcastAddresses[i].sa, sizeof(sockaddr)); - if (status < 0) - { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Send error: %s\n", errStr); - } - else - oneOK = true; - } - - if (!oneOK) - return false; - - } - else - break; - } - - } - - // TODO shutdown sockets? - // TODO this resouce is not released on failure - epicsSocketDestroy(socket); - - return true; -} - - #define DEFAULT_TIMEOUT 3.0 void usage (void) @@ -603,8 +169,9 @@ int main (int argc, char *argv[]) bool allOK = true; + ServerMap serverMap; if (noArgs || byGUIDSearch) - discoverServers(timeOut); + discoverServers(timeOut, serverMap); // just list all the discovered servers if (noArgs) @@ -665,52 +232,27 @@ int main (int argc, char *argv[]) } } - StructureConstPtr argstype(getFieldCreate()->createFieldBuilder() - ->setId("epics:nt/NTURI:1.0") - ->add("scheme", pvString) - ->add("path", pvString) - ->addNestedStructure("query") - ->add("op", pvString) - ->endNested() - ->createStructure()); + try + { + PVStructure::shared_pointer ret = getChannelInfo(serverAddress, printInfo ? "info" : "channels", timeOut); - PVStructure::shared_pointer args(getPVDataCreate()->createPVStructure(argstype)); + if(!printInfo) + { + PVStringArray::shared_pointer pvs(ret->getSubField("value")); - args->getSubFieldT("scheme")->put("pva"); - args->getSubFieldT("path")->put("server"); - args->getSubFieldT("query.op")->put(printInfo ? "info" : "channels"); + PVStringArray::const_svector val(pvs->view()); - if(debug) { - std::cerr<<"Query to "<(std::cout, "\n")); + } + else { + std::cout<getSubField("value")); - - PVStringArray::const_svector val(pvs->view()); - - std::copy(val.begin(), - val.end(), - std::ostream_iterator(std::cout, "\n")); - } - else { - std::cout< #include +#include +#include +#include +#include #include "pvutils.h" +using namespace epics::pvData; +using namespace epics::pvAccess; + double timeout = 5.0; bool debugFlag = false; @@ -124,5 +131,430 @@ void jarray(pvd::shared_vector& out, const char *inp) throw std::runtime_error("Unknown token"); } } +} + +// Get hex representation of byte. +std::string toHex(int8* ba, size_t len) +{ + // Byte to hexchar mapping. + static const char lookup[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + std::string sb; + + for (size_t i = 0; i < len; i++) + { + int8 b = ba[i]; + + int upper = (b>>4)&0x0F; + sb += lookup[upper]; + + int lower = b&0x0F; + sb += lookup[lower]; + } + + return sb; +} + +// Read size +std::size_t readSize(ByteBuffer* buffer) +{ + int8 b = buffer->getByte(); + if(b==-1) + return -1; + else if(b==-2) { + int32 s = buffer->getInt(); + if(s<0) THROW_BASE_EXCEPTION("negative size"); + return s; + } + else + return (std::size_t)(b<0 ? b+256 : b); +} + +// Deserialize string +std::string deserializeString(ByteBuffer* buffer) +{ + + std::size_t size = /*SerializeHelper::*/readSize(buffer); + if(size!=(size_t)-1) // TODO null strings check, to be removed in the future + { + // entire string is in buffer, simply create a string out of it (copy) + std::size_t pos = buffer->getPosition(); + std::string str(buffer->getBuffer()+pos, size); + buffer->setPosition(pos+size); + return str; + } + else + return std::string(); +} + +// Process search response +// Returns true if new server response is received +bool processSearchResponse(const osiSockAddr& responseFrom, ByteBuffer& receiveBuffer, ServerMap& serverMapByGuid) +{ + // first byte is PVA_MAGIC + int8 magic = receiveBuffer.getByte(); + if(magic != PVA_MAGIC) { + return false; + } + + // second byte version + int8 version = receiveBuffer.getByte(); + if(version == 0) { + // 0 -> 1 included incompatible changes + return false; + } + + // only data for UDP + int8 flags = receiveBuffer.getByte(); + if (flags < 0) { + // 7-bit set + receiveBuffer.setEndianess(EPICS_ENDIAN_BIG); + } + else { + receiveBuffer.setEndianess(EPICS_ENDIAN_LITTLE); + } + + // command ID and paylaod + int8 command = receiveBuffer.getByte(); + if (command != (int8)0x04) { + return false; + } + + size_t payloadSize = receiveBuffer.getInt(); + if (payloadSize < (12+4+16+2)) { + return false; + } + + ServerGUID guid; + receiveBuffer.get(guid.value, 0, sizeof(guid.value)); + + /*int32 searchSequenceId = */receiveBuffer.getInt(); + + osiSockAddr serverAddress; + memset(&serverAddress, 0, sizeof(serverAddress)); + serverAddress.ia.sin_family = AF_INET; + + // 128-bit IPv6 address + if (!decodeAsIPv6Address(&receiveBuffer, &serverAddress)) { + return false; + } + + // accept given address if explicitly specified by sender + if (serverAddress.ia.sin_addr.s_addr == INADDR_ANY) { + serverAddress.ia.sin_addr = responseFrom.ia.sin_addr; + } + + // NOTE: htons might be a macro (e.g. vxWorks) + int16 port = receiveBuffer.getShort(); + serverAddress.ia.sin_port = htons(port); + std::string protocol = /*SerializeHelper::*/deserializeString(&receiveBuffer); + + /*bool found =*/ receiveBuffer.getByte(); // != 0; + + + std::string guidString = toHex((int8*)guid.value, sizeof(guid.value)); + + ServerMap::iterator iter = serverMapByGuid.find(guidString); + if (iter != serverMapByGuid.end()) { + bool found = false; + std::vector& vec = iter->second.addresses; + for (std::vector::const_iterator ai = vec.begin(); ai != vec.end(); ai++) { + if (sockAddrAreIdentical(&(*ai), &serverAddress)) { + found = true; + break; + } + } + + if (!found) { + vec.push_back(serverAddress); + return true; + } + else { + return false; + } + } + else { + ServerEntry serverEntry; + serverEntry.guid = guidString; + serverEntry.protocol = protocol; + serverEntry.addresses.push_back(serverAddress); + serverEntry.version = version; + serverMapByGuid[guidString] = serverEntry; + return true; + } +} + +// Discover servers +bool discoverServers(double timeOut, ServerMap& serverMapByGuid) +{ + osiSockAttach(); + + SOCKET socket = epicsSocketCreate(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (socket == INVALID_SOCKET) { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Failed to create a socket: %s\n", errStr); + return false; + } + + // + // read config + // + + Configuration::shared_pointer configuration(new SystemConfigurationImpl()); + + std::string addressList = configuration->getPropertyAsString("EPICS_PVA_ADDR_LIST", ""); + bool autoAddressList = configuration->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", true); + int broadcastPort = configuration->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", PVA_BROADCAST_PORT); + + // query broadcast addresses of all IFs + InetAddrVector broadcastAddresses; + { + IfaceNodeVector ifaces; + if(discoverInterfaces(ifaces, socket, 0)) { + fprintf(stderr, "Unable to populate interface list\n"); + return false; + } + + for(IfaceNodeVector::const_iterator it(ifaces.begin()), end(ifaces.end()); it!=end; ++it) + { + if(it->validBcast && it->bcast.sa.sa_family == AF_INET) { + osiSockAddr bcast = it->bcast; + bcast.ia.sin_port = htons(broadcastPort); + broadcastAddresses.push_back(bcast); + } + } + } + + // set broadcast address list + if (!addressList.empty()) { + // if auto is true, add it to specified list + InetAddrVector* appendList = 0; + if (autoAddressList) + appendList = &broadcastAddresses; + + InetAddrVector list; + getSocketAddressList(list, addressList, broadcastPort, appendList); + if (!list.empty()) { + // delete old list and take ownership of a new one + broadcastAddresses = list; + } + } + + for (size_t i = 0; i < broadcastAddresses.size(); i++) { + LOG(logLevelDebug, "Broadcast address #%zu: %s.", i, inetAddressToString(broadcastAddresses[i]).c_str()); + } + + // --- + + int optval = 1; + int status = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)); + if (status) { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Error setting SO_BROADCAST: %s\n", errStr); + epicsSocketDestroy (socket); + return false; + } + + osiSockAddr bindAddr; + memset(&bindAddr, 0, sizeof(bindAddr)); + bindAddr.ia.sin_family = AF_INET; + bindAddr.ia.sin_port = htons(0); + bindAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY); + + status = ::bind(socket, (sockaddr*)&(bindAddr.sa), sizeof(sockaddr)); + if (status) { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Failed to bind: %s\n", errStr); + epicsSocketDestroy(socket); + return false; + } + + // set timeout +#ifdef _WIN32 + // ms + DWORD timeout = 250; +#else + struct timeval timeout; + memset(&timeout, 0, sizeof(struct timeval)); + timeout.tv_sec = 0; + timeout.tv_usec = 250000; +#endif + status = ::setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, + (char*)&timeout, sizeof(timeout)); + if (status) { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Error setting SO_RCVTIMEO: %s\n", errStr); + return false; + } + + osiSockAddr responseAddress; + osiSocklen_t sockLen = sizeof(sockaddr); + // read the actual socket info + status = ::getsockname(socket, &responseAddress.sa, &sockLen); + if (status) { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Failed to get local socket address: %s.", errStr); + return false; + } + + char buffer[1024]; + ByteBuffer sendBuffer(buffer, sizeof(buffer)/sizeof(char)); + + sendBuffer.putByte(PVA_MAGIC); + sendBuffer.putByte(PVA_CLIENT_PROTOCOL_REVISION); + sendBuffer.putByte((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) ? 0x80 : 0x00); // data + 7-bit endianess + sendBuffer.putByte((int8_t)CMD_SEARCH); // search + sendBuffer.putInt(4+1+3+16+2+1+2); // "zero" payload + + sendBuffer.putInt(0); // sequenceId + sendBuffer.putByte((int8_t)0x81); // reply required // TODO unicast vs multicast; for now we mark ourselves as unicast + sendBuffer.putByte((int8_t)0); // reserved + sendBuffer.putShort((int16_t)0); // reserved + + // NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0 + encodeAsIPv6Address(&sendBuffer, &responseAddress); + sendBuffer.putShort((int16_t)ntohs(responseAddress.ia.sin_port)); + + sendBuffer.putByte((int8_t)0x00); // protocol count + sendBuffer.putShort((int16_t)0); // name count + + bool oneOK = false; + for (size_t i = 0; i < broadcastAddresses.size(); i++) { + if(pvAccessIsLoggable(logLevelDebug)) { + char strBuffer[64]; + sockAddrToDottedIP(&broadcastAddresses[i].sa, strBuffer, sizeof(strBuffer)); + LOG(logLevelDebug, "UDP Tx (%zu) -> %s", sendBuffer.getPosition(), strBuffer); + } + + status = ::sendto(socket, sendBuffer.getBuffer(), sendBuffer.getPosition(), 0, + &broadcastAddresses[i].sa, sizeof(sockaddr)); + if (status < 0) { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Send error: %s\n", errStr); + } + else { + oneOK = true; + } + } + + if (!oneOK) { + return false; + } + + char rxbuff[1024]; + ByteBuffer receiveBuffer(rxbuff, sizeof(rxbuff)/sizeof(char)); + + osiSockAddr fromAddress; + osiSocklen_t addrStructSize = sizeof(sockaddr); + + int sendCount = 0; + + while (true) { + receiveBuffer.clear(); + + // receive packet from socket + int bytesRead = ::recvfrom(socket, (char*)receiveBuffer.getBuffer(), + receiveBuffer.getRemaining(), 0, + (sockaddr*)&fromAddress, &addrStructSize); + + if (bytesRead > 0) { + if(pvAccessIsLoggable(logLevelDebug)) { + char strBuffer[64]; + sockAddrToDottedIP(&fromAddress.sa, strBuffer, sizeof(strBuffer)); + LOG(logLevelDebug, "UDP Rx (%d) <- %s", bytesRead, strBuffer); + } + receiveBuffer.setPosition(bytesRead); + receiveBuffer.flip(); + + processSearchResponse(fromAddress, receiveBuffer, serverMapByGuid); + + } + else { + if (bytesRead == -1) { + int socketError = SOCKERRNO; + + // interrupted or timeout + if (socketError == SOCK_EINTR || + socketError == EAGAIN || // no alias in libCom + // windows times out with this + socketError == SOCK_ETIMEDOUT || + socketError == SOCK_EWOULDBLOCK) { + // OK + } + else if (socketError == SOCK_ECONNREFUSED || // avoid spurious ECONNREFUSED in Linux + socketError == SOCK_ECONNRESET) { // or ECONNRESET in Windows + // OK + } + else { + // unexpected error + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Socket recv error: %s\n", errStr); + break; + } + } + + if (++sendCount < 3) { + // TODO duplicate code + bool oneOK = false; + for (size_t i = 0; i < broadcastAddresses.size(); i++) { + // send the packet + status = ::sendto(socket, sendBuffer.getBuffer(), sendBuffer.getPosition(), 0, &broadcastAddresses[i].sa, sizeof(sockaddr)); + if (status < 0) { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Send error: %s\n", errStr); + } + else { + oneOK = true; + } + } + + if (!oneOK) { + return false; + } + } + else { + break; + } + } + } + + // TODO shutdown sockets? + // TODO this resouce is not released on failure + epicsSocketDestroy(socket); + return true; +} + +PVStructure::shared_pointer getChannelInfo(const std::string& serverAddress, const std::string& queryOp, double timeOut) +{ + LOG(logLevelDebug, "Querying server %s for %s", serverAddress.c_str(), queryOp.c_str()); + StructureConstPtr argstype(getFieldCreate()->createFieldBuilder() + ->setId("epics:nt/NTURI:1.0") + ->add("scheme", pvString) + ->add("path", pvString) + ->addNestedStructure("query") + ->add("op", pvString) + ->endNested() + ->createStructure()); + + PVStructure::shared_pointer args(getPVDataCreate()->createPVStructure(argstype)); + + args->getSubFieldT("scheme")->put("pva"); + args->getSubFieldT("path")->put("server"); + args->getSubFieldT("query.op")->put(queryOp); + + PVStructure::shared_pointer ret; + RPCClient rpc("server", createRequest("field()"), ChannelProvider::shared_pointer(), serverAddress); + return rpc.request(args, timeOut, true); } diff --git a/pvtoolsSrc/pvutils.h b/pvtoolsSrc/pvutils.h index 3eea5949..bd90bede 100644 --- a/pvtoolsSrc/pvutils.h +++ b/pvtoolsSrc/pvutils.h @@ -8,14 +8,18 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include +#include typedef epicsGuard Guard; typedef epicsGuardRelease UnGuard; @@ -72,7 +76,21 @@ struct Tracker { EPICS_NOT_COPYABLE(Tracker) }; +struct ServerEntry { + std::string guid; + std::string protocol; + std::vector addresses; + pvd::int8 version; +}; +typedef std::map ServerMap; + void jarray(pvd::shared_vector& out, const char *inp); +std::string toHex(pvd::int8* ba, size_t len); +std::size_t readSize(pvd::ByteBuffer* buffer); +std::string deserializeString(pvd::ByteBuffer* buffer); +bool processSearchResponse(const osiSockAddr& responseFrom, pvd::ByteBuffer& receiveBuffer, ServerMap& serverMapByGuid); +bool discoverServers(double timeOut, ServerMap& serverMapByGuid); +pvd::PVStructure::shared_pointer getChannelInfo(const std::string& serverAddress, const std::string& queryOp, double timeOut); #endif /* PVUTILS_H */ From d8a1dba03edcf6d004df9f8088cac89470220dbc Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 20 Mar 2024 14:59:59 -0500 Subject: [PATCH 28/82] add PVA name server utility --- pvtoolsSrc/Makefile | 5 + pvtoolsSrc/nameServer.cpp | 686 ++++++++++++++++++++++++++++++++++++++ pvtoolsSrc/nameServer.h | 171 ++++++++++ pvtoolsSrc/pvans.cpp | 179 ++++++++++ 4 files changed, 1041 insertions(+) create mode 100644 pvtoolsSrc/nameServer.cpp create mode 100644 pvtoolsSrc/nameServer.h create mode 100644 pvtoolsSrc/pvans.cpp diff --git a/pvtoolsSrc/Makefile b/pvtoolsSrc/Makefile index 002a891e..1d97eca3 100644 --- a/pvtoolsSrc/Makefile +++ b/pvtoolsSrc/Makefile @@ -30,6 +30,11 @@ PROD_DEFAULT += pvlist pvlist_SRCS += pvlist.cpp pvlist_SRCS += pvutils.cpp +PROD_DEFAULT += pvans +pvans_SRCS += pvans.cpp +pvans_SRCS += pvutils.cpp +pvans_SRCS += nameServer.cpp + PROD_LIBS += pvAccessCA pvAccess pvData ca Com PROD_SYS_LIBS_WIN32 += netapi32 ws2_32 diff --git a/pvtoolsSrc/nameServer.cpp b/pvtoolsSrc/nameServer.cpp new file mode 100644 index 00000000..fafaa8d3 --- /dev/null +++ b/pvtoolsSrc/nameServer.cpp @@ -0,0 +1,686 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvAccessCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + + +#include + +#include "nameServer.h" +#include "pvutils.h" + +using namespace std; +using namespace epics::pvData; +using std::tr1::dynamic_pointer_cast; +using std::tr1::static_pointer_cast; + +namespace epics { +namespace pvAccess { + +/* + * Name server channel find requester + */ + +NameServerChannelFindRequesterImpl::NameServerChannelFindRequesterImpl(const ServerContextImpl::shared_pointer& context_, const PeerInfo::const_shared_pointer& peer_, int32 expectedResponseCount_) + : mutex() + , nameServerGuid(context_->getGUID()) + , nameServerAddress(inetAddressToString(*(context_->getServerInetAddress()))) + , sendTo() + , channelWasFound(false) + , context(context_) + , peer(peer_) + , expectedResponseCount(expectedResponseCount_) + , responseCount(0) + , serverSearch(false) +{ +} + +NameServerChannelFindRequesterImpl::~NameServerChannelFindRequesterImpl() +{ +} + +void NameServerChannelFindRequesterImpl::clear() +{ + Lock lock(mutex); + channelWasFound = false; + responseCount = 0; + serverSearch = false; +} + +void NameServerChannelFindRequesterImpl::callback() +{ + channelFindResult(Status::Ok, ChannelFind::shared_pointer(), false); +} + +void NameServerChannelFindRequesterImpl::timerStopped() +{ +} + +void NameServerChannelFindRequesterImpl::set(std::string channelName, int32 searchSequenceId, int32 cid, const osiSockAddr& sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch) +{ + Lock lock(mutex); + this->channelName = channelName; + this->searchSequenceId = searchSequenceId; + this->cid = cid; + this->sendTo = sendTo; + this->transport = transport; + this->responseRequired = responseRequired; + this->serverSearch = serverSearch; +} + +void NameServerChannelFindRequesterImpl::channelFindResult(const Status& /*status*/, const ChannelFind::shared_pointer& channelFind, bool wasFound) +{ + Lock lock(mutex); + responseCount++; + if (responseCount > expectedResponseCount) { + if ((responseCount+1) == expectedResponseCount) { + LOG(logLevelDebug,"[NameServerChannelFindRequesterImpl::channelFindResult] More responses received than expected for channel '%s'!", channelName.c_str()); + } + return; + } + + if (wasFound && channelWasFound) { + LOG(logLevelDebug,"[NameServerChannelFindRequesterImpl::channelFindResult] Channel '%s' is hosted by different channel providers!", channelName.c_str()); + return; + } + + if (wasFound || (responseRequired && (responseCount == expectedResponseCount))) { + if (wasFound && expectedResponseCount > 1) { + Lock L(context->_mutex); + context->s_channelNameToProvider[channelName] = channelFind->getChannelProvider(); + } + channelWasFound = wasFound; + if (channelFind && ! channelName.empty()) { + ChannelProvider::shared_pointer channelProvider = channelFind->getChannelProvider(); + NameServerChannelProvider::shared_pointer nsChannelProvider = dynamic_pointer_cast(channelProvider); + if (nsChannelProvider) { + channelServerAddress = nsChannelProvider->getChannelServerAddress(channelName); + } + } + if (transport && transport->getType() == PVA_TCP_PROTOCOL) { + TransportSender::shared_pointer thisSender = shared_from_this(); + transport->enqueueSendRequest(thisSender); + } + else { + BlockingUDPTransport::shared_pointer bt = context->getBroadcastTransport(); + if (bt) { + TransportSender::shared_pointer thisSender = shared_from_this(); + bt->enqueueSendRequest(thisSender); + } + } + } +} + +std::tr1::shared_ptr NameServerChannelFindRequesterImpl::getPeerInfo() +{ + return peer; +} + +void NameServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) +{ + std::string sendToStr = inetAddressToString(sendTo); + LOG(logLevelDebug, "Name server search response will be sent to %s", sendToStr.c_str()); + control->startMessage(CMD_SEARCH_RESPONSE, 12+4+16+2); + + Lock lock(mutex); + buffer->put(nameServerGuid.value, 0, sizeof(nameServerGuid.value)); + buffer->putInt(searchSequenceId); + + int nameServerPort = context->getServerPort(); + osiSockAddr channelServerAddr; + channelServerAddr.ia.sin_port = htons(nameServerPort); + if (stringToInetAddress(channelServerAddress, channelServerAddr)) { + LOG(logLevelDebug, "Encoding channel server address %s into channel search response", channelServerAddress.c_str()); + } + else { + stringToInetAddress(nameServerAddress, channelServerAddr); + LOG(logLevelDebug, "Encoding name server address %s into channel search response", nameServerAddress.c_str()); + } + encodeAsIPv6Address(buffer, &channelServerAddr); + int16 port = ntohs(channelServerAddr.ia.sin_port); + buffer->putShort(port); + + SerializeHelper::serializeString(ServerSearchHandler::SUPPORTED_PROTOCOL, buffer, control); + + control->ensureBuffer(1); + buffer->putByte(channelWasFound ? (int8)1 : (int8)0); + + if (!serverSearch) { + // For now we do not gather search responses + buffer->putShort((int16)1); + buffer->putInt(cid); + } + else { + buffer->putShort((int16)0); + } + + control->setRecipient(sendTo); +} + +/* + * Name server search handler + */ +const std::string NameServerSearchHandler::SUPPORTED_PROTOCOL = PVA_TCP_PROTOCOL; + +NameServerSearchHandler::NameServerSearchHandler(const ServerContextImpl::shared_pointer& context) + : AbstractServerResponseHandler(context, "Search request") +{ + // initialize random seed + srand(time(NULL)); +} + +NameServerSearchHandler::~NameServerSearchHandler() +{ +} + +void NameServerSearchHandler::handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, int8 version, int8 command, size_t payloadSize, ByteBuffer* payloadBuffer) +{ + std::string responseFromStr = inetAddressToString(*responseFrom); + LOG(logLevelDebug, "Name server search handler is handling request from %s", responseFromStr.c_str()); + AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); + transport->ensureData(4+1+3+16+2); + + size_t startPosition = payloadBuffer->getPosition(); + + const int32 searchSequenceId = payloadBuffer->getInt(); + const int8 qosCode = payloadBuffer->getByte(); + + // reserved part + payloadBuffer->getByte(); + payloadBuffer->getShort(); + + osiSockAddr responseAddress; + memset(&responseAddress, 0, sizeof(responseAddress)); + responseAddress.ia.sin_family = AF_INET; + + // 128-bit IPv6 address + if (!decodeAsIPv6Address(payloadBuffer, &responseAddress)) { + return; + } + + // accept given address if explicitly specified by sender + if (responseAddress.ia.sin_addr.s_addr == INADDR_ANY) { + responseAddress.ia.sin_addr = responseFrom->ia.sin_addr; + } + + int16 port = payloadBuffer->getShort(); + if (port) { + responseAddress.ia.sin_port = htons(port); + } + else { + LOG(logLevelDebug, "Server search handler is reusing connection port %d", ntohs(responseFrom->ia.sin_port)); + responseAddress.ia.sin_port = responseFrom->ia.sin_port; + } + + size_t protocolsCount = SerializeHelper::readSize(payloadBuffer, transport.get()); + bool allowed = (protocolsCount == 0); + for (size_t i = 0; i < protocolsCount; i++) { + string protocol = SerializeHelper::deserializeString(payloadBuffer, transport.get()); + if (SUPPORTED_PROTOCOL == protocol) { + allowed = true; + } + } + + transport->ensureData(2); + const int32 count = payloadBuffer->getShort() & 0xFFFF; + const bool responseRequired = (QOS_REPLY_REQUIRED & qosCode) != 0; + + // + // locally broadcast if unicast (qosCode & QOS_GET_PUT == QOS_GET_PUT) via UDP + // + if ((qosCode & QOS_GET_PUT) == QOS_GET_PUT) { + BlockingUDPTransport::shared_pointer bt = dynamic_pointer_cast(transport); + if (bt && bt->hasLocalMulticastAddress()) { + // RECEIVE_BUFFER_PRE_RESERVE allows to pre-fix message + size_t newStartPos = (startPosition-PVA_MESSAGE_HEADER_SIZE)-PVA_MESSAGE_HEADER_SIZE-16; + payloadBuffer->setPosition(newStartPos); + + // copy part of a header, and add: command, payloadSize, NIF address + payloadBuffer->put(payloadBuffer->getBuffer(), startPosition-PVA_MESSAGE_HEADER_SIZE, PVA_MESSAGE_HEADER_SIZE-5); + payloadBuffer->putByte(CMD_ORIGIN_TAG); + payloadBuffer->putInt(16); + // encode this socket bind address + encodeAsIPv6Address(payloadBuffer, bt->getBindAddress()); + + // clear unicast flag + payloadBuffer->put(startPosition+4, (int8)(qosCode & ~0x80)); + + // update response address + payloadBuffer->setPosition(startPosition+8); + encodeAsIPv6Address(payloadBuffer, &responseAddress); + + // set to end of a message + payloadBuffer->setPosition(payloadBuffer->getLimit()); + + bt->send(payloadBuffer->getBuffer()+newStartPos, payloadBuffer->getPosition()-newStartPos, bt->getLocalMulticastAddress()); + return; + } + } + + PeerInfo::shared_pointer info; + if(allowed) { + info.reset(new PeerInfo); + info->transport = "pva"; + info->peer = responseFromStr; + info->transportVersion = version; + } + + if (count > 0) { + // regular name search + for (int32 i = 0; i < count; i++) { + transport->ensureData(4); + const int32 cid = payloadBuffer->getInt(); + const string name = SerializeHelper::deserializeString(payloadBuffer, transport.get()); + LOG(logLevelDebug, "Search for channel %s, cid %d", name.c_str(), cid); + if (allowed) { + const std::vector& providers = _context->getChannelProviders(); + int providerCount = providers.size(); + std::tr1::shared_ptr channelFindRequester(new NameServerChannelFindRequesterImpl(_context, info, providerCount)); + channelFindRequester->set(name, searchSequenceId, cid, responseAddress, transport, responseRequired, false); + + for (int i = 0; i < providerCount; i++) { + providers[i]->channelFind(name, channelFindRequester); + } + } + } + } + else { + // Server discovery ping by pvlist + if (allowed) + { + // ~random hold-off to reduce impact of all servers responding. + // in [0.05, 0.15] + double delay = double(rand())/RAND_MAX; // [0, 1] + delay = delay*0.1 + 0.05; + std::tr1::shared_ptr channelFindRequester(new NameServerChannelFindRequesterImpl(_context, info, 1)); + channelFindRequester->set("", searchSequenceId, 0, responseAddress, transport, true, true); + + TimerCallback::shared_pointer tc = channelFindRequester; + _context->getTimer()->scheduleAfterDelay(tc, delay); + } + } +} + +/* + * Name server search response handler + */ +NameServerSearchResponseHandler::NameServerSearchResponseHandler(const ServerContextImpl::shared_pointer& context) + : ResponseHandler(context.get(), "NameServerSearchResponseHandler") + , badResponseHandler(context) + , beaconHandler(context, "Beacon") + , validationHandler(context) + , echoHandler(context) + , searchHandler(context) + , authnzHandler(context.get()) + , createChannelHandler(context) + , destroyChannelHandler(context) + , rpcHandler(context) + , handlerTable(CMD_CANCEL_REQUEST+1, &badResponseHandler) +{ + handlerTable[CMD_BEACON] = &badResponseHandler; /* 0 */ + handlerTable[CMD_CONNECTION_VALIDATION] = &validationHandler; /* 1 */ + handlerTable[CMD_ECHO] = &echoHandler; /* 2 */ + handlerTable[CMD_SEARCH] = &searchHandler; /* 3 */ + handlerTable[CMD_SEARCH_RESPONSE] = &badResponseHandler; + handlerTable[CMD_AUTHNZ] = &authnzHandler; /* 5 */ + handlerTable[CMD_ACL_CHANGE] = &badResponseHandler; /* 6 - access right change */ + handlerTable[CMD_CREATE_CHANNEL] = &createChannelHandler; /* 7 */ + handlerTable[CMD_DESTROY_CHANNEL] = &destroyChannelHandler; /* 8 */ + handlerTable[CMD_CONNECTION_VALIDATED] = &badResponseHandler; /* 9 */ + + handlerTable[CMD_GET] = &badResponseHandler; /* 10 - get response */ + handlerTable[CMD_PUT] = &badResponseHandler; /* 11 - put response */ + handlerTable[CMD_PUT_GET] = &badResponseHandler; /* 12 - put-get response */ + handlerTable[CMD_MONITOR] = &badResponseHandler; /* 13 - monitor response */ + handlerTable[CMD_ARRAY] = &badResponseHandler; /* 14 - array response */ + handlerTable[CMD_DESTROY_REQUEST] = &badResponseHandler; /* 15 - destroy request */ + handlerTable[CMD_PROCESS] = &badResponseHandler; /* 16 - process response */ + handlerTable[CMD_GET_FIELD] = &badResponseHandler; /* 17 - get field response */ + handlerTable[CMD_MESSAGE] = &badResponseHandler; /* 18 - message to Requester */ + handlerTable[CMD_MULTIPLE_DATA] = &badResponseHandler; /* 19 - grouped monitors */ + + handlerTable[CMD_RPC] = &rpcHandler; /* 20 - RPC response */ + handlerTable[CMD_CANCEL_REQUEST] = &badResponseHandler; /* 21 - cancel request */ +} + +NameServerSearchResponseHandler::~NameServerSearchResponseHandler() +{ +} + +void NameServerSearchResponseHandler::handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, int8 version, int8 command, size_t payloadSize, ByteBuffer* payloadBuffer) +{ + if(command<0||command>=(int8)handlerTable.size()) + { + LOG(logLevelError, "Invalid (or unsupported) command: %x.", (0xFF&command)); + if(IS_LOGGABLE(logLevelError)) { + std::ios::fmtflags initialflags = std::cerr.flags(); + std::cerr << "Invalid (or unsupported) command: " + << std::hex << (int)(0xFF&command) << "\n" + << HexDump(*payloadBuffer, payloadSize).limit(256u); + std::cerr.flags(initialflags); + } + return; + } + // delegate + handlerTable[command]->handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); +} + +/* + * Name server channel find + */ +NameServerChannelFind::NameServerChannelFind(ChannelProvider::shared_pointer& provider) + : channelProvider(provider) +{ +} + +NameServerChannelFind::~NameServerChannelFind() +{ +} + +void NameServerChannelFind::destroy() +{ +} + +ChannelProvider::shared_pointer NameServerChannelFind::getChannelProvider() +{ + return channelProvider.lock(); +}; + +void NameServerChannelFind::cancel() +{ + throw std::runtime_error("Not supported"); +} + +/* + * Name server channel provider class + */ + +const std::string NameServerChannelProvider::PROVIDER_NAME("remote"); + +NameServerChannelProvider::NameServerChannelProvider() + : nsChannelFind() +{ +} + +NameServerChannelProvider::~NameServerChannelProvider() +{ +} + +void NameServerChannelProvider::initialize() +{ + ChannelProvider::shared_pointer thisChannelProvider = shared_from_this(); + nsChannelFind.reset(new NameServerChannelFind(thisChannelProvider)); +} + +void NameServerChannelProvider::setChannelEntryExpirationTime(double expirationTime) +{ + this->channelEntryExpirationTime = expirationTime; +} + +std::string NameServerChannelProvider::NameServerChannelProvider::getProviderName() +{ + return PROVIDER_NAME; +} + +void NameServerChannelProvider::destroy() +{ +} + +ChannelFind::shared_pointer NameServerChannelProvider::channelFind(const std::string& channelName, const ChannelFindRequester::shared_pointer& channelFindRequester) +{ + bool exists = false; + epicsTimeStamp now; + epicsTimeGetCurrent(&now); + { + Lock lock(channelMapMutex); + ChannelMap::iterator it = channelMap.find(channelName); + if (it != channelMap.end()) { + exists = true; + // Check expiration time if it is configured + if (channelEntryExpirationTime > 0) { + ChannelEntry channelEntry = it->second; + epicsTimeStamp channelUpdateTime = channelEntry.updateTime; + double timeSinceUpdate = epicsTimeDiffInSeconds(&now, &channelUpdateTime); + if (timeSinceUpdate > channelEntryExpirationTime) { + LOG(logLevelDebug, "Channel %s was last updated %.2f seconds ago, channel entry has expired", channelName.c_str(), timeSinceUpdate); + channelMap.erase(it); + exists = false; + } + } + } + } + channelFindRequester->channelFindResult(epics::pvData::Status::Ok, nsChannelFind, exists); + return nsChannelFind; +} + +ChannelFind::shared_pointer NameServerChannelProvider::channelList(const ChannelListRequester::shared_pointer& channelListRequester) +{ + if (!channelListRequester.get()) { + throw std::runtime_error("Null requester"); + } + + epics::pvData::PVStringArray::svector channelNames; + { + Lock lock(channelMapMutex); + for (ChannelMap::const_iterator it = channelMap.begin(); it != channelMap.end(); it++) { + std::string channelName = it->first; + channelNames.push_back(channelName); + } + } + channelListRequester->channelListResult(epics::pvData::Status::Ok, nsChannelFind, freeze(channelNames), true); + return nsChannelFind; +} + +Channel::shared_pointer NameServerChannelProvider::createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short priority) +{ + // SVDBG + return createChannel(channelName, channelRequester, priority, "local"); +} + +Channel::shared_pointer NameServerChannelProvider::createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short /*priority*/, const std::string& address) +{ + Channel::shared_pointer nullPtr; + epics::pvData::Status errorStatus(epics::pvData::Status::STATUSTYPE_ERROR, "Not supported"); + channelRequester->channelCreated(errorStatus, nullPtr); + return nullPtr; +} + +void NameServerChannelProvider::updateChannelMap(const ChannelMap& updatedChannelMap) +{ + Lock lock(channelMapMutex); + for (ChannelMap::const_iterator it = updatedChannelMap.begin(); it != updatedChannelMap.end(); it++) { + std::string channelName = it->first; + ChannelEntry channelEntry = it->second; + channelMap[channelName] = channelEntry; + } + LOG(logLevelDebug, "Name server channel provider updated %ld channels", updatedChannelMap.size()); +} + +std::string NameServerChannelProvider::getChannelServerAddress(const std::string& channelName) +{ + std::string serverAddress; + Lock lock(channelMapMutex); + ChannelMap::const_iterator it = channelMap.find(channelName); + if (it != channelMap.end()) { + serverAddress = it->second.serverAddress; + } + return serverAddress; +} + +/* + * Name server class + */ +NameServer::NameServer(const epics::pvAccess::Configuration::shared_pointer& conf) + : channelProvider(new NameServerChannelProvider) +{ + channelProvider->initialize(); + ServerContext::Config serverConfig = ServerContext::Config().config(conf).provider(channelProvider); + context = ServerContextImpl::create(serverConfig); + ResponseHandler::shared_pointer searchResponseHandler(new NameServerSearchResponseHandler(context)); + context->initialize(searchResponseHandler, searchResponseHandler); +} + +NameServer::~NameServer() +{ + shutdown(); + context.reset(); +} + +void NameServer::setPollPeriod(double pollPeriod) +{ + LOG(logLevelDebug, "Setting server poll period to %.2f seconds", pollPeriod); + this->pollPeriod = pollPeriod; +} +void NameServer::setPvaTimeout(double timeout) +{ + LOG(logLevelDebug, "Setting PVA timeout to %.2f seconds", timeout); + this->timeout = timeout; +} +void NameServer::setAutoDiscovery(bool autoDiscovery) +{ + this->autoDiscovery = autoDiscovery; +} +void NameServer::setServerAddresses(const std::string& serverAddresses) +{ + this->serverAddresses = serverAddresses; +} + +void NameServer::setChannelEntryExpirationTime(double expirationTime) +{ + LOG(logLevelDebug, "Setting channel entry expiration time to %.2f seconds", expirationTime); + this->channelProvider->setChannelEntryExpirationTime(expirationTime); +} + +void NameServer::run(double runtime) +{ + epicsTimeStamp startTime; + epicsTimeGetCurrent(&startTime); + while(true) { + ServerAddressList serverAddressList; + addServersFromAddresses(serverAddressList); + discoverServers(serverAddressList); + ChannelMap channelMap; + discoverChannels(serverAddressList, channelMap); + channelProvider->updateChannelMap(channelMap); + epicsTimeStamp now; + epicsTimeGetCurrent(&now); + double deltaT = epicsTimeDiffInSeconds(&now, &startTime); + if (runtime > 0 && deltaT > runtime) { + break; + } + double remainingTime = runtime-deltaT; + double waitTime = pollPeriod; + if (waitTime > remainingTime) { + waitTime = remainingTime; + } + epicsThreadSleep(waitTime); + } +} + +bool NameServer::addUniqueServerToList(const std::string& serverAddress, ServerAddressList& serverAddressList) +{ + std::list::const_iterator it = std::find(serverAddressList.begin(), serverAddressList.end(), serverAddress); + if (it == serverAddressList.end()) { + LOG(logLevelDebug, "Adding server address %s", serverAddress.c_str()); + serverAddressList.push_back(serverAddress); + return true; + } + LOG(logLevelDebug, "Ignoring duplicate server address %s", serverAddress.c_str()); + return false; +} + +void NameServer::addServersFromAddresses(ServerAddressList& serverAddressList) +{ + LOG(logLevelDebug, "Adding pre-configured server addresses"); + std::string::size_type pos; + std::string addresses = serverAddresses; + while ((pos = addresses.find(',')) != std::string::npos) { + addresses = addresses.replace(pos, 1, " "); + } + InetAddrVector inetAddrVector; + getSocketAddressList(inetAddrVector, addresses, context->getServerPort()); + int nAddedServers = 0; + for (unsigned int i = 0; i < inetAddrVector.size(); i++) { + std::string serverAddress = inetAddressToString(inetAddrVector[i]); + if (addUniqueServerToList(serverAddress, serverAddressList)) { + nAddedServers++; + } + } + LOG(logLevelDebug, "Added %d pre-configured server addresses", nAddedServers); +} + +void NameServer::discoverServers(ServerAddressList& serverAddressList) +{ + if (!autoDiscovery) { + LOG(logLevelDebug, "Skipping server discovery"); + return; + } + + LOG(logLevelDebug, "Starting server discovery"); + ServerGUID guid = context->getGUID(); + std::string nsGuid = ::toHex((int8*)guid.value, sizeof(guid.value)); + ServerMap serverMap; + ::discoverServers(timeout, serverMap); + + int nDiscoveredServers = 0; + for (ServerMap::const_iterator it = serverMap.begin(); it != serverMap.end(); it++) { + const ServerEntry& entry = it->second; + if (nsGuid == entry.guid) { + LOG(logLevelDebug, "Ignoring our own server GUID 0x%s", entry.guid.c_str()); + continue; + } + size_t count = entry.addresses.size(); + std::string addresses = " "; + for (size_t i = 0; i < count; i++) { + addresses = addresses + inetAddressToString(entry.addresses[i]) + " "; + } + LOG(logLevelDebug, "Found server GUID 0x%s version %d: %s@[%s]", entry.guid.c_str(), (int)entry.version, entry.protocol.c_str(), addresses.c_str()); + if (count > 0) { + std::string serverAddress = inetAddressToString(entry.addresses[0]); + if (addUniqueServerToList(serverAddress, serverAddressList)) { + nDiscoveredServers++; + } + } + } + LOG(logLevelDebug, "Discovered %d servers", nDiscoveredServers); +} + +void NameServer::discoverServerChannels(const std::string& serverAddress, ChannelMap& channelMap) +{ + LOG(logLevelDebug, "Discovering channels for server %s", serverAddress.c_str()); + try { + PVStructure::shared_pointer ret = getChannelInfo(serverAddress, "channels", timeout); + PVStringArray::shared_pointer pvs(ret->getSubField("value")); + PVStringArray::const_svector val(pvs->view()); + epicsTimeStamp now; + epicsTimeGetCurrent(&now); + for (unsigned int i = 0; i < val.size(); i++) { + ChannelEntry channelEntry; + channelEntry.channelName = val[i]; + channelEntry.serverAddress = serverAddress; + channelEntry.updateTime = now; + channelMap[val[i]] = channelEntry; + } + LOG(logLevelDebug, "Discovered %ld channels for server %s", val.size(), serverAddress.c_str()); + } + catch(std::exception& e) { + LOG(logLevelError, "Error retrieving channels for server %s: %s", serverAddress.c_str(), e.what()); + } +} + +void NameServer::discoverChannels(ServerAddressList& serverAddressList, ChannelMap& channelMap) +{ + LOG(logLevelDebug, "Discovering channels for %ld servers", serverAddressList.size()); + for (ServerAddressList::const_iterator it = serverAddressList.begin(); it != serverAddressList.end(); it++) { + std::string serverAddress = *it; + discoverServerChannels(serverAddress, channelMap); + } +} + +void NameServer::shutdown() +{ + context->shutdown(); +} + +}} diff --git a/pvtoolsSrc/nameServer.h b/pvtoolsSrc/nameServer.h new file mode 100644 index 00000000..3c8f46df --- /dev/null +++ b/pvtoolsSrc/nameServer.h @@ -0,0 +1,171 @@ +#ifndef NAME_SERVER_H +#define NAME_SERVER_H + +#include +#include +#include +#include +#include "pvutils.h" + +namespace epics { namespace pvAccess { + +/* + * Name server channel entry + */ +struct ChannelEntry { + std::string channelName; + std::string serverAddress; + epicsTimeStamp updateTime; +}; +typedef std::map ChannelMap; +typedef std::list ServerAddressList; + +class NameServerChannelFindRequesterImpl + : public ChannelFindRequester + , public TransportSender + , public epics::pvData::TimerCallback + , public std::tr1::enable_shared_from_this +{ +public: + NameServerChannelFindRequesterImpl(const ServerContextImpl::shared_pointer& context, const PeerInfo::const_shared_pointer& peerInfo, epics::pvData::int32 expectedResponseCount); + virtual ~NameServerChannelFindRequesterImpl(); + void clear(); + void set(std::string channelName, epics::pvData::int32 searchSequenceId, epics::pvData::int32 cid, osiSockAddr const & sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch); + virtual void channelFindResult(const epics::pvData::Status& status, const ChannelFind::shared_pointer& channelFind, bool wasFound) OVERRIDE FINAL; + virtual std::tr1::shared_ptr getPeerInfo() OVERRIDE FINAL; + virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) OVERRIDE FINAL; + virtual void callback() OVERRIDE FINAL; + virtual void timerStopped() OVERRIDE FINAL; + +private: + mutable epics::pvData::Mutex mutex; + ServerGUID nameServerGuid; + std::string nameServerAddress; + std::string channelName; + std::string channelServerAddress; + epics::pvData::int32 searchSequenceId; + epics::pvData::int32 cid; + osiSockAddr sendTo; + Transport::shared_pointer transport; + bool responseRequired; + bool channelWasFound; + const ServerContextImpl::shared_pointer context; + const PeerInfo::const_shared_pointer peer; + const epics::pvData::int32 expectedResponseCount; + epics::pvData::int32 responseCount; + bool serverSearch; +}; + +class NameServerSearchHandler + : public AbstractServerResponseHandler +{ +public: + static const std::string SUPPORTED_PROTOCOL; + + NameServerSearchHandler(const ServerContextImpl::shared_pointer& context); + virtual ~NameServerSearchHandler(); + + virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData::int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE FINAL; +}; + +class NameServerSearchResponseHandler + : public ResponseHandler +{ +public: + NameServerSearchResponseHandler(const ServerContextImpl::shared_pointer& context); + virtual ~NameServerSearchResponseHandler(); + virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData::int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE FINAL; + +private: + ServerBadResponse badResponseHandler; + ServerNoopResponse beaconHandler; + ServerConnectionValidationHandler validationHandler; + ServerEchoHandler echoHandler; + NameServerSearchHandler searchHandler; + AuthNZHandler authnzHandler; + ServerCreateChannelHandler createChannelHandler; + ServerDestroyChannelHandler destroyChannelHandler; + ServerRPCHandler rpcHandler; + + // Table of response handlers for each command ID. + std::vector handlerTable; + +}; + +class NameServerChannelFind + : public ChannelFind +{ +public: + POINTER_DEFINITIONS(NameServerChannelFind); + + NameServerChannelFind(ChannelProvider::shared_pointer& provider); + virtual ~NameServerChannelFind(); + virtual void destroy(); + virtual ChannelProvider::shared_pointer getChannelProvider(); + virtual void cancel(); + +private: + ChannelProvider::weak_pointer channelProvider; +}; + +class NameServerChannelProvider + : public ChannelProvider + , public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(NameServerChannelProvider); + static const std::string PROVIDER_NAME; + + NameServerChannelProvider(); + virtual ~NameServerChannelProvider(); + void initialize(); + virtual std::string getProviderName(); + virtual void destroy(); + virtual ChannelFind::shared_pointer channelFind(const std::string& channelName, const ChannelFindRequester::shared_pointer& channelFindRequester); + virtual ChannelFind::shared_pointer channelList(const ChannelListRequester::shared_pointer& channelListRequester); + virtual Channel::shared_pointer createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short priority); + virtual Channel::shared_pointer createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short /*priority*/, const std::string& address); + void updateChannelMap(const ChannelMap& updatedChannelMap); + std::string getChannelServerAddress(const std::string& channelName); + void setChannelEntryExpirationTime(double expirationTime); + +private: + ChannelFind::shared_pointer nsChannelFind; + mutable epics::pvData::Mutex channelMapMutex; + ChannelMap channelMap; + double channelEntryExpirationTime; +}; + +class NameServer + : public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(NameServer); + NameServer(const epics::pvAccess::Configuration::shared_pointer& conf); + virtual ~NameServer(); + void setPollPeriod(double pollPeriod); + void setPvaTimeout(double timeout); + void setAutoDiscovery(bool autoDiscovery); + void setServerAddresses(const std::string& serverAddresses); + void setChannelEntryExpirationTime(double expirationTime); + void run(double runtime); + +private: + ServerContextImpl::shared_pointer context; + NameServerChannelProvider::shared_pointer channelProvider; + double pollPeriod; + double timeout; + bool autoDiscovery; + std::string serverAddresses; + + bool addUniqueServerToList(const std::string& serverAddress, ServerAddressList& serverAddressList); + void addServersFromAddresses(ServerAddressList& serverAddressList); + void discoverServers(ServerAddressList& serverAddressList); + void discoverServerChannels(const std::string& serverAddress, ChannelMap& channelMap); + void discoverChannels(ServerAddressList& serverAddressList, ChannelMap& channelMap); + void shutdown(); +}; + +}} + +#endif // NAME_SERVER_H diff --git a/pvtoolsSrc/pvans.cpp b/pvtoolsSrc/pvans.cpp new file mode 100644 index 00000000..078cced6 --- /dev/null +++ b/pvtoolsSrc/pvans.cpp @@ -0,0 +1,179 @@ +/* + * Copyright information and license terms for this software can be + * found in the file LICENSE that is included with the distribution + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "nameServer.h" +#include "pvutils.h" + +using namespace std; + +using namespace epics::pvData; +using namespace epics::pvAccess; + +namespace { + +#define DEFAULT_PVA_TIMEOUT 3.0 +#define DEFAULT_POLL_PERIOD 900.0 +#define DEFAULT_CHANNEL_EXPIRATION_TIME 2*DEFAULT_POLL_PERIOD + +void usage (void) { + fprintf (stderr, + "\nPVA Name Server\n" + "\nUsage: pvans [options]...\n\n" + "\noptions:\n" + " -h|-H\t\t\t:\tHelp: Print this message\n" + " -V\t\t\t:\tPrint version and exit\n" + " -f \t:\tInput file containing list of PVA server addresses in the form :\n" + " -s ,,...\t:\tComma-separated list of PVA server addresses in the form :\n" + " -a\t\t\t:\tAuto mode, discover severs available on the network\n" + " -p \t:\tServer poll period in seconds (default: %.2f [s])\n" + " -w \t:\tServer wait time in seconds (default: %.2f [s])\n" + " -e \t:\tChannel entry expiration time in seconds (default: %.2f [s])\n" + " -d\t\t\t:\tEnable debug output\n" + "\nDifferent inputs for PVA server address will be combined." + "\nChannel expiration time <= 0 indicates that channel entries never expire.\n\n" + , DEFAULT_POLL_PERIOD, DEFAULT_PVA_TIMEOUT, DEFAULT_CHANNEL_EXPIRATION_TIME); +} + +std::string addServerAddressesFromFile(const std::string& inputFile, const std::string& existingAddresses = "") +{ + std::string serverAddresses = existingAddresses; + if (inputFile.empty()) { + return serverAddresses; + } + std::ifstream ifs(inputFile); + std::string line; + while (std::getline(ifs, line)) { + serverAddresses = serverAddresses + " " + line; + } + return serverAddresses; +} + +} //namespace + +int main(int argc, char *argv[]) +{ + int opt; /* getopt() current option */ + bool debug = false; + bool autoDiscovery = false; + double timeout = DEFAULT_PVA_TIMEOUT; + double pollPeriod = DEFAULT_POLL_PERIOD; + double channelExpirationTime = DEFAULT_CHANNEL_EXPIRATION_TIME; + std::string inputFile; + std::string serverAddresses; + + while ((opt = getopt(argc, argv, ":hHVw:e:p:das:f:")) != -1) { + switch (opt) { + case 'h': /* Print usage */ + case 'H': /* Print usage */ + usage(); + return 0; + case 'V': { /* Print version */ + fprintf(stdout, "pvAccess %u.%u.%u%s\n", + EPICS_PVA_MAJOR_VERSION, + EPICS_PVA_MINOR_VERSION, + EPICS_PVA_MAINTENANCE_VERSION, + (EPICS_PVA_DEVELOPMENT_FLAG)?"-SNAPSHOT":""); + fprintf(stdout, "pvData %u.%u.%u%s\n", + EPICS_PVD_MAJOR_VERSION, + EPICS_PVD_MINOR_VERSION, + EPICS_PVD_MAINTENANCE_VERSION, + (EPICS_PVD_DEVELOPMENT_FLAG)?"-SNAPSHOT":""); + fprintf(stdout, "Base %s\n", EPICS_VERSION_FULL); + return 0; + } + case 'p': { /* Set poll period */ + if((epicsScanDouble(optarg, &pollPeriod)) != 1 || pollPeriod <= 0.0) { + fprintf(stderr, + "'%s' is not a valid poll period value " + "- ignored. ('pvans -h' for help.)\n", optarg); + timeout = DEFAULT_PVA_TIMEOUT; + } + break; + } + case 'w': { /* Set PVA timeout value */ + if((epicsScanDouble(optarg, &timeout)) != 1 || timeout <= 0.0) { + fprintf(stderr, + "'%s' is not a valid timeout value " + "- ignored. ('pvans -h' for help.)\n", optarg); + timeout = DEFAULT_PVA_TIMEOUT; + } + break; + } + case 'e': { /* Set channel expiration time */ + if((epicsScanDouble(optarg, &channelExpirationTime)) != 1) { + fprintf(stderr, + "'%s' is not a valid expiration time value " + "- ignored. ('pvans -h' for help.)\n", optarg); + channelExpirationTime = DEFAULT_CHANNEL_EXPIRATION_TIME; + } + break; + } + case 's': { /* Server list */ + serverAddresses = optarg; + break; + } + case 'f': { /* Server list file */ + inputFile = optarg; + break; + } + case 'd': { /* Debug log level */ + debug = true; + break; + } + case 'a': { /* Auto discovery */ + autoDiscovery = true; + break; + } + case '?': { + fprintf(stderr, + "Unrecognized option: '-%c'. ('pvans -h' for help.)\n", + optopt); + return 1; + } + case ':': { + fprintf(stderr, + "Option '-%c' requires an argument. ('pvans -h' for help.)\n", + optopt); + return 1; + } + default: { + usage(); + return 1; + } + } + } + + SET_LOG_LEVEL(debug ? logLevelDebug : logLevelError); + + NameServer::shared_pointer srv(new NameServer(ConfigurationBuilder() + .push_env() + .push_map() + .build())); + srv->setPollPeriod(pollPeriod); + srv->setPvaTimeout(timeout); + srv->setAutoDiscovery(autoDiscovery); + srv->setChannelEntryExpirationTime(channelExpirationTime); + while (true) { + std::string allServerAddresses = addServerAddressesFromFile(inputFile, serverAddresses); + srv->setServerAddresses(allServerAddresses); + srv->run(pollPeriod); + } + return 0; +} From 797aa775e7cf046c3a3265d74e3366ae26e31c90 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 20 Mar 2024 15:41:19 -0500 Subject: [PATCH 29/82] add name server utility description --- pvtoolsSrc/nameServer.cpp | 1 - pvtoolsSrc/pvans.cpp | 12 +++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pvtoolsSrc/nameServer.cpp b/pvtoolsSrc/nameServer.cpp index fafaa8d3..5f812502 100644 --- a/pvtoolsSrc/nameServer.cpp +++ b/pvtoolsSrc/nameServer.cpp @@ -474,7 +474,6 @@ ChannelFind::shared_pointer NameServerChannelProvider::channelList(const Channel Channel::shared_pointer NameServerChannelProvider::createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short priority) { - // SVDBG return createChannel(channelName, channelRequester, priority, "local"); } diff --git a/pvtoolsSrc/pvans.cpp b/pvtoolsSrc/pvans.cpp index 078cced6..b90a5be3 100644 --- a/pvtoolsSrc/pvans.cpp +++ b/pvtoolsSrc/pvans.cpp @@ -3,6 +3,14 @@ * found in the file LICENSE that is included with the distribution */ +/* + * PVA Name Server utility. It polls a set of PVA + * servers for a list of channels, and resolves channel queries. + * PVA servers can be discovered, they can be passed through the + * command line, or they can be specified via an input file which + * gets re-read at runtime. + */ + #include #include @@ -81,9 +89,10 @@ int main(int argc, char *argv[]) while ((opt = getopt(argc, argv, ":hHVw:e:p:das:f:")) != -1) { switch (opt) { case 'h': /* Print usage */ - case 'H': /* Print usage */ + case 'H': { /* Print usage */ usage(); return 0; + } case 'V': { /* Print version */ fprintf(stdout, "pvAccess %u.%u.%u%s\n", EPICS_PVA_MAJOR_VERSION, @@ -171,6 +180,7 @@ int main(int argc, char *argv[]) srv->setAutoDiscovery(autoDiscovery); srv->setChannelEntryExpirationTime(channelExpirationTime); while (true) { + // Reread input file before polling. std::string allServerAddresses = addServerAddressesFromFile(inputFile, serverAddresses); srv->setServerAddresses(allServerAddresses); srv->run(pollPeriod); From fd115a8dc45ce33dd7c0a2bd5f26bd19d694fce4 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 21 Mar 2024 09:48:05 -0500 Subject: [PATCH 30/82] add utilities for manipulating strings --- src/utils/Makefile | 2 + src/utils/pv/stringUtility.h | 25 +++++++++ src/utils/stringUtility.cpp | 79 +++++++++++++++++++++++++++++ testApp/utils/Makefile | 6 +++ testApp/utils/testStringUtility.cpp | 62 ++++++++++++++++++++++ 5 files changed, 174 insertions(+) create mode 100644 src/utils/pv/stringUtility.h create mode 100644 src/utils/stringUtility.cpp create mode 100644 testApp/utils/testStringUtility.cpp diff --git a/src/utils/Makefile b/src/utils/Makefile index bbc13eb1..95d57ef3 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -12,6 +12,7 @@ INC += pv/wildcard.h INC += pv/fairQueue.h INC += pv/requester.h INC += pv/destroyable.h +INC += pv/stringUtility.h pvAccess_SRCS += getgroups.cpp pvAccess_SRCS += hexDump.cpp @@ -22,3 +23,4 @@ pvAccess_SRCS += configuration.cpp pvAccess_SRCS += referenceCountingLock.cpp pvAccess_SRCS += requester.cpp pvAccess_SRCS += wildcard.cpp +pvAccess_SRCS += stringUtility.cpp diff --git a/src/utils/pv/stringUtility.h b/src/utils/pv/stringUtility.h new file mode 100644 index 00000000..ae041a68 --- /dev/null +++ b/src/utils/pv/stringUtility.h @@ -0,0 +1,25 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvAccessCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#ifndef STRING_UTILITY_H +#define STRING_UTILITY_H + +#include +#include + +namespace epics { namespace pvAccess { namespace StringUtility { + +std::string leftTrim(const std::string& s); +std::string rightTrim(const std::string& s); +std::string trim(const std::string& s); +std::vector& split(const std::string& s, char delimiter, std::vector& elements); +std::vector split(const std::string& s, char delimiter); +std::string toLowerCase(const std::string& input); +std::string toUpperCase(const std::string& input); + +}}} // namespace epics::pvAccess::StringUtility + +#endif diff --git a/src/utils/stringUtility.cpp b/src/utils/stringUtility.cpp new file mode 100644 index 00000000..45094210 --- /dev/null +++ b/src/utils/stringUtility.cpp @@ -0,0 +1,79 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvAccessCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#include +#include +#include +#include "pv/stringUtility.h" + +namespace epics { namespace pvAccess { namespace StringUtility { + +std::string leftTrim(const std::string& s) +{ + unsigned int i; + unsigned int n = (unsigned int)s.length(); + for (i = 0; i < n; i++) { + if (!isspace(s[i])) { + break; + } + } + return s.substr(i,n-i); +} + +std::string rightTrim(const std::string& s) +{ + unsigned int i; + unsigned int n = (unsigned int)s.length(); + for (i = n; i > 0; i--) { + if (!isspace(s[i-1])) { + break; + } + } + return s.substr(0,i); +} + +std::string trim(const std::string& s) +{ + return rightTrim(leftTrim(s)); +} + +std::vector& split(const std::string& s, char delimiter, std::vector& elements) +{ + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delimiter)) { + elements.push_back(trim(item)); + } + return elements; +} + +std::vector split(const std::string& s, char delimiter) +{ + std::vector elements; + split(s, delimiter, elements); + return elements; +} + +std::string toLowerCase(const std::string& input) +{ + std::stringstream ss; + for (unsigned int i = 0; i < input.size(); i++) { + char c = std::tolower(input.at(i)); + ss << c; + } + return ss.str(); +} + +std::string toUpperCase(const std::string& input) +{ + std::stringstream ss; + for (unsigned int i = 0; i < input.size(); i++) { + char c = std::toupper(input.at(i)); + ss << c; + } + return ss.str(); +} +}}} diff --git a/testApp/utils/Makefile b/testApp/utils/Makefile index c57c9030..402d37fa 100644 --- a/testApp/utils/Makefile +++ b/testApp/utils/Makefile @@ -33,3 +33,9 @@ TESTS += testWildcard TESTPROD_HOST += showauth showauth_SRCS += showauth.cpp + +TESTPROD_HOST += testStringUtility +testStringUtility_SRCS = testStringUtility.cpp +testHarness_SRCS += testStringUtility.cpp +TESTS += testStringUtility + diff --git a/testApp/utils/testStringUtility.cpp b/testApp/utils/testStringUtility.cpp new file mode 100644 index 00000000..f144e970 --- /dev/null +++ b/testApp/utils/testStringUtility.cpp @@ -0,0 +1,62 @@ +#include +#include + +#include + +#include + +#include + +#include +#include + +using namespace epics::pvAccess::StringUtility; + +namespace { + +void test_trim() +{ + testDiag("Test trim()"); + testOk1(trim(" abc123 ") == "abc123"); + testOk1(trim("abc123 ") == "abc123"); + testOk1(trim(" abc123") == "abc123"); +} + +void test_split() +{ + testDiag("Test split()"); + const std::string testString = " a123 , b123 , c123 , d123,e123 "; + std::vector v = split(testString, ','); + testOk1(v.size() == 5); + testOk1(v[0] == "a123"); + testOk1(v[1] == "b123"); + testOk1(v[2] == "c123"); + testOk1(v[3] == "d123"); + testOk1(v[4] == "e123"); +} + +void test_toLowerCase() +{ + testDiag("Test toLowerCase()"); + testOk1(toLowerCase("AbCdEfGhIj12345Kl") == "abcdefghij12345kl"); +} + +void test_toUpperCase() +{ + testDiag("Test toUpperCase()"); + testOk1(toUpperCase("AbCdEfGhIj12345Kl") == "ABCDEFGHIJ12345KL"); +} + +} // namespace + +MAIN(testStringUtility) +{ + testPlan(3+6+1+1); + testDiag("Tests for string utilities"); + + test_trim(); + test_split(); + test_toLowerCase(); + test_toUpperCase(); + return testDone(); +} From 9dcd131cbf5681b17edfdc753a686b3409a40ec9 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 21 Mar 2024 10:47:15 -0500 Subject: [PATCH 31/82] add additional utility methods --- src/utils/pv/stringUtility.h | 7 +++-- src/utils/stringUtility.cpp | 43 ++++++++++++++++++++++++++--- testApp/utils/testStringUtility.cpp | 25 +++++++++++++++-- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/utils/pv/stringUtility.h b/src/utils/pv/stringUtility.h index ae041a68..2b2d431e 100644 --- a/src/utils/pv/stringUtility.h +++ b/src/utils/pv/stringUtility.h @@ -15,10 +15,13 @@ namespace epics { namespace pvAccess { namespace StringUtility { std::string leftTrim(const std::string& s); std::string rightTrim(const std::string& s); std::string trim(const std::string& s); -std::vector& split(const std::string& s, char delimiter, std::vector& elements); -std::vector split(const std::string& s, char delimiter); +std::vector& split(const std::string& s, char delimiter, std::vector& elements, bool ignoreEmptyTokens = false); +std::vector split(const std::string& s, char delimiter, bool ignoreEmptyTokens = false); std::string toLowerCase(const std::string& input); std::string toUpperCase(const std::string& input); +std::string replace(const std::string& input, char oldChar, char newChar); +std::string replace(const std::string& input, char oldChar, const std::string& newString); +std::string replace(const std::string& input, const std::string& oldString, const std::string& newString); }}} // namespace epics::pvAccess::StringUtility diff --git a/src/utils/stringUtility.cpp b/src/utils/stringUtility.cpp index 45094210..116f91c2 100644 --- a/src/utils/stringUtility.cpp +++ b/src/utils/stringUtility.cpp @@ -40,20 +40,23 @@ std::string trim(const std::string& s) return rightTrim(leftTrim(s)); } -std::vector& split(const std::string& s, char delimiter, std::vector& elements) +std::vector& split(const std::string& s, char delimiter, std::vector& elements, bool ignoreEmptyTokens) { std::stringstream ss(s); std::string item; while (std::getline(ss, item, delimiter)) { - elements.push_back(trim(item)); + item = trim(item); + if (!item.empty() || !ignoreEmptyTokens) { + elements.push_back(item); + } } return elements; } -std::vector split(const std::string& s, char delimiter) +std::vector split(const std::string& s, char delimiter, bool ignoreEmptyTokens) { std::vector elements; - split(s, delimiter, elements); + split(s, delimiter, elements, ignoreEmptyTokens); return elements; } @@ -76,4 +79,36 @@ std::string toUpperCase(const std::string& input) } return ss.str(); } + +std::string replace(const std::string& input, char oldChar, char newChar) +{ + std::string oldString; + oldString += oldChar; + std::string newString; + newString += newChar; + return replace(input, oldString, newString); +} + +std::string replace(const std::string& input, char oldChar, const std::string& newString) +{ + std::string oldString; + oldString += oldChar; + return replace(input, oldString, newString); +} + +std::string replace(const std::string& input, const std::string& oldString, const std::string& newString) +{ + if (oldString.empty()) { + return input; + } + std::string output = input; + std::string::size_type pos = input.find(oldString); + while (pos != std::string::npos) { + output = output.replace(pos, oldString.size(), newString); + pos = pos + newString.size(); + pos = output.find(oldString, pos); + } + return output; +} + }}} diff --git a/testApp/utils/testStringUtility.cpp b/testApp/utils/testStringUtility.cpp index f144e970..f1bd9de4 100644 --- a/testApp/utils/testStringUtility.cpp +++ b/testApp/utils/testStringUtility.cpp @@ -25,7 +25,8 @@ void test_trim() void test_split() { testDiag("Test split()"); - const std::string testString = " a123 , b123 , c123 , d123,e123 "; + std::string testString = " a123 , b123 , c123 , d123,e123 "; + testDiag("Splitting by ',', input string: '%s'", testString.c_str()); std::vector v = split(testString, ','); testOk1(v.size() == 5); testOk1(v[0] == "a123"); @@ -33,6 +34,16 @@ void test_split() testOk1(v[2] == "c123"); testOk1(v[3] == "d123"); testOk1(v[4] == "e123"); + testString = " a123 b123 c123 d123 e123 "; + testDiag("Splitting by ' ' and ignoring empty tokens, input string: '%s'", testString.c_str()); + bool ignoreEmptyTokens = true; + v = split(testString, ' ', ignoreEmptyTokens); + testOk1(v.size() == 5); + testOk1(v[0] == "a123"); + testOk1(v[1] == "b123"); + testOk1(v[2] == "c123"); + testOk1(v[3] == "d123"); + testOk1(v[4] == "e123"); } void test_toLowerCase() @@ -47,16 +58,26 @@ void test_toUpperCase() testOk1(toUpperCase("AbCdEfGhIj12345Kl") == "ABCDEFGHIJ12345KL"); } +void test_replace() +{ + testDiag("Test replace()"); + testOk1(replace("a,b,c,d,e,f,1,2,3", ",", " ") == "a b c d e f 1 2 3"); + testOk1(replace("a,b,c", ',', ' ') == "a b c"); + testOk1(replace("a,b,c", ',', "aa") == "aaabaac"); + testOk1(replace("a,b,c", ",", ",X,") == "a,X,b,X,c"); +} + } // namespace MAIN(testStringUtility) { - testPlan(3+6+1+1); + testPlan(3+12+1+1+4); testDiag("Tests for string utilities"); test_trim(); test_split(); test_toLowerCase(); test_toUpperCase(); + test_replace(); return testDone(); } From 6719d200d8e4f664030ac4d3b2330ab9631fa469 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 21 Mar 2024 11:46:19 -0500 Subject: [PATCH 32/82] add support for a static channel map read from a file --- pvtoolsSrc/nameServer.cpp | 25 +++++++++++----- pvtoolsSrc/nameServer.h | 4 ++- pvtoolsSrc/pvans.cpp | 63 ++++++++++++++++++++++++++++++++------- 3 files changed, 74 insertions(+), 18 deletions(-) diff --git a/pvtoolsSrc/nameServer.cpp b/pvtoolsSrc/nameServer.cpp index 5f812502..1025ae88 100644 --- a/pvtoolsSrc/nameServer.cpp +++ b/pvtoolsSrc/nameServer.cpp @@ -6,6 +6,7 @@ #include +#include #include "nameServer.h" #include "pvutils.h" @@ -418,6 +419,17 @@ void NameServerChannelProvider::setChannelEntryExpirationTime(double expirationT this->channelEntryExpirationTime = expirationTime; } +void NameServerChannelProvider::setStaticChannelEntries(const ChannelMap& channelMap) +{ + Lock lock(channelMapMutex); + for (ChannelMap::const_iterator it = channelMap.begin(); it != channelMap.end(); it++) { + std::string channelName = it->first; + ChannelEntry channelEntry = it->second; + this->channelMap[channelName] = channelEntry; + } + LOG(logLevelDebug, "Updated %ld static channel entries", channelMap.size()); +} + std::string NameServerChannelProvider::NameServerChannelProvider::getProviderName() { return PROVIDER_NAME; @@ -540,11 +552,14 @@ void NameServer::setAutoDiscovery(bool autoDiscovery) { this->autoDiscovery = autoDiscovery; } -void NameServer::setServerAddresses(const std::string& serverAddresses) +void NameServer::setStaticServerAddresses(const std::string& serverAddresses) { this->serverAddresses = serverAddresses; } - +void NameServer::setStaticChannelEntries(const ChannelMap& channelMap) +{ + this->channelProvider->setStaticChannelEntries(channelMap); +} void NameServer::setChannelEntryExpirationTime(double expirationTime) { LOG(logLevelDebug, "Setting channel entry expiration time to %.2f seconds", expirationTime); @@ -592,11 +607,7 @@ bool NameServer::addUniqueServerToList(const std::string& serverAddress, ServerA void NameServer::addServersFromAddresses(ServerAddressList& serverAddressList) { LOG(logLevelDebug, "Adding pre-configured server addresses"); - std::string::size_type pos; - std::string addresses = serverAddresses; - while ((pos = addresses.find(',')) != std::string::npos) { - addresses = addresses.replace(pos, 1, " "); - } + std::string addresses = StringUtility::replace(serverAddresses, ',', " "); InetAddrVector inetAddrVector; getSocketAddressList(inetAddrVector, addresses, context->getServerPort()); int nAddedServers = 0; diff --git a/pvtoolsSrc/nameServer.h b/pvtoolsSrc/nameServer.h index 3c8f46df..b9071ede 100644 --- a/pvtoolsSrc/nameServer.h +++ b/pvtoolsSrc/nameServer.h @@ -128,6 +128,7 @@ class NameServerChannelProvider void updateChannelMap(const ChannelMap& updatedChannelMap); std::string getChannelServerAddress(const std::string& channelName); void setChannelEntryExpirationTime(double expirationTime); + void setStaticChannelEntries(const ChannelMap& channelMap); private: ChannelFind::shared_pointer nsChannelFind; @@ -146,7 +147,8 @@ class NameServer void setPollPeriod(double pollPeriod); void setPvaTimeout(double timeout); void setAutoDiscovery(bool autoDiscovery); - void setServerAddresses(const std::string& serverAddresses); + void setStaticServerAddresses(const std::string& serverAddresses); + void setStaticChannelEntries(const ChannelMap& channelMap); void setChannelEntryExpirationTime(double expirationTime); void run(double runtime); diff --git a/pvtoolsSrc/pvans.cpp b/pvtoolsSrc/pvans.cpp index b90a5be3..bc1674e6 100644 --- a/pvtoolsSrc/pvans.cpp +++ b/pvtoolsSrc/pvans.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ #include #include +#include #include "nameServer.h" #include "pvutils.h" @@ -47,19 +49,25 @@ void usage (void) { "\noptions:\n" " -h|-H\t\t\t:\tHelp: Print this message\n" " -V\t\t\t:\tPrint version and exit\n" - " -f \t:\tInput file containing list of PVA server addresses in the form :\n" - " -s ,,...\t:\tComma-separated list of PVA server addresses in the form :\n" + " -f \t:\tStatic server list file with '' entries\n" + " -F \t:\tStatic channel map file with ' ' entries\n" + " -s ,,...\t:\tComma-separated list of '' static server entries\n" " -a\t\t\t:\tAuto mode, discover severs available on the network\n" " -p \t:\tServer poll period in seconds (default: %.2f [s])\n" " -w \t:\tServer wait time in seconds (default: %.2f [s])\n" " -e \t:\tChannel entry expiration time in seconds (default: %.2f [s])\n" " -d\t\t\t:\tEnable debug output\n" "\nDifferent inputs for PVA server address will be combined." - "\nChannel expiration time <= 0 indicates that channel entries never expire.\n\n" + "\nServer list file should contain '' entries separated by spaces or commas, or on different lines." + "\nChannel map file should contain ' ' entries separated by spaces or commas, or on different lines." + "\nChannel expiration time <= 0 indicates that channel entries" + "\nnever expire.\n\n" , DEFAULT_POLL_PERIOD, DEFAULT_PVA_TIMEOUT, DEFAULT_CHANNEL_EXPIRATION_TIME); } -std::string addServerAddressesFromFile(const std::string& inputFile, const std::string& existingAddresses = "") +// Expected server address format: +// There can be multiple addresses per line, separated by spaces or commas. +std::string readServerAddressesFromFile(const std::string& inputFile, const std::string& existingAddresses = "") { std::string serverAddresses = existingAddresses; if (inputFile.empty()) { @@ -68,12 +76,39 @@ std::string addServerAddressesFromFile(const std::string& inputFile, const std:: std::ifstream ifs(inputFile); std::string line; while (std::getline(ifs, line)) { + line = StringUtility::replace(line, ',', " "); serverAddresses = serverAddresses + " " + line; } return serverAddresses; } -} //namespace +// Expected channel entry format: +// There can be multiple entries per line, separated by spaces or commas. +void readChannelAddressesFromFile(const std::string& inputFile, ChannelMap& channelMap) +{ + if (inputFile.empty()) { + return; + } + bool ignoreEmptyTokens = true; + epicsTimeStamp now; + epicsTimeGetCurrent(&now); + std::ifstream ifs(inputFile); + std::string line; + while (std::getline(ifs, line)) { + line = StringUtility::replace(line, ',', " "); + std::vector tokens = StringUtility::split(line, ' ', ignoreEmptyTokens); + int nTokens = int(tokens.size()); + for (int i = 0; i < nTokens-1; i+=2) { + std::string channelName = tokens[i]; + std::string serverAddress = tokens[i+1]; + ChannelEntry channelEntry = {channelName, serverAddress, now}; + channelMap[channelName] = channelEntry; + LOG(logLevelDebug, "Adding %s/%s channel entry", channelName.c_str(), serverAddress.c_str()); + } + } +} + +} // namespace int main(int argc, char *argv[]) { @@ -83,10 +118,11 @@ int main(int argc, char *argv[]) double timeout = DEFAULT_PVA_TIMEOUT; double pollPeriod = DEFAULT_POLL_PERIOD; double channelExpirationTime = DEFAULT_CHANNEL_EXPIRATION_TIME; - std::string inputFile; std::string serverAddresses; + std::string serverListFile; + std::string channelMapFile; - while ((opt = getopt(argc, argv, ":hHVw:e:p:das:f:")) != -1) { + while ((opt = getopt(argc, argv, ":hHVw:e:p:das:f:F:")) != -1) { switch (opt) { case 'h': /* Print usage */ case 'H': { /* Print usage */ @@ -139,7 +175,11 @@ int main(int argc, char *argv[]) break; } case 'f': { /* Server list file */ - inputFile = optarg; + serverListFile = optarg; + break; + } + case 'F': { /* Channel map file */ + channelMapFile = optarg; break; } case 'd': { /* Debug log level */ @@ -181,8 +221,11 @@ int main(int argc, char *argv[]) srv->setChannelEntryExpirationTime(channelExpirationTime); while (true) { // Reread input file before polling. - std::string allServerAddresses = addServerAddressesFromFile(inputFile, serverAddresses); - srv->setServerAddresses(allServerAddresses); + std::string staticServerAddresses = readServerAddressesFromFile(serverListFile, serverAddresses); + srv->setStaticServerAddresses(staticServerAddresses); + ChannelMap staticChannelMap; + readChannelAddressesFromFile(channelMapFile, staticChannelMap); + srv->setStaticChannelEntries(staticChannelMap); srv->run(pollPeriod); } return 0; From 3c598c21c9e52e58ed66be85a516ccd78fe25cda Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 21 Mar 2024 11:51:55 -0500 Subject: [PATCH 33/82] update description --- pvtoolsSrc/pvans.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pvtoolsSrc/pvans.cpp b/pvtoolsSrc/pvans.cpp index bc1674e6..aaa6e60a 100644 --- a/pvtoolsSrc/pvans.cpp +++ b/pvtoolsSrc/pvans.cpp @@ -8,7 +8,8 @@ * servers for a list of channels, and resolves channel queries. * PVA servers can be discovered, they can be passed through the * command line, or they can be specified via an input file which - * gets re-read at runtime. + * gets re-read at runtime. The utility also supports static channel + * map entries read from an input file. */ #include @@ -66,7 +67,7 @@ void usage (void) { } // Expected server address format: -// There can be multiple addresses per line, separated by spaces or commas. +// There can be multiple addresses per line, separated by spaces or commas. std::string readServerAddressesFromFile(const std::string& inputFile, const std::string& existingAddresses = "") { std::string serverAddresses = existingAddresses; @@ -83,7 +84,7 @@ std::string readServerAddressesFromFile(const std::string& inputFile, const std: } // Expected channel entry format: -// There can be multiple entries per line, separated by spaces or commas. +// There can be multiple entries per line, separated by spaces or commas. void readChannelAddressesFromFile(const std::string& inputFile, ChannelMap& channelMap) { if (inputFile.empty()) { @@ -103,7 +104,7 @@ void readChannelAddressesFromFile(const std::string& inputFile, ChannelMap& chan std::string serverAddress = tokens[i+1]; ChannelEntry channelEntry = {channelName, serverAddress, now}; channelMap[channelName] = channelEntry; - LOG(logLevelDebug, "Adding %s/%s channel entry", channelName.c_str(), serverAddress.c_str()); + LOG(logLevelDebug, "Adding %s/%s channel entry", channelName.c_str(), serverAddress.c_str()); } } } From 18a7e2a7322267b53019089cb2bed19708356cf8 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 21 Mar 2024 15:22:37 -0500 Subject: [PATCH 34/82] send search response immediately --- src/server/responseHandlers.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 997a04b6..588cbe72 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -582,6 +582,9 @@ void ServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendContr } control->setRecipient(_sendTo); + + // send immediately + control->flush(true); } /****************************************************************************************/ From f629385e8e6a6b0848102facdb353f619634ae36 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 21 Mar 2024 15:26:04 -0500 Subject: [PATCH 35/82] send name server search response immediately --- pvtoolsSrc/nameServer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pvtoolsSrc/nameServer.cpp b/pvtoolsSrc/nameServer.cpp index 1025ae88..5276f951 100644 --- a/pvtoolsSrc/nameServer.cpp +++ b/pvtoolsSrc/nameServer.cpp @@ -157,6 +157,9 @@ void NameServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendC } control->setRecipient(sendTo); + + // send immediately + control->flush(true); } /* From 94e9042e2b9a4e8ed0e9de29787847f691b9bbe9 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 21 Mar 2024 19:32:00 -0500 Subject: [PATCH 36/82] update for older gcc compiler --- pvtoolsSrc/pvans.cpp | 4 ++-- src/remoteClient/clientContextImpl.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pvtoolsSrc/pvans.cpp b/pvtoolsSrc/pvans.cpp index aaa6e60a..7e9ef776 100644 --- a/pvtoolsSrc/pvans.cpp +++ b/pvtoolsSrc/pvans.cpp @@ -74,7 +74,7 @@ std::string readServerAddressesFromFile(const std::string& inputFile, const std: if (inputFile.empty()) { return serverAddresses; } - std::ifstream ifs(inputFile); + std::ifstream ifs(inputFile.c_str()); std::string line; while (std::getline(ifs, line)) { line = StringUtility::replace(line, ',', " "); @@ -93,7 +93,7 @@ void readChannelAddressesFromFile(const std::string& inputFile, ChannelMap& chan bool ignoreEmptyTokens = true; epicsTimeStamp now; epicsTimeGetCurrent(&now); - std::ifstream ifs(inputFile); + std::ifstream ifs(inputFile.c_str()); std::string line; while (std::getline(ifs, line)) { line = StringUtility::replace(line, ',', " "); diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 4fcae9fa..8da953eb 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -4136,7 +4136,7 @@ class InternalClientContextImpl : } createNameServerConnector(); - if (!m_nsConnector) + if (!m_nsConnector.get()) { return Transport::shared_pointer(); } @@ -4315,7 +4315,7 @@ class InternalClientContextImpl : void createNameServerConnector() { - if (!m_nsConnector && m_nsAddresses.size()) + if (!m_nsConnector.get() && m_nsAddresses.size()) { LOG(logLevelDebug, "Creating internal name server channel and connector"); InetAddrVector nsAddresses; // avoid direct connection attempts From db58c6f31581a9403eab0f1a1a4b8b69bd67d638 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 22 Mar 2024 16:18:24 -0500 Subject: [PATCH 37/82] fix windows build --- src/utils/pv/stringUtility.h | 22 ++++++++++++---------- src/utils/stringUtility.cpp | 2 ++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/utils/pv/stringUtility.h b/src/utils/pv/stringUtility.h index 2b2d431e..5067cca4 100644 --- a/src/utils/pv/stringUtility.h +++ b/src/utils/pv/stringUtility.h @@ -10,18 +10,20 @@ #include #include +#include + namespace epics { namespace pvAccess { namespace StringUtility { -std::string leftTrim(const std::string& s); -std::string rightTrim(const std::string& s); -std::string trim(const std::string& s); -std::vector& split(const std::string& s, char delimiter, std::vector& elements, bool ignoreEmptyTokens = false); -std::vector split(const std::string& s, char delimiter, bool ignoreEmptyTokens = false); -std::string toLowerCase(const std::string& input); -std::string toUpperCase(const std::string& input); -std::string replace(const std::string& input, char oldChar, char newChar); -std::string replace(const std::string& input, char oldChar, const std::string& newString); -std::string replace(const std::string& input, const std::string& oldString, const std::string& newString); +epicsShareFunc std::string leftTrim(const std::string& s); +epicsShareFunc std::string rightTrim(const std::string& s); +epicsShareFunc std::string trim(const std::string& s); +epicsShareFunc std::vector& split(const std::string& s, char delimiter, std::vector& elements, bool ignoreEmptyTokens = false); +epicsShareFunc std::vector split(const std::string& s, char delimiter, bool ignoreEmptyTokens = false); +epicsShareFunc std::string toLowerCase(const std::string& input); +epicsShareFunc std::string toUpperCase(const std::string& input); +epicsShareFunc std::string replace(const std::string& input, char oldChar, char newChar); +epicsShareFunc std::string replace(const std::string& input, char oldChar, const std::string& newString); +epicsShareFunc std::string replace(const std::string& input, const std::string& oldString, const std::string& newString); }}} // namespace epics::pvAccess::StringUtility diff --git a/src/utils/stringUtility.cpp b/src/utils/stringUtility.cpp index 116f91c2..41377de3 100644 --- a/src/utils/stringUtility.cpp +++ b/src/utils/stringUtility.cpp @@ -7,6 +7,8 @@ #include #include #include + +#define epicsExportSharedSymbols #include "pv/stringUtility.h" namespace epics { namespace pvAccess { namespace StringUtility { From f63cb892e6d507bda20ead056c4039f81119003b Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Sun, 24 Mar 2024 20:01:18 -0500 Subject: [PATCH 38/82] move base nameserver code to the library --- pvtoolsSrc/Makefile | 2 +- pvtoolsSrc/nameServerImpl.cpp | 92 ++++++++++++++++++++++ pvtoolsSrc/nameServerImpl.h | 23 ++++++ pvtoolsSrc/pvans.cpp | 9 ++- src/server/Makefile | 8 +- {pvtoolsSrc => src/server}/nameServer.cpp | 69 ++-------------- {pvtoolsSrc => src/server/pv}/nameServer.h | 67 ++++++++-------- src/utils/Makefile | 2 + src/utils/channelDiscovery.cpp | 27 +++++++ src/utils/pv/channelDiscovery.h | 45 +++++++++++ 10 files changed, 242 insertions(+), 102 deletions(-) create mode 100644 pvtoolsSrc/nameServerImpl.cpp create mode 100644 pvtoolsSrc/nameServerImpl.h rename {pvtoolsSrc => src/server}/nameServer.cpp (90%) rename {pvtoolsSrc => src/server/pv}/nameServer.h (77%) create mode 100644 src/utils/channelDiscovery.cpp create mode 100644 src/utils/pv/channelDiscovery.h diff --git a/pvtoolsSrc/Makefile b/pvtoolsSrc/Makefile index 1d97eca3..b4a8b9b5 100644 --- a/pvtoolsSrc/Makefile +++ b/pvtoolsSrc/Makefile @@ -33,7 +33,7 @@ pvlist_SRCS += pvutils.cpp PROD_DEFAULT += pvans pvans_SRCS += pvans.cpp pvans_SRCS += pvutils.cpp -pvans_SRCS += nameServer.cpp +pvans_SRCS += nameServerImpl.cpp PROD_LIBS += pvAccessCA pvAccess pvData ca Com diff --git a/pvtoolsSrc/nameServerImpl.cpp b/pvtoolsSrc/nameServerImpl.cpp new file mode 100644 index 00000000..b56afabd --- /dev/null +++ b/pvtoolsSrc/nameServerImpl.cpp @@ -0,0 +1,92 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvAccessCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + + +#include +#include + +#include "nameServerImpl.h" +#include "pvutils.h" + +using namespace std; +using namespace epics::pvData; +using epics::pvAccess::ChannelDiscovery::ChannelEntry; +using epics::pvAccess::ChannelDiscovery::ChannelMap; +using epics::pvAccess::ChannelDiscovery::ServerAddressList; + + +namespace epics { namespace pvAccess { + + +NameServerImpl::NameServerImpl(const epics::pvAccess::Configuration::shared_pointer& conf) + : NameServer(conf) +{ +} + +NameServerImpl::~NameServerImpl() +{ +} + +void NameServerImpl::discoverServers(ServerAddressList& serverAddressList) +{ + if (!autoDiscovery) { + LOG(logLevelDebug, "Skipping server discovery"); + return; + } + + LOG(logLevelDebug, "Starting server discovery"); + ServerGUID guid = context->getGUID(); + std::string nsGuid = ::toHex((int8*)guid.value, sizeof(guid.value)); + ServerMap serverMap; + ::discoverServers(timeout, serverMap); + + int nDiscoveredServers = 0; + for (ServerMap::const_iterator it = serverMap.begin(); it != serverMap.end(); it++) { + const ServerEntry& entry = it->second; + if (nsGuid == entry.guid) { + LOG(logLevelDebug, "Ignoring our own server GUID 0x%s", entry.guid.c_str()); + continue; + } + size_t count = entry.addresses.size(); + std::string addresses = " "; + for (size_t i = 0; i < count; i++) { + addresses = addresses + inetAddressToString(entry.addresses[i]) + " "; + } + LOG(logLevelDebug, "Found server GUID 0x%s version %d: %s@[%s]", entry.guid.c_str(), (int)entry.version, entry.protocol.c_str(), addresses.c_str()); + if (count > 0) { + std::string serverAddress = inetAddressToString(entry.addresses[0]); + if (addUniqueServerToList(serverAddress, serverAddressList)) { + nDiscoveredServers++; + } + } + } + LOG(logLevelDebug, "Discovered %d servers", nDiscoveredServers); +} + +void NameServerImpl::discoverServerChannels(const std::string& serverAddress, ChannelMap& channelMap) +{ + LOG(logLevelDebug, "Discovering channels for server %s", serverAddress.c_str()); + try { + PVStructure::shared_pointer ret = getChannelInfo(serverAddress, "channels", timeout); + PVStringArray::shared_pointer pvs(ret->getSubField("value")); + PVStringArray::const_svector val(pvs->view()); + epicsTimeStamp now; + epicsTimeGetCurrent(&now); + for (unsigned int i = 0; i < val.size(); i++) { + ChannelEntry channelEntry; + channelEntry.channelName = val[i]; + channelEntry.serverAddress = serverAddress; + channelEntry.updateTime = now; + channelMap[val[i]] = channelEntry; + } + LOG(logLevelDebug, "Discovered %ld channels for server %s", val.size(), serverAddress.c_str()); + } + catch(std::exception& e) { + LOG(logLevelError, "Error retrieving channels for server %s: %s", serverAddress.c_str(), e.what()); + } +} + +}} diff --git a/pvtoolsSrc/nameServerImpl.h b/pvtoolsSrc/nameServerImpl.h new file mode 100644 index 00000000..b05a0ae8 --- /dev/null +++ b/pvtoolsSrc/nameServerImpl.h @@ -0,0 +1,23 @@ +#ifndef NAME_SERVER_IMPL_H +#define NAME_SERVER_IMPL_H + +#include + +namespace epics { namespace pvAccess { + +class NameServerImpl + : public NameServer + , public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(NameServerImpl); + NameServerImpl(const epics::pvAccess::Configuration::shared_pointer& conf); + virtual ~NameServerImpl(); + + virtual void discoverServers(ChannelDiscovery::ServerAddressList& serverAddressList); + virtual void discoverServerChannels(const std::string& serverAddress, ChannelDiscovery::ChannelMap& channelMap); +}; + +}} + +#endif // NAME_SERVER_IMPL_H diff --git a/pvtoolsSrc/pvans.cpp b/pvtoolsSrc/pvans.cpp index 7e9ef776..0593ec06 100644 --- a/pvtoolsSrc/pvans.cpp +++ b/pvtoolsSrc/pvans.cpp @@ -29,13 +29,14 @@ #include #include -#include "nameServer.h" -#include "pvutils.h" +#include "nameServerImpl.h" using namespace std; using namespace epics::pvData; using namespace epics::pvAccess; +using epics::pvAccess::ChannelDiscovery::ChannelEntry; +using epics::pvAccess::ChannelDiscovery::ChannelMap; namespace { @@ -102,7 +103,7 @@ void readChannelAddressesFromFile(const std::string& inputFile, ChannelMap& chan for (int i = 0; i < nTokens-1; i+=2) { std::string channelName = tokens[i]; std::string serverAddress = tokens[i+1]; - ChannelEntry channelEntry = {channelName, serverAddress, now}; + ChannelEntry channelEntry(channelName, serverAddress, now); channelMap[channelName] = channelEntry; LOG(logLevelDebug, "Adding %s/%s channel entry", channelName.c_str(), serverAddress.c_str()); } @@ -212,7 +213,7 @@ int main(int argc, char *argv[]) SET_LOG_LEVEL(debug ? logLevelDebug : logLevelError); - NameServer::shared_pointer srv(new NameServer(ConfigurationBuilder() + NameServerImpl::shared_pointer srv(new NameServerImpl(ConfigurationBuilder() .push_env() .push_map() .build())); diff --git a/src/server/Makefile b/src/server/Makefile index 5c1c80e5..d3d8466c 100644 --- a/src/server/Makefile +++ b/src/server/Makefile @@ -4,11 +4,12 @@ SRC_DIRS += $(PVACCESS_SRC)/server INC += pv/serverContext.h INC += pv/beaconServerStatusProvider.h -INC += pv/responseHandlers.h -INC += pv/serverContextImpl.h -INC += pv/serverChannelImpl.h INC += pv/baseChannelRequester.h INC += pv/beaconEmitter.h +INC += pv/nameServer.h +INC += pv/responseHandlers.h +INC += pv/serverChannelImpl.h +INC += pv/serverContextImpl.h INC += pva/server.h INC += pva/sharedstate.h @@ -19,6 +20,7 @@ pvAccess_SRCS += baseChannelRequester.cpp pvAccess_SRCS += beaconEmitter.cpp pvAccess_SRCS += beaconServerStatusProvider.cpp pvAccess_SRCS += server.cpp +pvAccess_SRCS += nameServer.cpp pvAccess_SRCS += sharedstate_pv.cpp pvAccess_SRCS += sharedstate_channel.cpp pvAccess_SRCS += sharedstate_rpc.cpp diff --git a/pvtoolsSrc/nameServer.cpp b/src/server/nameServer.cpp similarity index 90% rename from pvtoolsSrc/nameServer.cpp rename to src/server/nameServer.cpp index 5276f951..134456f0 100644 --- a/pvtoolsSrc/nameServer.cpp +++ b/src/server/nameServer.cpp @@ -8,16 +8,18 @@ #include #include -#include "nameServer.h" -#include "pvutils.h" +#define epicsExportSharedSymbols +#include "pv/nameServer.h" using namespace std; using namespace epics::pvData; using std::tr1::dynamic_pointer_cast; using std::tr1::static_pointer_cast; +using epics::pvAccess::ChannelDiscovery::ChannelEntry; +using epics::pvAccess::ChannelDiscovery::ChannelMap; +using epics::pvAccess::ChannelDiscovery::ServerAddressList; -namespace epics { -namespace pvAccess { +namespace epics { namespace pvAccess { /* * Name server channel find requester @@ -623,65 +625,6 @@ void NameServer::addServersFromAddresses(ServerAddressList& serverAddressList) LOG(logLevelDebug, "Added %d pre-configured server addresses", nAddedServers); } -void NameServer::discoverServers(ServerAddressList& serverAddressList) -{ - if (!autoDiscovery) { - LOG(logLevelDebug, "Skipping server discovery"); - return; - } - - LOG(logLevelDebug, "Starting server discovery"); - ServerGUID guid = context->getGUID(); - std::string nsGuid = ::toHex((int8*)guid.value, sizeof(guid.value)); - ServerMap serverMap; - ::discoverServers(timeout, serverMap); - - int nDiscoveredServers = 0; - for (ServerMap::const_iterator it = serverMap.begin(); it != serverMap.end(); it++) { - const ServerEntry& entry = it->second; - if (nsGuid == entry.guid) { - LOG(logLevelDebug, "Ignoring our own server GUID 0x%s", entry.guid.c_str()); - continue; - } - size_t count = entry.addresses.size(); - std::string addresses = " "; - for (size_t i = 0; i < count; i++) { - addresses = addresses + inetAddressToString(entry.addresses[i]) + " "; - } - LOG(logLevelDebug, "Found server GUID 0x%s version %d: %s@[%s]", entry.guid.c_str(), (int)entry.version, entry.protocol.c_str(), addresses.c_str()); - if (count > 0) { - std::string serverAddress = inetAddressToString(entry.addresses[0]); - if (addUniqueServerToList(serverAddress, serverAddressList)) { - nDiscoveredServers++; - } - } - } - LOG(logLevelDebug, "Discovered %d servers", nDiscoveredServers); -} - -void NameServer::discoverServerChannels(const std::string& serverAddress, ChannelMap& channelMap) -{ - LOG(logLevelDebug, "Discovering channels for server %s", serverAddress.c_str()); - try { - PVStructure::shared_pointer ret = getChannelInfo(serverAddress, "channels", timeout); - PVStringArray::shared_pointer pvs(ret->getSubField("value")); - PVStringArray::const_svector val(pvs->view()); - epicsTimeStamp now; - epicsTimeGetCurrent(&now); - for (unsigned int i = 0; i < val.size(); i++) { - ChannelEntry channelEntry; - channelEntry.channelName = val[i]; - channelEntry.serverAddress = serverAddress; - channelEntry.updateTime = now; - channelMap[val[i]] = channelEntry; - } - LOG(logLevelDebug, "Discovered %ld channels for server %s", val.size(), serverAddress.c_str()); - } - catch(std::exception& e) { - LOG(logLevelError, "Error retrieving channels for server %s: %s", serverAddress.c_str(), e.what()); - } -} - void NameServer::discoverChannels(ServerAddressList& serverAddressList, ChannelMap& channelMap) { LOG(logLevelDebug, "Discovering channels for %ld servers", serverAddressList.size()); diff --git a/pvtoolsSrc/nameServer.h b/src/server/pv/nameServer.h similarity index 77% rename from pvtoolsSrc/nameServer.h rename to src/server/pv/nameServer.h index b9071ede..8ba8c326 100644 --- a/pvtoolsSrc/nameServer.h +++ b/src/server/pv/nameServer.h @@ -3,22 +3,24 @@ #include #include + +#ifdef epicsExportSharedSymbols +# define nameServerEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + #include +#include #include -#include "pvutils.h" -namespace epics { namespace pvAccess { +#ifdef nameServerEpicsExportSharedSymbols +# define epicsExportSharedSymbols +# undef nameServerEpicsExportSharedSymbols +#endif -/* - * Name server channel entry - */ -struct ChannelEntry { - std::string channelName; - std::string serverAddress; - epicsTimeStamp updateTime; -}; -typedef std::map ChannelMap; -typedef std::list ServerAddressList; +#include + +namespace epics { namespace pvAccess { class NameServerChannelFindRequesterImpl : public ChannelFindRequester @@ -125,47 +127,50 @@ class NameServerChannelProvider virtual ChannelFind::shared_pointer channelList(const ChannelListRequester::shared_pointer& channelListRequester); virtual Channel::shared_pointer createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short priority); virtual Channel::shared_pointer createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short /*priority*/, const std::string& address); - void updateChannelMap(const ChannelMap& updatedChannelMap); + void updateChannelMap(const ChannelDiscovery::ChannelMap& updatedChannelMap); std::string getChannelServerAddress(const std::string& channelName); void setChannelEntryExpirationTime(double expirationTime); - void setStaticChannelEntries(const ChannelMap& channelMap); + void setStaticChannelEntries(const ChannelDiscovery::ChannelMap& channelMap); private: ChannelFind::shared_pointer nsChannelFind; mutable epics::pvData::Mutex channelMapMutex; - ChannelMap channelMap; + ChannelDiscovery::ChannelMap channelMap; double channelEntryExpirationTime; }; -class NameServer +class epicsShareClass NameServer : public std::tr1::enable_shared_from_this { public: POINTER_DEFINITIONS(NameServer); NameServer(const epics::pvAccess::Configuration::shared_pointer& conf); virtual ~NameServer(); - void setPollPeriod(double pollPeriod); - void setPvaTimeout(double timeout); - void setAutoDiscovery(bool autoDiscovery); - void setStaticServerAddresses(const std::string& serverAddresses); - void setStaticChannelEntries(const ChannelMap& channelMap); - void setChannelEntryExpirationTime(double expirationTime); - void run(double runtime); -private: + virtual void setPollPeriod(double pollPeriod); + virtual void setPvaTimeout(double timeout); + virtual void setAutoDiscovery(bool autoDiscovery); + virtual void setStaticServerAddresses(const std::string& serverAddresses); + virtual void setStaticChannelEntries(const ChannelDiscovery::ChannelMap& channelMap); + virtual void setChannelEntryExpirationTime(double expirationTime); + virtual void run(double runtime); + + virtual bool addUniqueServerToList(const std::string& serverAddress, ChannelDiscovery::ServerAddressList& serverAddressList); + virtual void addServersFromAddresses(ChannelDiscovery::ServerAddressList& serverAddressList); + virtual void discoverChannels(ChannelDiscovery::ServerAddressList& serverAddressList, ChannelDiscovery::ChannelMap& channelMap); + virtual void shutdown(); + + virtual void discoverServers(ChannelDiscovery::ServerAddressList& serverAddressList) = 0; + virtual void discoverServerChannels(const std::string& serverAddress, ChannelDiscovery::ChannelMap& channelMap) = 0; + + +protected: ServerContextImpl::shared_pointer context; NameServerChannelProvider::shared_pointer channelProvider; double pollPeriod; double timeout; bool autoDiscovery; std::string serverAddresses; - - bool addUniqueServerToList(const std::string& serverAddress, ServerAddressList& serverAddressList); - void addServersFromAddresses(ServerAddressList& serverAddressList); - void discoverServers(ServerAddressList& serverAddressList); - void discoverServerChannels(const std::string& serverAddress, ChannelMap& channelMap); - void discoverChannels(ServerAddressList& serverAddressList, ChannelMap& channelMap); - void shutdown(); }; }} diff --git a/src/utils/Makefile b/src/utils/Makefile index 95d57ef3..ca46b0cb 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -13,6 +13,7 @@ INC += pv/fairQueue.h INC += pv/requester.h INC += pv/destroyable.h INC += pv/stringUtility.h +INC += pv/channelDiscovery.h pvAccess_SRCS += getgroups.cpp pvAccess_SRCS += hexDump.cpp @@ -24,3 +25,4 @@ pvAccess_SRCS += referenceCountingLock.cpp pvAccess_SRCS += requester.cpp pvAccess_SRCS += wildcard.cpp pvAccess_SRCS += stringUtility.cpp +pvAccess_SRCS += channelDiscovery.cpp diff --git a/src/utils/channelDiscovery.cpp b/src/utils/channelDiscovery.cpp new file mode 100644 index 00000000..4f69188f --- /dev/null +++ b/src/utils/channelDiscovery.cpp @@ -0,0 +1,27 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvAccessCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#define epicsExportSharedSymbols +#include "pv/channelDiscovery.h" + +namespace epics { namespace pvAccess { namespace ChannelDiscovery { + +ChannelEntry::ChannelEntry() +{ +} + +ChannelEntry::ChannelEntry(const std::string& channelName_, const std::string& serverAddress_, const epicsTimeStamp& updateTime_) + : channelName(channelName_) + , serverAddress(serverAddress_) + , updateTime(updateTime_) +{ +} + +ChannelEntry::~ChannelEntry() +{ +} + +}}} diff --git a/src/utils/pv/channelDiscovery.h b/src/utils/pv/channelDiscovery.h new file mode 100644 index 00000000..82497e9e --- /dev/null +++ b/src/utils/pv/channelDiscovery.h @@ -0,0 +1,45 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvAccessCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#ifndef CHANNEL_DISCOVERY_H +#define CHANNEL_DISCOVERY_H + +#include +#include +#include + +#ifdef epicsExportSharedSymbols +# define channelDiscoveryEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#include + +#ifdef channelDiscoveryEpicsExportSharedSymbols +# define epicsExportSharedSymbols +# undef channelDiscoveryEpicsExportSharedSymbols +#endif +#include + +namespace epics { namespace pvAccess { namespace ChannelDiscovery { + +/* + * Name server channel entry + */ +struct epicsShareClass ChannelEntry { + ChannelEntry(); + ChannelEntry(const std::string& channelName, const std::string& serverAddress, const epicsTimeStamp& updateTime); + virtual ~ChannelEntry(); + std::string channelName; + std::string serverAddress; + epicsTimeStamp updateTime; +}; +typedef std::map ChannelMap; +typedef std::list ServerAddressList; + +}}} + +#endif From 249e7f0fcfbec6aa7068076bb62fc7548088b775 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 25 Mar 2024 10:19:35 -0500 Subject: [PATCH 39/82] fix build on older gcc version --- src/server/nameServer.cpp | 4 ++-- src/server/pv/nameServer.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/server/nameServer.cpp b/src/server/nameServer.cpp index 134456f0..2fca8309 100644 --- a/src/server/nameServer.cpp +++ b/src/server/nameServer.cpp @@ -281,11 +281,11 @@ void NameServerSearchHandler::handleResponse(osiSockAddr* responseFrom, const Tr LOG(logLevelDebug, "Search for channel %s, cid %d", name.c_str(), cid); if (allowed) { const std::vector& providers = _context->getChannelProviders(); - int providerCount = providers.size(); + unsigned int providerCount = providers.size(); std::tr1::shared_ptr channelFindRequester(new NameServerChannelFindRequesterImpl(_context, info, providerCount)); channelFindRequester->set(name, searchSequenceId, cid, responseAddress, transport, responseRequired, false); - for (int i = 0; i < providerCount; i++) { + for (unsigned int i = 0; i < providerCount; i++) { providers[i]->channelFind(name, channelFindRequester); } } diff --git a/src/server/pv/nameServer.h b/src/server/pv/nameServer.h index 8ba8c326..d8763fdd 100644 --- a/src/server/pv/nameServer.h +++ b/src/server/pv/nameServer.h @@ -140,7 +140,6 @@ class NameServerChannelProvider }; class epicsShareClass NameServer - : public std::tr1::enable_shared_from_this { public: POINTER_DEFINITIONS(NameServer); From 56f504ac0281743dfddcc533da4686a735802be9 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 25 Mar 2024 16:19:19 -0500 Subject: [PATCH 40/82] fixes for mingw builds --- pvtoolsSrc/nameServerImpl.cpp | 3 +-- src/server/nameServer.cpp | 6 ++++-- src/server/pv/nameServer.h | 12 ++---------- src/utils/pv/channelDiscovery.h | 10 ---------- 4 files changed, 7 insertions(+), 24 deletions(-) diff --git a/pvtoolsSrc/nameServerImpl.cpp b/pvtoolsSrc/nameServerImpl.cpp index b56afabd..a89e1021 100644 --- a/pvtoolsSrc/nameServerImpl.cpp +++ b/pvtoolsSrc/nameServerImpl.cpp @@ -38,8 +38,7 @@ void NameServerImpl::discoverServers(ServerAddressList& serverAddressList) } LOG(logLevelDebug, "Starting server discovery"); - ServerGUID guid = context->getGUID(); - std::string nsGuid = ::toHex((int8*)guid.value, sizeof(guid.value)); + std::string nsGuid = ::toHex((int8*)nameServerGuid.value, sizeof(nameServerGuid.value)); ServerMap serverMap; ::discoverServers(timeout, serverMap); diff --git a/src/server/nameServer.cpp b/src/server/nameServer.cpp index 2fca8309..581626a4 100644 --- a/src/server/nameServer.cpp +++ b/src/server/nameServer.cpp @@ -5,10 +5,11 @@ */ -#include -#include #define epicsExportSharedSymbols +#include +#include +#include #include "pv/nameServer.h" using namespace std; @@ -535,6 +536,7 @@ NameServer::NameServer(const epics::pvAccess::Configuration::shared_pointer& con context = ServerContextImpl::create(serverConfig); ResponseHandler::shared_pointer searchResponseHandler(new NameServerSearchResponseHandler(context)); context->initialize(searchResponseHandler, searchResponseHandler); + nameServerGuid = context->getGUID(); } NameServer::~NameServer() diff --git a/src/server/pv/nameServer.h b/src/server/pv/nameServer.h index d8763fdd..b45f4d48 100644 --- a/src/server/pv/nameServer.h +++ b/src/server/pv/nameServer.h @@ -4,19 +4,10 @@ #include #include -#ifdef epicsExportSharedSymbols -# define nameServerEpicsExportSharedSymbols -# undef epicsExportSharedSymbols -#endif - #include #include #include - -#ifdef nameServerEpicsExportSharedSymbols -# define epicsExportSharedSymbols -# undef nameServerEpicsExportSharedSymbols -#endif +#include #include @@ -165,6 +156,7 @@ class epicsShareClass NameServer protected: ServerContextImpl::shared_pointer context; + ServerGUID nameServerGuid; NameServerChannelProvider::shared_pointer channelProvider; double pollPeriod; double timeout; diff --git a/src/utils/pv/channelDiscovery.h b/src/utils/pv/channelDiscovery.h index 82497e9e..d68b2e37 100644 --- a/src/utils/pv/channelDiscovery.h +++ b/src/utils/pv/channelDiscovery.h @@ -11,17 +11,7 @@ #include #include -#ifdef epicsExportSharedSymbols -# define channelDiscoveryEpicsExportSharedSymbols -# undef epicsExportSharedSymbols -#endif - #include - -#ifdef channelDiscoveryEpicsExportSharedSymbols -# define epicsExportSharedSymbols -# undef channelDiscoveryEpicsExportSharedSymbols -#endif #include namespace epics { namespace pvAccess { namespace ChannelDiscovery { From 0e237d91d7bacb3506372a01585ea3873d6d63b0 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 25 Mar 2024 16:38:38 -0500 Subject: [PATCH 41/82] fix few log formats --- src/remote/blockingUDPTransport.cpp | 8 ++++---- src/remote/channelSearchManager.cpp | 2 +- src/remote/codec.cpp | 4 ++-- src/remote/transportRegistry.cpp | 2 +- src/server/nameServer.cpp | 4 ++-- src/server/responseHandlers.cpp | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/remote/blockingUDPTransport.cpp b/src/remote/blockingUDPTransport.cpp index 8ca95b8f..73c95119 100644 --- a/src/remote/blockingUDPTransport.cpp +++ b/src/remote/blockingUDPTransport.cpp @@ -435,7 +435,7 @@ bool BlockingUDPTransport::send(const char* buffer, size_t length, const osiSock { if (IS_LOGGABLE(logLevelDebug)) { - LOG(logLevelDebug, "UDP Tx (%zu) %s -> %s.", + LOG(logLevelDebug, "UDP Tx (%lu) %s -> %s.", length, _remoteName.c_str(), inetAddressToString(address).c_str()); } @@ -460,7 +460,7 @@ bool BlockingUDPTransport::send(ByteBuffer* buffer, const osiSockAddr& address) if (IS_LOGGABLE(logLevelDebug)) { - LOG(logLevelDebug, "Sending %zu bytes %s -> %s.", + LOG(logLevelDebug, "Sending %lu bytes %s -> %s.", buffer->getRemaining(), _remoteName.c_str(), inetAddressToString(address).c_str()); } @@ -498,7 +498,7 @@ bool BlockingUDPTransport::send(ByteBuffer* buffer, InetAddressType target) { if (IS_LOGGABLE(logLevelDebug)) { - LOG(logLevelDebug, "Sending %zu bytes %s -> %s.", + LOG(logLevelDebug, "Sending %lu bytes %s -> %s.", buffer->getRemaining(), _remoteName.c_str(), inetAddressToString(_sendAddresses[i]).c_str()); } @@ -685,7 +685,7 @@ void initializeUDPTransports(bool serverFlag, } } LOG(logLevelDebug, - "Broadcast address #%zu: %s. (%sunicast)", i, inetAddressToString(list[i]).c_str(), + "Broadcast address #%lu: %s. (%sunicast)", i, inetAddressToString(list[i]).c_str(), isunicast[i]?"":"not "); } diff --git a/src/remote/channelSearchManager.cpp b/src/remote/channelSearchManager.cpp index 5290b479..3594d987 100644 --- a/src/remote/channelSearchManager.cpp +++ b/src/remote/channelSearchManager.cpp @@ -301,7 +301,7 @@ void ChannelSearchManager::flushSendBuffer() Transport::shared_pointer nsTransport = m_context.lock()->getNameServerSearchTransport(); if(nsTransport) { - LOG(logLevelDebug, "Initiating name server search for %lu channels", m_channels.size()); + LOG(logLevelDebug, "Initiating name server search for %d channels", int(m_channels.size())); nsTransport->enqueueSendRequest(shared_from_this()); } initializeSendBuffer(); diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 3e61f075..fa99e292 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -1611,7 +1611,7 @@ void BlockingServerTCPTransportCodec::destroyAllChannels() { { LOG( logLevelDebug, - "Transport to %s still has %zu channel(s) active and closing...", + "Transport to %s still has %lu channel(s) active and closing...", _socketName.c_str(), _channels.size()); } @@ -1792,7 +1792,7 @@ void BlockingClientTCPTransportCodec::internalClose() { { LOG( logLevelDebug, - "Transport to %s still has %zu client(s) active and closing...", + "Transport to %s still has %lu client(s) active and closing...", _socketName.c_str(), refs); } diff --git a/src/remote/transportRegistry.cpp b/src/remote/transportRegistry.cpp index 13fdc24e..5b83088b 100644 --- a/src/remote/transportRegistry.cpp +++ b/src/remote/transportRegistry.cpp @@ -127,7 +127,7 @@ void TransportRegistry::clear() if(temp.empty()) return; - LOG(logLevelDebug, "Context still has %zu transport(s) active and closing...", temp.size()); + LOG(logLevelDebug, "Context still has %lu transport(s) active and closing...", temp.size()); for(transports_t::iterator it(temp.begin()), end(temp.end()); it != end; ++it) diff --git a/src/server/nameServer.cpp b/src/server/nameServer.cpp index 581626a4..cf2ff256 100644 --- a/src/server/nameServer.cpp +++ b/src/server/nameServer.cpp @@ -433,7 +433,7 @@ void NameServerChannelProvider::setStaticChannelEntries(const ChannelMap& channe ChannelEntry channelEntry = it->second; this->channelMap[channelName] = channelEntry; } - LOG(logLevelDebug, "Updated %ld static channel entries", channelMap.size()); + LOG(logLevelDebug, "Updated %d static channel entries", int(channelMap.size())); } std::string NameServerChannelProvider::NameServerChannelProvider::getProviderName() @@ -629,7 +629,7 @@ void NameServer::addServersFromAddresses(ServerAddressList& serverAddressList) void NameServer::discoverChannels(ServerAddressList& serverAddressList, ChannelMap& channelMap) { - LOG(logLevelDebug, "Discovering channels for %ld servers", serverAddressList.size()); + LOG(logLevelDebug, "Discovering channels for %d servers", int(serverAddressList.size())); for (ServerAddressList::const_iterator it = serverAddressList.begin(); it != serverAddressList.end(); it++) { std::string serverAddress = *it; discoverServerChannels(serverAddress, channelMap); diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 588cbe72..0748c0c2 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -2114,7 +2114,7 @@ void ServerMonitorRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* // This really shouldn't happen as the above ensures that _window_open *was* non-zero, // and only we (the sender) will decrement. message("Monitor Logic Error: send outside of window", epics::pvData::warningMessage); - LOG(logLevelError, "Monitor Logic Error: send outside of window %zu", _window_closed.size()); + LOG(logLevelError, "Monitor Logic Error: send outside of window %lu", _window_closed.size()); } else { _window_closed.push_back(element.letGo()); From 1007a9c30719d6308a64477ae57e1309e9c3cc98 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 25 Mar 2024 19:47:51 -0500 Subject: [PATCH 42/82] fix few codacy complaints; avoid duplicate symbold on rtems --- pvtoolsSrc/nameServerImpl.cpp | 2 +- pvtoolsSrc/pvutils.cpp | 2 +- src/server/nameServer.cpp | 12 +++++++----- src/server/pv/nameServer.h | 2 +- testApp/remote/Makefile | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pvtoolsSrc/nameServerImpl.cpp b/pvtoolsSrc/nameServerImpl.cpp index a89e1021..a744634a 100644 --- a/pvtoolsSrc/nameServerImpl.cpp +++ b/pvtoolsSrc/nameServerImpl.cpp @@ -43,7 +43,7 @@ void NameServerImpl::discoverServers(ServerAddressList& serverAddressList) ::discoverServers(timeout, serverMap); int nDiscoveredServers = 0; - for (ServerMap::const_iterator it = serverMap.begin(); it != serverMap.end(); it++) { + for (ServerMap::const_iterator it = serverMap.begin(); it != serverMap.end(); ++it) { const ServerEntry& entry = it->second; if (nsGuid == entry.guid) { LOG(logLevelDebug, "Ignoring our own server GUID 0x%s", entry.guid.c_str()); diff --git a/pvtoolsSrc/pvutils.cpp b/pvtoolsSrc/pvutils.cpp index d097e211..29f03c4f 100644 --- a/pvtoolsSrc/pvutils.cpp +++ b/pvtoolsSrc/pvutils.cpp @@ -261,7 +261,7 @@ bool processSearchResponse(const osiSockAddr& responseFrom, ByteBuffer& receiveB if (iter != serverMapByGuid.end()) { bool found = false; std::vector& vec = iter->second.addresses; - for (std::vector::const_iterator ai = vec.begin(); ai != vec.end(); ai++) { + for (std::vector::const_iterator ai = vec.begin(); ai != vec.end(); ++ai) { if (sockAddrAreIdentical(&(*ai), &serverAddress)) { found = true; break; diff --git a/src/server/nameServer.cpp b/src/server/nameServer.cpp index cf2ff256..84c2d849 100644 --- a/src/server/nameServer.cpp +++ b/src/server/nameServer.cpp @@ -31,6 +31,7 @@ NameServerChannelFindRequesterImpl::NameServerChannelFindRequesterImpl(const Ser , nameServerGuid(context_->getGUID()) , nameServerAddress(inetAddressToString(*(context_->getServerInetAddress()))) , sendTo() + , responseRequired(false) , channelWasFound(false) , context(context_) , peer(peer_) @@ -61,7 +62,7 @@ void NameServerChannelFindRequesterImpl::timerStopped() { } -void NameServerChannelFindRequesterImpl::set(std::string channelName, int32 searchSequenceId, int32 cid, const osiSockAddr& sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch) +void NameServerChannelFindRequesterImpl::set(const std::string& channelName, int32 searchSequenceId, int32 cid, const osiSockAddr& sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch) { Lock lock(mutex); this->channelName = channelName; @@ -407,6 +408,7 @@ const std::string NameServerChannelProvider::PROVIDER_NAME("remote"); NameServerChannelProvider::NameServerChannelProvider() : nsChannelFind() + , channelEntryExpirationTime(0) { } @@ -428,7 +430,7 @@ void NameServerChannelProvider::setChannelEntryExpirationTime(double expirationT void NameServerChannelProvider::setStaticChannelEntries(const ChannelMap& channelMap) { Lock lock(channelMapMutex); - for (ChannelMap::const_iterator it = channelMap.begin(); it != channelMap.end(); it++) { + for (ChannelMap::const_iterator it = channelMap.begin(); it != channelMap.end(); ++it) { std::string channelName = it->first; ChannelEntry channelEntry = it->second; this->channelMap[channelName] = channelEntry; @@ -481,7 +483,7 @@ ChannelFind::shared_pointer NameServerChannelProvider::channelList(const Channel epics::pvData::PVStringArray::svector channelNames; { Lock lock(channelMapMutex); - for (ChannelMap::const_iterator it = channelMap.begin(); it != channelMap.end(); it++) { + for (ChannelMap::const_iterator it = channelMap.begin(); it != channelMap.end(); ++it) { std::string channelName = it->first; channelNames.push_back(channelName); } @@ -506,7 +508,7 @@ Channel::shared_pointer NameServerChannelProvider::createChannel(const std::stri void NameServerChannelProvider::updateChannelMap(const ChannelMap& updatedChannelMap) { Lock lock(channelMapMutex); - for (ChannelMap::const_iterator it = updatedChannelMap.begin(); it != updatedChannelMap.end(); it++) { + for (ChannelMap::const_iterator it = updatedChannelMap.begin(); it != updatedChannelMap.end(); ++it) { std::string channelName = it->first; ChannelEntry channelEntry = it->second; channelMap[channelName] = channelEntry; @@ -630,7 +632,7 @@ void NameServer::addServersFromAddresses(ServerAddressList& serverAddressList) void NameServer::discoverChannels(ServerAddressList& serverAddressList, ChannelMap& channelMap) { LOG(logLevelDebug, "Discovering channels for %d servers", int(serverAddressList.size())); - for (ServerAddressList::const_iterator it = serverAddressList.begin(); it != serverAddressList.end(); it++) { + for (ServerAddressList::const_iterator it = serverAddressList.begin(); it != serverAddressList.end(); ++it) { std::string serverAddress = *it; discoverServerChannels(serverAddress, channelMap); } diff --git a/src/server/pv/nameServer.h b/src/server/pv/nameServer.h index b45f4d48..542ad82e 100644 --- a/src/server/pv/nameServer.h +++ b/src/server/pv/nameServer.h @@ -23,7 +23,7 @@ class NameServerChannelFindRequesterImpl NameServerChannelFindRequesterImpl(const ServerContextImpl::shared_pointer& context, const PeerInfo::const_shared_pointer& peerInfo, epics::pvData::int32 expectedResponseCount); virtual ~NameServerChannelFindRequesterImpl(); void clear(); - void set(std::string channelName, epics::pvData::int32 searchSequenceId, epics::pvData::int32 cid, osiSockAddr const & sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch); + void set(const std::string& channelName, epics::pvData::int32 searchSequenceId, epics::pvData::int32 cid, const osiSockAddr& sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch); virtual void channelFindResult(const epics::pvData::Status& status, const ChannelFind::shared_pointer& channelFind, bool wasFound) OVERRIDE FINAL; virtual std::tr1::shared_ptr getPeerInfo() OVERRIDE FINAL; virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) OVERRIDE FINAL; diff --git a/testApp/remote/Makefile b/testApp/remote/Makefile index 7c349153..76f60dfb 100644 --- a/testApp/remote/Makefile +++ b/testApp/remote/Makefile @@ -15,10 +15,10 @@ TESTPROD_HOST += testDcChannelDiscovery testUdpChannelDiscovery_SRCS = udpChannelDiscoveryTest.cpp testNsChannelDiscovery_SRCS = nsChannelDiscoveryTest.cpp testDcChannelDiscovery_SRCS = dcChannelDiscoveryTest.cpp +ifneq (RTEMS,$(OS_CLASS)) testHarness_SRCS += udpChannelDiscoveryTest.cpp testHarness_SRCS += nsChannelDiscoveryTest.cpp testHarness_SRCS += dcChannelDiscoveryTest.cpp -ifneq (RTEMS,$(OS_CLASS)) TESTS += testUdpChannelDiscovery TESTS += testNsChannelDiscovery TESTS += testDcChannelDiscovery From 8d0135a250659c117c21b46d63d8e1980192b4dc Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 27 Mar 2024 16:59:28 -0500 Subject: [PATCH 43/82] move string constants to pvaConstants --- src/pva/Makefile | 1 + src/pva/pv/pvaConstants.h | 22 +++++++--------------- src/pva/pvaConstants.cpp | 18 ++++++++++++++++++ src/pva/pvaVersion.cpp | 4 ---- src/remote/channelSearchManager.cpp | 4 ++-- src/remote/codec.cpp | 3 --- src/remote/pv/channelSearchManager.h | 11 ----------- src/remote/pv/remote.h | 10 ++-------- src/server/responseHandlers.cpp | 5 ++++- 9 files changed, 34 insertions(+), 44 deletions(-) create mode 100644 src/pva/pvaConstants.cpp diff --git a/src/pva/Makefile b/src/pva/Makefile index 0a030ff9..e538dfce 100644 --- a/src/pva/Makefile +++ b/src/pva/Makefile @@ -8,5 +8,6 @@ INC += pv/pvaVersion.h INC += pv/pvaVersionNum.h INC += pv/clientFactory.h +pvAccess_SRCS += pvaConstants.cpp pvAccess_SRCS += pvaVersion.cpp pvAccess_SRCS += clientFactory.cpp diff --git a/src/pva/pv/pvaConstants.h b/src/pva/pv/pvaConstants.h index c4548991..484589d9 100644 --- a/src/pva/pv/pvaConstants.h +++ b/src/pva/pv/pvaConstants.h @@ -8,22 +8,10 @@ #define PVACONSTANTS_H_ #include - -#ifdef epicsExportSharedSymbols -# define pvaConstantsepicsExportSharedSymbols -# undef epicsExportSharedSymbols -#endif - #include - -#ifdef pvaConstantsepicsExportSharedSymbols -# define epicsExportSharedSymbols -# undef pvaConstantsepicsExportSharedSymbols -#endif #include -namespace epics { -namespace pvAccess { +namespace epics { namespace pvAccess { /** PVA protocol magic number */ const epics::pvData::int8 PVA_MAGIC = static_cast(0xCA); @@ -89,7 +77,11 @@ epicsShareExtern const std::string PVACCESS_ALL_PROVIDERS; /** Name of the system env. variable to turn on debugging. */ epicsShareExtern const std::string PVACCESS_DEBUG; -} -} + +/** Protocol constants. */ +epicsShareExtern const std::string PVA_TCP_PROTOCOL; +epicsShareExtern const std::string PVA_UDP_PROTOCOL; + +}} #endif /* PVACONSTANTS_H_ */ diff --git a/src/pva/pvaConstants.cpp b/src/pva/pvaConstants.cpp new file mode 100644 index 00000000..5f19a4f3 --- /dev/null +++ b/src/pva/pvaConstants.cpp @@ -0,0 +1,18 @@ +/** +* Copyright - See the COPYRIGHT that is included with this distribution. +* pvAccessCPP is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +*/ + +#define epicsExportSharedSymbols +#include + +namespace epics { namespace pvAccess { + +const std::string PVACCESS_DEFAULT_PROVIDER("local"); +const std::string PVACCESS_ALL_PROVIDERS(""); +const std::string PVACCESS_DEBUG("EPICS_PVA_DEBUG"); +const std::string PVA_TCP_PROTOCOL("tcp"); +const std::string PVA_UDP_PROTOCOL("udp"); + +}} diff --git a/src/pva/pvaVersion.cpp b/src/pva/pvaVersion.cpp index 815a3a5d..f15f9fc1 100644 --- a/src/pva/pvaVersion.cpp +++ b/src/pva/pvaVersion.cpp @@ -16,10 +16,6 @@ using std::string; namespace epics { namespace pvAccess { -const std::string PVACCESS_DEFAULT_PROVIDER("local"); -const std::string PVACCESS_ALL_PROVIDERS(""); -const std::string PVACCESS_DEBUG("EPICS_PVA_DEBUG"); - Version::Version(std::string const & productName, std::string const & implementationLangugage, int majorVersion, int minorVersion, diff --git a/src/remote/channelSearchManager.cpp b/src/remote/channelSearchManager.cpp index 3594d987..e9eeffe2 100644 --- a/src/remote/channelSearchManager.cpp +++ b/src/remote/channelSearchManager.cpp @@ -224,7 +224,7 @@ void ChannelSearchManager::send(epics::pvData::ByteBuffer* buffer, TransportSend encodeAsIPv6Address(buffer, &anyAddress); buffer->putShort((int16_t)ntohs(anyAddress.ia.sin_port)); buffer->putByte((int8_t)1); - SerializeHelper::serializeString(PVA_TCP_PROTOCOL, buffer, control); + SerializeHelper::serializeString("tcp", buffer, control); buffer->putShort((int16_t)0); // initial channel count vector toSend; @@ -280,7 +280,7 @@ void ChannelSearchManager::initializeSendBuffer() m_sendBuffer.putByte((int8_t)1); MockTransportSendControl control; - SerializeHelper::serializeString(PVA_TCP_PROTOCOL, &m_sendBuffer, &control); + SerializeHelper::serializeString("tcp", &m_sendBuffer, &control); m_sendBuffer.putShort((int16_t)0); // count } diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index fa99e292..c61900d0 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -58,9 +58,6 @@ struct BreakTransport : TransportSender namespace epics { namespace pvAccess { -const std::string PVA_TCP_PROTOCOL("tcp"); -const std::string PVA_UDP_PROTOCOL("udp"); - /* HACK! * RTEMS allows blocking sockets to be interrupted by shutdown() (aka. esscimqi_socketBothShutdownRequired). * However, a concurrent close() is a race which can leave a send()/recv() call permanently stuck! diff --git a/src/remote/pv/channelSearchManager.h b/src/remote/pv/channelSearchManager.h index 0aa7789a..36ed375f 100644 --- a/src/remote/pv/channelSearchManager.h +++ b/src/remote/pv/channelSearchManager.h @@ -7,18 +7,7 @@ #ifndef CHANNELSEARCHMANAGER_H #define CHANNELSEARCHMANAGER_H -#ifdef epicsExportSharedSymbols -# define channelSearchManagerEpicsExportSharedSymbols -# undef epicsExportSharedSymbols -#endif - #include - -#ifdef channelSearchManagerEpicsExportSharedSymbols -# define epicsExportSharedSymbols -# undef channelSearchManagerEpicsExportSharedSymbols -#endif - #include #include diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 564736c1..86b37b7c 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -23,16 +23,15 @@ #include #include #include +#include #ifdef remoteEpicsExportSharedSymbols # define epicsExportSharedSymbols # undef remoteEpicsExportSharedSymbols #endif -#include #include #include -#include /// TODO only here because of the Lockable #include @@ -40,12 +39,6 @@ namespace epics { namespace pvAccess { -/** - * String constants. - */ -epicsShareExtern const std::string PVA_TCP_PROTOCOL; -epicsShareExtern const std::string PVA_UDP_PROTOCOL; - class TransportRegistry; class ClientChannelImpl; @@ -289,6 +282,7 @@ class epicsShareClass Transport : public epics::pvData::DeserializableControl { class Channel; class SecurityPlugin; class AuthenticationRegistry; +class Configuration; /** * Not public IF, used by Transports, etc. diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 0748c0c2..1803d599 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -298,7 +298,7 @@ void ServerEchoHandler::handleResponse(osiSockAddr* responseFrom, /****************************************************************************************/ -const std::string ServerSearchHandler::SUPPORTED_PROTOCOL = PVA_TCP_PROTOCOL; +const std::string ServerSearchHandler::SUPPORTED_PROTOCOL = "tcp"; ServerSearchHandler::ServerSearchHandler(ServerContextImpl::shared_pointer const & context) : AbstractServerResponseHandler(context, "Search request") @@ -357,12 +357,15 @@ void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, { string protocol = SerializeHelper::deserializeString(payloadBuffer, transport.get()); if (SUPPORTED_PROTOCOL == protocol) + { allowed = true; + } } // NOTE: we do not stop reading the buffer transport->ensureData(2); const int32 count = payloadBuffer->getShort() & 0xFFFF; + LOG(logLevelDebug, "Search request from %s is allowed: %d, payload count is %d", strBuffer, int(allowed), count); // TODO DoS attack? // You bet! With a reply address encoded in the request we don't even need a forged UDP header. From 26ff188e8094b566b2088288da0ef4af01ed7c92 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 27 Mar 2024 17:03:08 -0500 Subject: [PATCH 44/82] include missing header --- src/remote/abstractResponseHandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/remote/abstractResponseHandler.cpp b/src/remote/abstractResponseHandler.cpp index 6b93c320..7d3f1686 100644 --- a/src/remote/abstractResponseHandler.cpp +++ b/src/remote/abstractResponseHandler.cpp @@ -10,6 +10,7 @@ #include #define epicsExportSharedSymbols +#include #include #include From 70e52cfa09aac2c1d2063320b17b9bd69e04fdde Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 27 Mar 2024 20:10:01 -0500 Subject: [PATCH 45/82] fix few log statement formats --- pvtoolsSrc/nameServerImpl.cpp | 2 +- pvtoolsSrc/pvutils.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pvtoolsSrc/nameServerImpl.cpp b/pvtoolsSrc/nameServerImpl.cpp index a744634a..741d41eb 100644 --- a/pvtoolsSrc/nameServerImpl.cpp +++ b/pvtoolsSrc/nameServerImpl.cpp @@ -81,7 +81,7 @@ void NameServerImpl::discoverServerChannels(const std::string& serverAddress, Ch channelEntry.updateTime = now; channelMap[val[i]] = channelEntry; } - LOG(logLevelDebug, "Discovered %ld channels for server %s", val.size(), serverAddress.c_str()); + LOG(logLevelDebug, "Discovered %d channels for server %s", int(val.size()), serverAddress.c_str()); } catch(std::exception& e) { LOG(logLevelError, "Error retrieving channels for server %s: %s", serverAddress.c_str(), e.what()); diff --git a/pvtoolsSrc/pvutils.cpp b/pvtoolsSrc/pvutils.cpp index 29f03c4f..4f00e4a5 100644 --- a/pvtoolsSrc/pvutils.cpp +++ b/pvtoolsSrc/pvutils.cpp @@ -345,7 +345,7 @@ bool discoverServers(double timeOut, ServerMap& serverMapByGuid) } for (size_t i = 0; i < broadcastAddresses.size(); i++) { - LOG(logLevelDebug, "Broadcast address #%zu: %s.", i, inetAddressToString(broadcastAddresses[i]).c_str()); + LOG(logLevelDebug, "Broadcast address #%d: %s.", int(i), inetAddressToString(broadcastAddresses[i]).c_str()); } // --- @@ -431,7 +431,7 @@ bool discoverServers(double timeOut, ServerMap& serverMapByGuid) if(pvAccessIsLoggable(logLevelDebug)) { char strBuffer[64]; sockAddrToDottedIP(&broadcastAddresses[i].sa, strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "UDP Tx (%zu) -> %s", sendBuffer.getPosition(), strBuffer); + LOG(logLevelDebug, "UDP Tx (%lu) -> %s", sendBuffer.getPosition(), strBuffer); } status = ::sendto(socket, sendBuffer.getBuffer(), sendBuffer.getPosition(), 0, From 270b4726fc7ec9d920380c4c811a8c003f1bcf61 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 28 Mar 2024 13:23:05 -0500 Subject: [PATCH 46/82] add diagnostics output for channel discovery tests --- testApp/remote/Makefile | 8 ++++++-- testApp/remote/channelDiscoveryTest.cpp | 19 +++++++++++-------- testApp/remote/channelDiscoveryTest.h | 1 + testApp/remote/dcChannelDiscoveryTest.cpp | 14 ++++++++++++-- testApp/remote/nsChannelDiscoveryTest.cpp | 16 +++++++++++++--- testApp/remote/udpChannelDiscoveryTest.cpp | 20 ++++++++++++++------ 6 files changed, 57 insertions(+), 21 deletions(-) diff --git a/testApp/remote/Makefile b/testApp/remote/Makefile index 76f60dfb..23416c6d 100644 --- a/testApp/remote/Makefile +++ b/testApp/remote/Makefile @@ -10,15 +10,19 @@ TESTS += testChannelAccess endif TESTPROD_HOST += testUdpChannelDiscovery -TESTPROD_HOST += testNsChannelDiscovery -TESTPROD_HOST += testDcChannelDiscovery testUdpChannelDiscovery_SRCS = udpChannelDiscoveryTest.cpp +testUdpChannelDiscovery_SRCS += channelDiscoveryTest.cpp +TESTPROD_HOST += testNsChannelDiscovery testNsChannelDiscovery_SRCS = nsChannelDiscoveryTest.cpp +testNsChannelDiscovery_SRCS += channelDiscoveryTest.cpp +TESTPROD_HOST += testDcChannelDiscovery testDcChannelDiscovery_SRCS = dcChannelDiscoveryTest.cpp +testDcChannelDiscovery_SRCS += channelDiscoveryTest.cpp ifneq (RTEMS,$(OS_CLASS)) testHarness_SRCS += udpChannelDiscoveryTest.cpp testHarness_SRCS += nsChannelDiscoveryTest.cpp testHarness_SRCS += dcChannelDiscoveryTest.cpp +testHarness_SRCS += channelDiscoveryTest.cpp TESTS += testUdpChannelDiscovery TESTS += testNsChannelDiscovery TESTS += testDcChannelDiscovery diff --git a/testApp/remote/channelDiscoveryTest.cpp b/testApp/remote/channelDiscoveryTest.cpp index 4c0ddb3c..d227ef5c 100644 --- a/testApp/remote/channelDiscoveryTest.cpp +++ b/testApp/remote/channelDiscoveryTest.cpp @@ -8,8 +8,6 @@ #include #include -#include -#include #include #include @@ -22,9 +20,14 @@ namespace EPVA = epics::pvAccess; // int value, increment on process const std::string ChannelDiscoveryTest::TEST_SIMPLECOUNTER_CHANNEL_NAME = "testSimpleCounter"; -int ChannelDiscoveryTest::runAllTests() { +int ChannelDiscoveryTest::getNumberOfTests() +{ + return 1; +} - testPlan(1); +int ChannelDiscoveryTest::runAllTests() +{ + testDiag("Starting channel discovery tests"); m_provider = ChannelProviderRegistry::clients()->getProvider("pva"); test_channelDiscovery(); return testDone(); @@ -32,7 +35,6 @@ int ChannelDiscoveryTest::runAllTests() { Channel::shared_pointer ChannelDiscoveryTest::createChannel(string channelName, bool debug ) { - TR1::shared_ptr channelReq(new SyncChannelRequesterImpl(debug)); Channel::shared_pointer channel = getChannelProvider()->createChannel(channelName, channelReq); return channel; @@ -71,8 +73,8 @@ SyncChannelGetRequesterImpl::shared_pointer ChannelDiscoveryTest::syncCreateChan return channelGetReq; } -void ChannelDiscoveryTest::test_channelGetInt(Channel::shared_pointer channel, - string const & testMethodName) { +void ChannelDiscoveryTest::test_channelGetInt(Channel::shared_pointer channel, string const & testMethodName) +{ string request = "record[process=true]field(value)"; @@ -95,7 +97,8 @@ void ChannelDiscoveryTest::test_channelGetInt(Channel::shared_pointer channel, channel->destroy(); } -void ChannelDiscoveryTest::test_channelDiscovery() { +void ChannelDiscoveryTest::test_channelDiscovery() +{ testDiag("BEGIN TEST %s:", CURRENT_FUNCTION); Channel::shared_pointer channel = syncCreateChannel(TEST_SIMPLECOUNTER_CHANNEL_NAME); if (!channel.get()) { diff --git a/testApp/remote/channelDiscoveryTest.h b/testApp/remote/channelDiscoveryTest.h index f3660e08..7405e3cc 100644 --- a/testApp/remote/channelDiscoveryTest.h +++ b/testApp/remote/channelDiscoveryTest.h @@ -8,6 +8,7 @@ class ChannelDiscoveryTest { public: + int getNumberOfTests(); int runAllTests(); virtual ~ChannelDiscoveryTest() {} diff --git a/testApp/remote/dcChannelDiscoveryTest.cpp b/testApp/remote/dcChannelDiscoveryTest.cpp index 9ed67b87..bed72d4f 100644 --- a/testApp/remote/dcChannelDiscoveryTest.cpp +++ b/testApp/remote/dcChannelDiscoveryTest.cpp @@ -9,8 +9,10 @@ #include #include +#include +#include -#include "channelDiscoveryTest.cpp" +#include "channelDiscoveryTest.h" #define TESTSERVERNOMAIN #include "testServer.cpp" @@ -19,6 +21,9 @@ namespace EPVA = epics::pvAccess; int runAllTests() { + ChannelDiscoveryTest cdTest; + testPlan(cdTest.getNumberOfTests()); + testDiag("Channel discovery type: direct connection"); EPVA::Configuration::shared_pointer baseConfig(ConfigurationBuilder() .add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1") @@ -35,6 +40,11 @@ int runAllTests() { TestServer::shared_pointer testServer(new TestServer(serverConfig)); std::ostringstream portStr; portStr << "127.0.0.1:" << testServer->getServerPort(); + testDiag("Test server is using ports TCP: %u, TCP Search: %u, UDP Broadcast: %u", + testServer->getServerPort(), + testServer->getSearchServerPort(), + testServer->getBroadcastPort()); + EPVA::Configuration::shared_pointer clientConfig(ConfigurationBuilder() .push_config(baseConfig) .add("EPICS_PVA_ADDR_LIST", portStr.str()) @@ -42,9 +52,9 @@ int runAllTests() { .build()); ConfigurationFactory::registerConfiguration("pvAccess-client", clientConfig); + testDiag("Starting client factory"); epics::pvAccess::ClientFactory::start(); - ChannelDiscoveryTest cdTest; return cdTest.runAllTests(); } diff --git a/testApp/remote/nsChannelDiscoveryTest.cpp b/testApp/remote/nsChannelDiscoveryTest.cpp index bc2b3d69..f8cfdf0a 100644 --- a/testApp/remote/nsChannelDiscoveryTest.cpp +++ b/testApp/remote/nsChannelDiscoveryTest.cpp @@ -9,8 +9,10 @@ #include #include +#include +#include -#include "channelDiscoveryTest.cpp" +#include "channelDiscoveryTest.h" #define TESTSERVERNOMAIN #include "testServer.cpp" @@ -19,7 +21,10 @@ namespace EPVA = epics::pvAccess; int runAllTests() { + ChannelDiscoveryTest cdTest; + testPlan(cdTest.getNumberOfTests()); + testDiag("Channel discovery type: TCP (name server) search"); EPVA::Configuration::shared_pointer baseConfig(ConfigurationBuilder() .add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1") .add("EPICS_PVA_SERVER_PORT", "0") @@ -35,6 +40,11 @@ int runAllTests() { TestServer::shared_pointer testServer(new TestServer(serverConfig)); std::ostringstream portStr; portStr << "127.0.0.1:" << testServer->getSearchServerPort(); + testDiag("Test server is using ports TCP: %u, TCP Search: %u, UDP Broadcast: %u", + testServer->getServerPort(), + testServer->getSearchServerPort(), + testServer->getBroadcastPort()); + EPVA::Configuration::shared_pointer clientConfig(ConfigurationBuilder() .push_config(baseConfig) .add("EPICS_PVA_NAME_SERVERS", portStr.str()) @@ -42,16 +52,16 @@ int runAllTests() { .build()); ConfigurationFactory::registerConfiguration("pvAccess-client", clientConfig); + testDiag("Starting client factory"); epics::pvAccess::ClientFactory::start(); - ChannelDiscoveryTest cdTest; return cdTest.runAllTests(); } MAIN(testNsChannelDiscovery) { try{ - SET_LOG_LEVEL(logLevelError); + SET_LOG_LEVEL(logLevelDebug); return runAllTests(); } catch(std::exception& e) { diff --git a/testApp/remote/udpChannelDiscoveryTest.cpp b/testApp/remote/udpChannelDiscoveryTest.cpp index be26d76a..fa4e6e2a 100644 --- a/testApp/remote/udpChannelDiscoveryTest.cpp +++ b/testApp/remote/udpChannelDiscoveryTest.cpp @@ -8,8 +8,10 @@ #include #include +#include +#include -#include "channelDiscoveryTest.cpp" +#include "channelDiscoveryTest.h" #define TESTSERVERNOMAIN #include "testServer.cpp" @@ -18,11 +20,13 @@ namespace EPVA = epics::pvAccess; int runAllTests() { + ChannelDiscoveryTest cdTest; + testPlan(cdTest.getNumberOfTests()); + testDiag("Channel discovery type: UDP search"); EPVA::Configuration::shared_pointer baseConfig(ConfigurationBuilder() + //.add("EPICS_PVA_DEBUG", "3") .add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1") - .add("EPICS_PVA_ADDR_LIST", "127.0.0.1") - .add("EPICS_PVA_AUTO_ADDR_LIST","0") .add("EPICS_PVA_SERVER_PORT", "0") .add("EPICS_PVA_BROADCAST_PORT", "0") .push_map() @@ -34,6 +38,11 @@ int runAllTests() { .build()); TestServer::shared_pointer testServer(new TestServer(serverConfig)); + testDiag("Test server is using ports TCP: %u, TCP Search: %u, UDP Broadcast: %u", + testServer->getServerPort(), + testServer->getSearchServerPort(), + testServer->getBroadcastPort()); + EPVA::Configuration::shared_pointer clientConfig(ConfigurationBuilder() .push_config(baseConfig) .add("EPICS_PVA_BROADCAST_PORT", testServer->getBroadcastPort()) @@ -41,16 +50,15 @@ int runAllTests() { .build()); ConfigurationFactory::registerConfiguration("pvAccess-client", clientConfig); + testDiag("Starting client factory"); epics::pvAccess::ClientFactory::start(); - - ChannelDiscoveryTest cdTest; return cdTest.runAllTests(); } MAIN(testUdpChannelDiscovery) { try{ - SET_LOG_LEVEL(logLevelError); + SET_LOG_LEVEL(logLevelDebug); return runAllTests(); } catch(std::exception& e) { From 32231429845d3022d42e3f7896f75d302c859347 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 28 Mar 2024 15:22:38 -0500 Subject: [PATCH 47/82] initialize udp sender port --- src/remoteClient/clientContextImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 8da953eb..58efbc2b 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -4082,7 +4082,7 @@ class InternalClientContextImpl : InternalClientContextImpl(const Configuration::shared_pointer& conf) : m_addressList(""), m_autoAddressList(true), m_serverPort(PVA_SERVER_PORT), m_nsAddressList(""), m_nsAddressIndex(0), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), - m_broadcastPort(PVA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), + m_broadcastPort(PVA_BROADCAST_PORT), m_senderPort(PVA_UDP_SENDER_PORT), m_receiveBufferSize(MAX_TCP_RECV), m_lastCID(0x10203040), m_lastIOID(0x80706050), m_version("pvAccess Client", "cpp", From 278e24a09053f50357f4009cd281e7a938bd75b7 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 28 Mar 2024 15:23:40 -0500 Subject: [PATCH 48/82] add more diagnostics --- src/server/responseHandlers.cpp | 2 +- testApp/remote/channelAccessIFTest.cpp | 2 +- testApp/remote/udpChannelDiscoveryTest.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 1803d599..b580c20a 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -557,7 +557,7 @@ void ServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendContr { char ipAddrStr[24]; ipAddrToDottedIP(&_sendTo.ia, ipAddrStr, sizeof(ipAddrStr)); - LOG(logLevelDebug, "Search response will be sent to %s", ipAddrStr); + LOG(logLevelDebug, "Search response will be sent to %s, was found: %d", ipAddrStr, int(_wasFound)); control->startMessage(CMD_SEARCH_RESPONSE, 12+4+16+2); Lock guard(_mutex); diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index 97f545ce..46975c31 100644 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -2409,7 +2409,7 @@ PVStructure::shared_pointer ChannelAccessIFTest::createArrayPvRequest() { MAIN(testChannelAccess) { try{ - SET_LOG_LEVEL(logLevelError); + SET_LOG_LEVEL(logLevelDebug); ChannelAccessIFTest caRemoteTest; return caRemoteTest.runAllTest(); }catch(std::exception& e){ diff --git a/testApp/remote/udpChannelDiscoveryTest.cpp b/testApp/remote/udpChannelDiscoveryTest.cpp index fa4e6e2a..9b49606c 100644 --- a/testApp/remote/udpChannelDiscoveryTest.cpp +++ b/testApp/remote/udpChannelDiscoveryTest.cpp @@ -25,8 +25,9 @@ int runAllTests() { testDiag("Channel discovery type: UDP search"); EPVA::Configuration::shared_pointer baseConfig(ConfigurationBuilder() - //.add("EPICS_PVA_DEBUG", "3") .add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1") + .add("EPICS_PVA_ADDR_LIST", "127.0.0.1") + .add("EPICS_PVA_AUTO_ADDR_LIST", "0") .add("EPICS_PVA_SERVER_PORT", "0") .add("EPICS_PVA_BROADCAST_PORT", "0") .push_map() From e75b24a62787b4d3035630af3950786063e643e0 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 28 Mar 2024 16:02:04 -0500 Subject: [PATCH 49/82] prevent direct connection attempt to unknown port --- src/remoteClient/clientContextImpl.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 58efbc2b..e934a6f2 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -3694,9 +3694,15 @@ class InternalClientContextImpl : int index = m_addressIndex % m_addresses.size(); osiSockAddr* serverAddress = &m_addresses[index]; ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); - double delay = (m_addressIndex / m_addresses.size())*STATIC_SEARCH_BASE_DELAY_SEC+STATIC_SEARCH_MIN_DELAY_SEC; - LOG(logLevelDebug, "Scheduling direct channel connection attempt for address %s with delay of %.3f seconds.", strBuffer, delay); - m_context->getTimer()->scheduleAfterDelay(internal_from_this(), delay); + uint16_t port = ntohs(serverAddress->ia.sin_port); + if (port > 0) { + double delay = (m_addressIndex / m_addresses.size())*STATIC_SEARCH_BASE_DELAY_SEC+STATIC_SEARCH_MIN_DELAY_SEC; + LOG(logLevelDebug, "Scheduling direct channel connection attempt for address %s with delay of %.3f seconds.", strBuffer, delay); + m_context->getTimer()->scheduleAfterDelay(internal_from_this(), delay); + } + else { + LOG(logLevelDebug, "Cannot schedule direct channel connection attempt for address %s (port not specified).", strBuffer); + } } m_context->getChannelSearchManager()->registerSearchInstance(internal_from_this(), penalize); } From 7b4604dd9190b556904e58897f801373aaf1dd25 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 28 Mar 2024 16:38:24 -0500 Subject: [PATCH 50/82] restore logging level --- testApp/remote/channelAccessIFTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index 46975c31..97f545ce 100644 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -2409,7 +2409,7 @@ PVStructure::shared_pointer ChannelAccessIFTest::createArrayPvRequest() { MAIN(testChannelAccess) { try{ - SET_LOG_LEVEL(logLevelDebug); + SET_LOG_LEVEL(logLevelError); ChannelAccessIFTest caRemoteTest; return caRemoteTest.runAllTest(); }catch(std::exception& e){ From c9e23d140f6b5ce892b298a0d71ab46acb22cdda Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 29 Mar 2024 10:34:02 -0500 Subject: [PATCH 51/82] resolve codacy complaints --- pvtoolsSrc/nameServerImpl.cpp | 2 +- pvtoolsSrc/pvutils.cpp | 16 ++++++++-------- pvtoolsSrc/pvutils.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pvtoolsSrc/nameServerImpl.cpp b/pvtoolsSrc/nameServerImpl.cpp index 741d41eb..cd27b64b 100644 --- a/pvtoolsSrc/nameServerImpl.cpp +++ b/pvtoolsSrc/nameServerImpl.cpp @@ -38,7 +38,7 @@ void NameServerImpl::discoverServers(ServerAddressList& serverAddressList) } LOG(logLevelDebug, "Starting server discovery"); - std::string nsGuid = ::toHex((int8*)nameServerGuid.value, sizeof(nameServerGuid.value)); + std::string nsGuid = ::toHex(nameServerGuid.value, sizeof(nameServerGuid.value)); ServerMap serverMap; ::discoverServers(timeout, serverMap); diff --git a/pvtoolsSrc/pvutils.cpp b/pvtoolsSrc/pvutils.cpp index 4f00e4a5..d07a1642 100644 --- a/pvtoolsSrc/pvutils.cpp +++ b/pvtoolsSrc/pvutils.cpp @@ -134,7 +134,7 @@ void jarray(pvd::shared_vector& out, const char *inp) } // Get hex representation of byte. -std::string toHex(int8* ba, size_t len) +std::string toHex(char ba[], size_t len) { // Byte to hexchar mapping. static const char lookup[] = { @@ -146,7 +146,7 @@ std::string toHex(int8* ba, size_t len) for (size_t i = 0; i < len; i++) { - int8 b = ba[i]; + char b = ba[i]; int upper = (b>>4)&0x0F; sb += lookup[upper]; @@ -255,7 +255,7 @@ bool processSearchResponse(const osiSockAddr& responseFrom, ByteBuffer& receiveB /*bool found =*/ receiveBuffer.getByte(); // != 0; - std::string guidString = toHex((int8*)guid.value, sizeof(guid.value)); + std::string guidString = toHex(guid.value, sizeof(guid.value)); ServerMap::iterator iter = serverMapByGuid.find(guidString); if (iter != serverMapByGuid.end()) { @@ -351,7 +351,7 @@ bool discoverServers(double timeOut, ServerMap& serverMapByGuid) // --- int optval = 1; - int status = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)); + int status = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)); if (status) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); @@ -366,7 +366,7 @@ bool discoverServers(double timeOut, ServerMap& serverMapByGuid) bindAddr.ia.sin_port = htons(0); bindAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY); - status = ::bind(socket, (sockaddr*)&(bindAddr.sa), sizeof(sockaddr)); + status = ::bind(socket, static_cast(&bindAddr.sa), sizeof(sockaddr)); if (status) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); @@ -386,7 +386,7 @@ bool discoverServers(double timeOut, ServerMap& serverMapByGuid) timeout.tv_usec = 250000; #endif status = ::setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, - (char*)&timeout, sizeof(timeout)); + &timeout, sizeof(timeout)); if (status) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); @@ -462,9 +462,9 @@ bool discoverServers(double timeOut, ServerMap& serverMapByGuid) receiveBuffer.clear(); // receive packet from socket - int bytesRead = ::recvfrom(socket, (char*)receiveBuffer.getBuffer(), + int bytesRead = ::recvfrom(socket, const_cast(receiveBuffer.getBuffer()), receiveBuffer.getRemaining(), 0, - (sockaddr*)&fromAddress, &addrStructSize); + static_cast(&fromAddress.sa), &addrStructSize); if (bytesRead > 0) { if(pvAccessIsLoggable(logLevelDebug)) { diff --git a/pvtoolsSrc/pvutils.h b/pvtoolsSrc/pvutils.h index bd90bede..f0211033 100644 --- a/pvtoolsSrc/pvutils.h +++ b/pvtoolsSrc/pvutils.h @@ -85,7 +85,7 @@ struct ServerEntry { typedef std::map ServerMap; void jarray(pvd::shared_vector& out, const char *inp); -std::string toHex(pvd::int8* ba, size_t len); +std::string toHex(char ba[], size_t len); std::size_t readSize(pvd::ByteBuffer* buffer); std::string deserializeString(pvd::ByteBuffer* buffer); bool processSearchResponse(const osiSockAddr& responseFrom, pvd::ByteBuffer& receiveBuffer, ServerMap& serverMapByGuid); From bfbde6399caee7a066ece451aeb99af7257b58a7 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 29 Mar 2024 10:35:24 -0500 Subject: [PATCH 52/82] reduce test logging level --- testApp/remote/dcChannelDiscoveryTest.cpp | 2 +- testApp/remote/nsChannelDiscoveryTest.cpp | 2 +- testApp/remote/udpChannelDiscoveryTest.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/testApp/remote/dcChannelDiscoveryTest.cpp b/testApp/remote/dcChannelDiscoveryTest.cpp index bed72d4f..181329be 100644 --- a/testApp/remote/dcChannelDiscoveryTest.cpp +++ b/testApp/remote/dcChannelDiscoveryTest.cpp @@ -61,7 +61,7 @@ int runAllTests() { MAIN(testDcChannelDiscovery) { try{ - SET_LOG_LEVEL(logLevelDebug); + SET_LOG_LEVEL(logLevelError); return runAllTests(); } catch(std::exception& e) { diff --git a/testApp/remote/nsChannelDiscoveryTest.cpp b/testApp/remote/nsChannelDiscoveryTest.cpp index f8cfdf0a..5b075f4e 100644 --- a/testApp/remote/nsChannelDiscoveryTest.cpp +++ b/testApp/remote/nsChannelDiscoveryTest.cpp @@ -61,7 +61,7 @@ int runAllTests() { MAIN(testNsChannelDiscovery) { try{ - SET_LOG_LEVEL(logLevelDebug); + SET_LOG_LEVEL(logLevelError); return runAllTests(); } catch(std::exception& e) { diff --git a/testApp/remote/udpChannelDiscoveryTest.cpp b/testApp/remote/udpChannelDiscoveryTest.cpp index 9b49606c..44b762be 100644 --- a/testApp/remote/udpChannelDiscoveryTest.cpp +++ b/testApp/remote/udpChannelDiscoveryTest.cpp @@ -59,7 +59,7 @@ int runAllTests() { MAIN(testUdpChannelDiscovery) { try{ - SET_LOG_LEVEL(logLevelDebug); + SET_LOG_LEVEL(logLevelError); return runAllTests(); } catch(std::exception& e) { From d14f6d899b8d85bc5b3b1fdcce58b2ead377838f Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 29 Mar 2024 10:51:39 -0500 Subject: [PATCH 53/82] fix setsockopt call for mingw --- pvtoolsSrc/pvutils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvtoolsSrc/pvutils.cpp b/pvtoolsSrc/pvutils.cpp index d07a1642..33f9862e 100644 --- a/pvtoolsSrc/pvutils.cpp +++ b/pvtoolsSrc/pvutils.cpp @@ -351,7 +351,7 @@ bool discoverServers(double timeOut, ServerMap& serverMapByGuid) // --- int optval = 1; - int status = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)); + int status = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&optval), sizeof(optval)); if (status) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); @@ -386,7 +386,7 @@ bool discoverServers(double timeOut, ServerMap& serverMapByGuid) timeout.tv_usec = 250000; #endif status = ::setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, - &timeout, sizeof(timeout)); + reinterpret_cast(&timeout), sizeof(timeout)); if (status) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); From b4a9f7a5380209b225d07c4dd7f6475ebd3d7988 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 29 Mar 2024 13:57:58 -0500 Subject: [PATCH 54/82] add missing 2 bytes --- src/remote/channelSearchManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/remote/channelSearchManager.cpp b/src/remote/channelSearchManager.cpp index e9eeffe2..a87f3aed 100644 --- a/src/remote/channelSearchManager.cpp +++ b/src/remote/channelSearchManager.cpp @@ -210,7 +210,7 @@ void ChannelSearchManager::newServerDetected() void ChannelSearchManager::send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { - control->startMessage(CMD_SEARCH, 4+1+3+16+2+1+4); + control->startMessage(CMD_SEARCH, 4+1+3+16+2+1+4+2); buffer->putInt(m_sequenceNumber); buffer->putByte((int8_t)QOS_REPLY_REQUIRED); // CAST_POSITION buffer->putByte((int8_t)0); // reserved From fc33afbf10437154856f04f33b06746874e57a72 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 29 Mar 2024 14:30:15 -0500 Subject: [PATCH 55/82] revert protocol type back to hardcoded string --- src/remote/pv/blockingUDP.h | 2 +- src/remote/pv/codec.h | 2 +- src/remoteClient/clientContextImpl.cpp | 4 ++-- src/server/nameServer.cpp | 4 ++-- src/server/responseHandlers.cpp | 2 +- src/server/serverContext.cpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index 5746b862..4bbf0bce 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -76,7 +76,7 @@ class BlockingUDPTransport : } virtual std::string getType() const OVERRIDE FINAL { - return PVA_UDP_PROTOCOL; + return "udp"; } virtual std::size_t getReceiveBufferSize() const OVERRIDE FINAL { diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index 0c8495c4..51d390b3 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -303,7 +303,7 @@ class BlockingTCPTransportCodec: virtual void invalidDataStreamHandler() OVERRIDE FINAL; virtual std::string getType() const OVERRIDE FINAL { - return PVA_TCP_PROTOCOL; + return "tcp"; } virtual void processControlMessage() OVERRIDE FINAL { diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index e934a6f2..97b71103 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -2605,7 +2605,7 @@ class SearchResponseHandler : public AbstractClientResponseHandler { bool found = payloadBuffer->getByte() != 0; if (!found) { - if (transport->getType() == PVA_TCP_PROTOCOL) + if (transport->getType() == "tcp") { LOG(logLevelDebug, "No channels found, releasing name server transport"); csm->releaseNameServerTransport(); @@ -2761,7 +2761,7 @@ class BeaconResponseHandler : public AbstractClientResponseHandler { serverAddress.ia.sin_port = htons(port); string protocol(SerializeHelper::deserializeString(payloadBuffer, transport.get())); - if(protocol != PVA_TCP_PROTOCOL) + if(protocol != "tcp") return; // TODO optimize diff --git a/src/server/nameServer.cpp b/src/server/nameServer.cpp index 84c2d849..34541ab7 100644 --- a/src/server/nameServer.cpp +++ b/src/server/nameServer.cpp @@ -103,7 +103,7 @@ void NameServerChannelFindRequesterImpl::channelFindResult(const Status& /*statu channelServerAddress = nsChannelProvider->getChannelServerAddress(channelName); } } - if (transport && transport->getType() == PVA_TCP_PROTOCOL) { + if (transport && transport->getType() == "tcp") { TransportSender::shared_pointer thisSender = shared_from_this(); transport->enqueueSendRequest(thisSender); } @@ -169,7 +169,7 @@ void NameServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendC /* * Name server search handler */ -const std::string NameServerSearchHandler::SUPPORTED_PROTOCOL = PVA_TCP_PROTOCOL; +const std::string NameServerSearchHandler::SUPPORTED_PROTOCOL = "tcp"; NameServerSearchHandler::NameServerSearchHandler(const ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Search request") diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index b580c20a..114bddb9 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -531,7 +531,7 @@ void ServerChannelFindRequesterImpl::channelFindResult(const Status& /*status*/, _context->s_channelNameToProvider[_name] = channelFind->getChannelProvider(); } _wasFound = wasFound; - if (_transport && _transport->getType() == PVA_TCP_PROTOCOL) + if (_transport && _transport->getType() == "tcp") { TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 63c044e9..c465d9e0 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -314,7 +314,7 @@ void ServerContextImpl::initialize(const ResponseHandler::shared_pointer& respon // setup broadcast UDP transport initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, _broadcastPort, _senderPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); - _beaconEmitter.reset(new BeaconEmitter(PVA_TCP_PROTOCOL, _broadcastTransport, thisServerContext)); + _beaconEmitter.reset(new BeaconEmitter("tcp", _broadcastTransport, thisServerContext)); _beaconEmitter->start(); } From 658d57dcc06c1bc6cacac0e3a53a56960920b76f Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 29 Mar 2024 14:44:47 -0500 Subject: [PATCH 56/82] use static cast for %lu format --- src/remote/blockingUDPTransport.cpp | 8 ++++---- src/remote/codec.cpp | 4 ++-- src/remote/transportRegistry.cpp | 2 +- src/server/responseHandlers.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/remote/blockingUDPTransport.cpp b/src/remote/blockingUDPTransport.cpp index 73c95119..f7d2cf9d 100644 --- a/src/remote/blockingUDPTransport.cpp +++ b/src/remote/blockingUDPTransport.cpp @@ -436,7 +436,7 @@ bool BlockingUDPTransport::send(const char* buffer, size_t length, const osiSock if (IS_LOGGABLE(logLevelDebug)) { LOG(logLevelDebug, "UDP Tx (%lu) %s -> %s.", - length, _remoteName.c_str(), inetAddressToString(address).c_str()); + static_cast(length), _remoteName.c_str(), inetAddressToString(address).c_str()); } int retval = sendto(_channel, buffer, @@ -461,7 +461,7 @@ bool BlockingUDPTransport::send(ByteBuffer* buffer, const osiSockAddr& address) if (IS_LOGGABLE(logLevelDebug)) { LOG(logLevelDebug, "Sending %lu bytes %s -> %s.", - buffer->getRemaining(), _remoteName.c_str(), inetAddressToString(address).c_str()); + static_cast(buffer->getRemaining()), _remoteName.c_str(), inetAddressToString(address).c_str()); } int retval = sendto(_channel, buffer->getBuffer(), @@ -499,7 +499,7 @@ bool BlockingUDPTransport::send(ByteBuffer* buffer, InetAddressType target) { if (IS_LOGGABLE(logLevelDebug)) { LOG(logLevelDebug, "Sending %lu bytes %s -> %s.", - buffer->getRemaining(), _remoteName.c_str(), inetAddressToString(_sendAddresses[i]).c_str()); + static_cast(buffer->getRemaining()), _remoteName.c_str(), inetAddressToString(_sendAddresses[i]).c_str()); } int retval = sendto(_channel, buffer->getBuffer(), @@ -685,7 +685,7 @@ void initializeUDPTransports(bool serverFlag, } } LOG(logLevelDebug, - "Broadcast address #%lu: %s. (%sunicast)", i, inetAddressToString(list[i]).c_str(), + "Broadcast address #%lu: %s. (%sunicast)", static_cast(i), inetAddressToString(list[i]).c_str(), isunicast[i]?"":"not "); } diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index c61900d0..e3497de3 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -1609,7 +1609,7 @@ void BlockingServerTCPTransportCodec::destroyAllChannels() { LOG( logLevelDebug, "Transport to %s still has %lu channel(s) active and closing...", - _socketName.c_str(), _channels.size()); + _socketName.c_str(), static_cast(_channels.size())); } _channels_t temp; @@ -1790,7 +1790,7 @@ void BlockingClientTCPTransportCodec::internalClose() { LOG( logLevelDebug, "Transport to %s still has %lu client(s) active and closing...", - _socketName.c_str(), refs); + _socketName.c_str(), static_cast(refs)); } TransportClientMap_t::iterator it = _owners.begin(); diff --git a/src/remote/transportRegistry.cpp b/src/remote/transportRegistry.cpp index 5b83088b..6c32bed9 100644 --- a/src/remote/transportRegistry.cpp +++ b/src/remote/transportRegistry.cpp @@ -127,7 +127,7 @@ void TransportRegistry::clear() if(temp.empty()) return; - LOG(logLevelDebug, "Context still has %lu transport(s) active and closing...", temp.size()); + LOG(logLevelDebug, "Context still has %lu transport(s) active and closing...", static_cast(temp.size())); for(transports_t::iterator it(temp.begin()), end(temp.end()); it != end; ++it) diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 114bddb9..89ded60c 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -2117,7 +2117,7 @@ void ServerMonitorRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* // This really shouldn't happen as the above ensures that _window_open *was* non-zero, // and only we (the sender) will decrement. message("Monitor Logic Error: send outside of window", epics::pvData::warningMessage); - LOG(logLevelError, "Monitor Logic Error: send outside of window %lu", _window_closed.size()); + LOG(logLevelError, "Monitor Logic Error: send outside of window %lu", static_cast(_window_closed.size())); } else { _window_closed.push_back(element.letGo()); From 10242e891cf0eb05993dd3bb7eca092b427ee579 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Sat, 30 Mar 2024 13:29:46 -0500 Subject: [PATCH 57/82] move stuff around to avoid exposing additional headers --- pvtoolsSrc/nameServerImpl.cpp | 6 +- src/remote/Makefile | 1 - src/server/Makefile | 5 -- src/server/nameServer.cpp | 111 +++++++++++++++++++++++++++++++--- src/server/pv/nameServer.h | 100 +++--------------------------- src/server/pv/serverContext.h | 1 - 6 files changed, 116 insertions(+), 108 deletions(-) diff --git a/pvtoolsSrc/nameServerImpl.cpp b/pvtoolsSrc/nameServerImpl.cpp index cd27b64b..29c307e8 100644 --- a/pvtoolsSrc/nameServerImpl.cpp +++ b/pvtoolsSrc/nameServerImpl.cpp @@ -5,7 +5,9 @@ */ +#define epicsExportSharedSymbols #include +#include #include #include "nameServerImpl.h" @@ -52,11 +54,11 @@ void NameServerImpl::discoverServers(ServerAddressList& serverAddressList) size_t count = entry.addresses.size(); std::string addresses = " "; for (size_t i = 0; i < count; i++) { - addresses = addresses + inetAddressToString(entry.addresses[i]) + " "; + addresses = addresses + inetAddrToString(entry.addresses[i]) + " "; } LOG(logLevelDebug, "Found server GUID 0x%s version %d: %s@[%s]", entry.guid.c_str(), (int)entry.version, entry.protocol.c_str(), addresses.c_str()); if (count > 0) { - std::string serverAddress = inetAddressToString(entry.addresses[0]); + std::string serverAddress = inetAddrToString(entry.addresses[0]); if (addUniqueServerToList(serverAddress, serverAddressList)) { nDiscoveredServers++; } diff --git a/src/remote/Makefile b/src/remote/Makefile index a7520056..89f43613 100644 --- a/src/remote/Makefile +++ b/src/remote/Makefile @@ -3,7 +3,6 @@ SRC_DIRS += $(PVACCESS_SRC)/remote INC += pv/security.h -INC += pv/remote.h INC += pv/serializationHelper.h pvAccess_SRCS += blockingUDPTransport.cpp diff --git a/src/server/Makefile b/src/server/Makefile index d3d8466c..f2cfd616 100644 --- a/src/server/Makefile +++ b/src/server/Makefile @@ -4,12 +4,7 @@ SRC_DIRS += $(PVACCESS_SRC)/server INC += pv/serverContext.h INC += pv/beaconServerStatusProvider.h -INC += pv/baseChannelRequester.h -INC += pv/beaconEmitter.h INC += pv/nameServer.h -INC += pv/responseHandlers.h -INC += pv/serverChannelImpl.h -INC += pv/serverContextImpl.h INC += pva/server.h INC += pva/sharedstate.h diff --git a/src/server/nameServer.cpp b/src/server/nameServer.cpp index 34541ab7..7b5e3ef6 100644 --- a/src/server/nameServer.cpp +++ b/src/server/nameServer.cpp @@ -4,12 +4,15 @@ * in file LICENSE that is included with this distribution. */ - - #define epicsExportSharedSymbols #include +#include +#include +#include #include #include +#include "pv/responseHandlers.h" +#include "pv/serverContextImpl.h" #include "pv/nameServer.h" using namespace std; @@ -25,6 +28,41 @@ namespace epics { namespace pvAccess { /* * Name server channel find requester */ +class NameServerChannelFindRequesterImpl + : public ChannelFindRequester + , public TransportSender + , public epics::pvData::TimerCallback + , public std::tr1::enable_shared_from_this +{ +public: + NameServerChannelFindRequesterImpl(const ServerContextImpl::shared_pointer& context, const PeerInfo::const_shared_pointer& peerInfo, epics::pvData::int32 expectedResponseCount); + virtual ~NameServerChannelFindRequesterImpl(); + void clear(); + void set(const std::string& channelName, epics::pvData::int32 searchSequenceId, epics::pvData::int32 cid, const osiSockAddr& sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch); + virtual void channelFindResult(const epics::pvData::Status& status, const ChannelFind::shared_pointer& channelFind, bool wasFound) OVERRIDE FINAL; + virtual std::tr1::shared_ptr getPeerInfo() OVERRIDE FINAL; + virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) OVERRIDE FINAL; + virtual void callback() OVERRIDE FINAL; + virtual void timerStopped() OVERRIDE FINAL; + +private: + mutable epics::pvData::Mutex mutex; + ServerGUID nameServerGuid; + std::string nameServerAddress; + std::string channelName; + std::string channelServerAddress; + epics::pvData::int32 searchSequenceId; + epics::pvData::int32 cid; + osiSockAddr sendTo; + Transport::shared_pointer transport; + bool responseRequired; + bool channelWasFound; + const ServerContextImpl::shared_pointer context; + const PeerInfo::const_shared_pointer peer; + const epics::pvData::int32 expectedResponseCount; + epics::pvData::int32 responseCount; + bool serverSearch; +}; NameServerChannelFindRequesterImpl::NameServerChannelFindRequesterImpl(const ServerContextImpl::shared_pointer& context_, const PeerInfo::const_shared_pointer& peer_, int32 expectedResponseCount_) : mutex() @@ -169,6 +207,18 @@ void NameServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendC /* * Name server search handler */ +class NameServerSearchHandler + : public AbstractServerResponseHandler +{ +public: + static const std::string SUPPORTED_PROTOCOL; + + NameServerSearchHandler(const ServerContextImpl::shared_pointer& context); + virtual ~NameServerSearchHandler(); + + virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData::int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE FINAL; +}; + const std::string NameServerSearchHandler::SUPPORTED_PROTOCOL = "tcp"; NameServerSearchHandler::NameServerSearchHandler(const ServerContextImpl::shared_pointer& context) @@ -313,6 +363,32 @@ void NameServerSearchHandler::handleResponse(osiSockAddr* responseFrom, const Tr /* * Name server search response handler */ +class NameServerSearchResponseHandler + : public ResponseHandler +{ +public: + NameServerSearchResponseHandler(const ServerContextImpl::shared_pointer& context); + virtual ~NameServerSearchResponseHandler(); + virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData:: +int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE + FINAL; + +private: + ServerBadResponse badResponseHandler; + ServerNoopResponse beaconHandler; + ServerConnectionValidationHandler validationHandler; + ServerEchoHandler echoHandler; + NameServerSearchHandler searchHandler; + AuthNZHandler authnzHandler; + ServerCreateChannelHandler createChannelHandler; + ServerDestroyChannelHandler destroyChannelHandler; + ServerRPCHandler rpcHandler; + + // Table of response handlers for each command ID. + std::vector handlerTable; + +}; + NameServerSearchResponseHandler::NameServerSearchResponseHandler(const ServerContextImpl::shared_pointer& context) : ResponseHandler(context.get(), "NameServerSearchResponseHandler") , badResponseHandler(context) @@ -377,6 +453,22 @@ void NameServerSearchResponseHandler::handleResponse(osiSockAddr* responseFrom, /* * Name server channel find */ +class NameServerChannelFind + : public ChannelFind +{ +public: + POINTER_DEFINITIONS(NameServerChannelFind); + + NameServerChannelFind(ChannelProvider::shared_pointer& provider); + virtual ~NameServerChannelFind(); + virtual void destroy(); + virtual ChannelProvider::shared_pointer getChannelProvider(); + virtual void cancel(); + +private: + ChannelProvider::weak_pointer channelProvider; +}; + NameServerChannelFind::NameServerChannelFind(ChannelProvider::shared_pointer& provider) : channelProvider(provider) { @@ -403,7 +495,6 @@ void NameServerChannelFind::cancel() /* * Name server channel provider class */ - const std::string NameServerChannelProvider::PROVIDER_NAME("remote"); NameServerChannelProvider::NameServerChannelProvider() @@ -535,10 +626,11 @@ NameServer::NameServer(const epics::pvAccess::Configuration::shared_pointer& con { channelProvider->initialize(); ServerContext::Config serverConfig = ServerContext::Config().config(conf).provider(channelProvider); - context = ServerContextImpl::create(serverConfig); - ResponseHandler::shared_pointer searchResponseHandler(new NameServerSearchResponseHandler(context)); - context->initialize(searchResponseHandler, searchResponseHandler); - nameServerGuid = context->getGUID(); + ServerContextImpl::shared_pointer contextImpl = ServerContextImpl::create(serverConfig); + ResponseHandler::shared_pointer searchResponseHandler(new NameServerSearchResponseHandler(contextImpl)); + contextImpl->initialize(searchResponseHandler, searchResponseHandler); + nameServerGuid = contextImpl->getGUID(); + context = contextImpl; } NameServer::~NameServer() @@ -643,4 +735,9 @@ void NameServer::shutdown() context->shutdown(); } +std::string NameServer::inetAddrToString(const osiSockAddr& addr) +{ + return inetAddressToString(addr); +} + }} diff --git a/src/server/pv/nameServer.h b/src/server/pv/nameServer.h index 542ad82e..05430ccd 100644 --- a/src/server/pv/nameServer.h +++ b/src/server/pv/nameServer.h @@ -5,102 +5,15 @@ #include #include +#include +#include #include -#include -#include +#include #include namespace epics { namespace pvAccess { -class NameServerChannelFindRequesterImpl - : public ChannelFindRequester - , public TransportSender - , public epics::pvData::TimerCallback - , public std::tr1::enable_shared_from_this -{ -public: - NameServerChannelFindRequesterImpl(const ServerContextImpl::shared_pointer& context, const PeerInfo::const_shared_pointer& peerInfo, epics::pvData::int32 expectedResponseCount); - virtual ~NameServerChannelFindRequesterImpl(); - void clear(); - void set(const std::string& channelName, epics::pvData::int32 searchSequenceId, epics::pvData::int32 cid, const osiSockAddr& sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch); - virtual void channelFindResult(const epics::pvData::Status& status, const ChannelFind::shared_pointer& channelFind, bool wasFound) OVERRIDE FINAL; - virtual std::tr1::shared_ptr getPeerInfo() OVERRIDE FINAL; - virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) OVERRIDE FINAL; - virtual void callback() OVERRIDE FINAL; - virtual void timerStopped() OVERRIDE FINAL; - -private: - mutable epics::pvData::Mutex mutex; - ServerGUID nameServerGuid; - std::string nameServerAddress; - std::string channelName; - std::string channelServerAddress; - epics::pvData::int32 searchSequenceId; - epics::pvData::int32 cid; - osiSockAddr sendTo; - Transport::shared_pointer transport; - bool responseRequired; - bool channelWasFound; - const ServerContextImpl::shared_pointer context; - const PeerInfo::const_shared_pointer peer; - const epics::pvData::int32 expectedResponseCount; - epics::pvData::int32 responseCount; - bool serverSearch; -}; - -class NameServerSearchHandler - : public AbstractServerResponseHandler -{ -public: - static const std::string SUPPORTED_PROTOCOL; - - NameServerSearchHandler(const ServerContextImpl::shared_pointer& context); - virtual ~NameServerSearchHandler(); - - virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData::int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE FINAL; -}; - -class NameServerSearchResponseHandler - : public ResponseHandler -{ -public: - NameServerSearchResponseHandler(const ServerContextImpl::shared_pointer& context); - virtual ~NameServerSearchResponseHandler(); - virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData::int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE FINAL; - -private: - ServerBadResponse badResponseHandler; - ServerNoopResponse beaconHandler; - ServerConnectionValidationHandler validationHandler; - ServerEchoHandler echoHandler; - NameServerSearchHandler searchHandler; - AuthNZHandler authnzHandler; - ServerCreateChannelHandler createChannelHandler; - ServerDestroyChannelHandler destroyChannelHandler; - ServerRPCHandler rpcHandler; - - // Table of response handlers for each command ID. - std::vector handlerTable; - -}; - -class NameServerChannelFind - : public ChannelFind -{ -public: - POINTER_DEFINITIONS(NameServerChannelFind); - - NameServerChannelFind(ChannelProvider::shared_pointer& provider); - virtual ~NameServerChannelFind(); - virtual void destroy(); - virtual ChannelProvider::shared_pointer getChannelProvider(); - virtual void cancel(); - -private: - ChannelProvider::weak_pointer channelProvider; -}; - class NameServerChannelProvider : public ChannelProvider , public std::tr1::enable_shared_from_this @@ -117,7 +30,7 @@ class NameServerChannelProvider virtual ChannelFind::shared_pointer channelFind(const std::string& channelName, const ChannelFindRequester::shared_pointer& channelFindRequester); virtual ChannelFind::shared_pointer channelList(const ChannelListRequester::shared_pointer& channelListRequester); virtual Channel::shared_pointer createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short priority); - virtual Channel::shared_pointer createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short /*priority*/, const std::string& address); + virtual Channel::shared_pointer createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short priority, const std::string& address); void updateChannelMap(const ChannelDiscovery::ChannelMap& updatedChannelMap); std::string getChannelServerAddress(const std::string& channelName); void setChannelEntryExpirationTime(double expirationTime); @@ -155,7 +68,10 @@ class epicsShareClass NameServer protected: - ServerContextImpl::shared_pointer context; + + std::string inetAddrToString(const osiSockAddr& addr); + + ServerContext::shared_pointer context; ServerGUID nameServerGuid; NameServerChannelProvider::shared_pointer channelProvider; double pollPeriod; diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index 96042c2a..bc1f7f0b 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include From c9227f938911e33204c6aaf7b1c7431f49bdb242 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Sun, 31 Mar 2024 06:13:43 -0500 Subject: [PATCH 58/82] few more changes for mingw --- pvtoolsSrc/nameServerImpl.cpp | 3 +-- src/remote/pv/remote.h | 1 - testApp/remote/channelDiscoveryTest.cpp | 3 --- testApp/remote/channelDiscoveryTest.h | 3 +++ 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pvtoolsSrc/nameServerImpl.cpp b/pvtoolsSrc/nameServerImpl.cpp index 29c307e8..1563698b 100644 --- a/pvtoolsSrc/nameServerImpl.cpp +++ b/pvtoolsSrc/nameServerImpl.cpp @@ -5,7 +5,6 @@ */ -#define epicsExportSharedSymbols #include #include #include @@ -56,7 +55,7 @@ void NameServerImpl::discoverServers(ServerAddressList& serverAddressList) for (size_t i = 0; i < count; i++) { addresses = addresses + inetAddrToString(entry.addresses[i]) + " "; } - LOG(logLevelDebug, "Found server GUID 0x%s version %d: %s@[%s]", entry.guid.c_str(), (int)entry.version, entry.protocol.c_str(), addresses.c_str()); + LOG(logLevelDebug, "Found server GUID 0x%s version %d: %s@[%s]", entry.guid.c_str(), int(entry.version), entry.protocol.c_str(), addresses.c_str()); if (count > 0) { std::string serverAddress = inetAddrToString(entry.addresses[0]); if (addUniqueServerToList(serverAddress, serverAddressList)) { diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 86b37b7c..3ff68413 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/testApp/remote/channelDiscoveryTest.cpp b/testApp/remote/channelDiscoveryTest.cpp index d227ef5c..d722cc30 100644 --- a/testApp/remote/channelDiscoveryTest.cpp +++ b/testApp/remote/channelDiscoveryTest.cpp @@ -7,9 +7,6 @@ #include #include -#include -#include - #include #include "channelDiscoveryTest.h" diff --git a/testApp/remote/channelDiscoveryTest.h b/testApp/remote/channelDiscoveryTest.h index 7405e3cc..374ee078 100644 --- a/testApp/remote/channelDiscoveryTest.h +++ b/testApp/remote/channelDiscoveryTest.h @@ -2,6 +2,9 @@ #define CHANNEL_DISCOVERY_H #include +#include +#include + #include "syncTestRequesters.h" class ChannelDiscoveryTest { From 4527a0bb8ff61929deffa4fd12a158d5bee4381c Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Sun, 31 Mar 2024 06:41:16 -0500 Subject: [PATCH 59/82] fix codacy complaint about explicit constructors --- src/server/nameServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/nameServer.cpp b/src/server/nameServer.cpp index 7b5e3ef6..6e16e102 100644 --- a/src/server/nameServer.cpp +++ b/src/server/nameServer.cpp @@ -213,7 +213,7 @@ class NameServerSearchHandler public: static const std::string SUPPORTED_PROTOCOL; - NameServerSearchHandler(const ServerContextImpl::shared_pointer& context); + explicit NameServerSearchHandler(const ServerContextImpl::shared_pointer& context); virtual ~NameServerSearchHandler(); virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData::int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE FINAL; @@ -367,7 +367,7 @@ class NameServerSearchResponseHandler : public ResponseHandler { public: - NameServerSearchResponseHandler(const ServerContextImpl::shared_pointer& context); + explicit NameServerSearchResponseHandler(const ServerContextImpl::shared_pointer& context); virtual ~NameServerSearchResponseHandler(); virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData:: int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE @@ -459,7 +459,7 @@ class NameServerChannelFind public: POINTER_DEFINITIONS(NameServerChannelFind); - NameServerChannelFind(ChannelProvider::shared_pointer& provider); + explicit NameServerChannelFind(ChannelProvider::shared_pointer& provider); virtual ~NameServerChannelFind(); virtual void destroy(); virtual ChannelProvider::shared_pointer getChannelProvider(); From 7832fc421f514b7b3b4342ede3046c1026d5de5c Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Sun, 31 Mar 2024 09:01:28 -0500 Subject: [PATCH 60/82] restore original export defs; remove unused constants --- src/pva/pv/pvaConstants.h | 15 +++++++++++---- src/pva/pvaConstants.cpp | 2 -- src/remote/pv/channelSearchManager.h | 11 +++++++++++ testApp/remote/testCodec.cpp | 2 +- testApp/utils/Makefile | 1 - 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/pva/pv/pvaConstants.h b/src/pva/pv/pvaConstants.h index 484589d9..878a03cf 100644 --- a/src/pva/pv/pvaConstants.h +++ b/src/pva/pv/pvaConstants.h @@ -8,7 +8,18 @@ #define PVACONSTANTS_H_ #include + +#ifdef epicsExportSharedSymbols +# define pvaConstantsepicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + #include + +#ifdef pvaConstantsepicsExportSharedSymbols +# define epicsExportSharedSymbols +# undef pvaConstantsepicsExportSharedSymbols +#endif #include namespace epics { namespace pvAccess { @@ -78,10 +89,6 @@ epicsShareExtern const std::string PVACCESS_ALL_PROVIDERS; /** Name of the system env. variable to turn on debugging. */ epicsShareExtern const std::string PVACCESS_DEBUG; -/** Protocol constants. */ -epicsShareExtern const std::string PVA_TCP_PROTOCOL; -epicsShareExtern const std::string PVA_UDP_PROTOCOL; - }} #endif /* PVACONSTANTS_H_ */ diff --git a/src/pva/pvaConstants.cpp b/src/pva/pvaConstants.cpp index 5f19a4f3..7b4e5ac8 100644 --- a/src/pva/pvaConstants.cpp +++ b/src/pva/pvaConstants.cpp @@ -12,7 +12,5 @@ namespace epics { namespace pvAccess { const std::string PVACCESS_DEFAULT_PROVIDER("local"); const std::string PVACCESS_ALL_PROVIDERS(""); const std::string PVACCESS_DEBUG("EPICS_PVA_DEBUG"); -const std::string PVA_TCP_PROTOCOL("tcp"); -const std::string PVA_UDP_PROTOCOL("udp"); }} diff --git a/src/remote/pv/channelSearchManager.h b/src/remote/pv/channelSearchManager.h index 36ed375f..0aa7789a 100644 --- a/src/remote/pv/channelSearchManager.h +++ b/src/remote/pv/channelSearchManager.h @@ -7,7 +7,18 @@ #ifndef CHANNELSEARCHMANAGER_H #define CHANNELSEARCHMANAGER_H +#ifdef epicsExportSharedSymbols +# define channelSearchManagerEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + #include + +#ifdef channelSearchManagerEpicsExportSharedSymbols +# define epicsExportSharedSymbols +# undef channelSearchManagerEpicsExportSharedSymbols +#endif + #include #include diff --git a/testApp/remote/testCodec.cpp b/testApp/remote/testCodec.cpp index 10833de9..c6ea1640 100644 --- a/testApp/remote/testCodec.cpp +++ b/testApp/remote/testCodec.cpp @@ -349,7 +349,7 @@ class TestCodec: public AbstractCodec { std::string getType() const { - return PVA_TCP_PROTOCOL; + return "tcp"; } const osiSockAddr& getRemoteAddress() const { diff --git a/testApp/utils/Makefile b/testApp/utils/Makefile index 402d37fa..e4c4e2b8 100644 --- a/testApp/utils/Makefile +++ b/testApp/utils/Makefile @@ -38,4 +38,3 @@ TESTPROD_HOST += testStringUtility testStringUtility_SRCS = testStringUtility.cpp testHarness_SRCS += testStringUtility.cpp TESTS += testStringUtility - From 6b19c200cc92bf816b305d281df621b491bd6693 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 1 Apr 2024 10:25:59 -0500 Subject: [PATCH 61/82] fix format warning --- src/server/nameServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/nameServer.cpp b/src/server/nameServer.cpp index 6e16e102..1bd1b329 100644 --- a/src/server/nameServer.cpp +++ b/src/server/nameServer.cpp @@ -604,7 +604,7 @@ void NameServerChannelProvider::updateChannelMap(const ChannelMap& updatedChanne ChannelEntry channelEntry = it->second; channelMap[channelName] = channelEntry; } - LOG(logLevelDebug, "Name server channel provider updated %ld channels", updatedChannelMap.size()); + LOG(logLevelDebug, "Name server channel provider updated %d channels", int(updatedChannelMap.size())); } std::string NameServerChannelProvider::getChannelServerAddress(const std::string& channelName) From 55bd40e91391a016b480690208ee00fab89aa08d Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 1 Apr 2024 10:31:17 -0500 Subject: [PATCH 62/82] add test disgnostics output --- testApp/remote/channelAccessIFTest.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index 97f545ce..3fd069f2 100644 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -2019,6 +2019,12 @@ void ChannelAccessIFTest::test_channelArray() { CURRENT_FUNCTION, (unsigned long) bigCapacity); testOk(data4[0] == 1.1 , "%s: 4.check 0: %f == 1.1", CURRENT_FUNCTION, data4[0]); testOk(data4[1] == 2.2 , "%s: 4.check 1: %f == 2.2", CURRENT_FUNCTION, data4[1]); + if (data4.size() == bigCapacity) { + size_t i = bigCapacity-5; + for (; i < bigCapacity; i++) { + testDiag("%s: 4.check %d: %f", CURRENT_FUNCTION, int(i), data4[i]); + } + } /* if (data4.size() == bigCapacity) { size_t i = newCap; From cc5d2d6491f4b301ef45b4294183138ed75fca80 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 1 Apr 2024 17:06:36 -0500 Subject: [PATCH 63/82] new test added --- src/remoteClient/clientContextImpl.cpp | 7 ++++--- testApp/remote/channelAccessIFTest.cpp | 9 ++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 97b71103..06e9c5c5 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -234,9 +234,10 @@ class BaseRequestImpl : {/* cancel overrides all but destroy */} else if(m_pendingRequest==NULL_REQUEST) {/* anything whenidle */} - else - {return false; /* others not allowed */} - + else { + LOG(logLevelError, "Request qos %d cannot be started, pending request %d", int(qos), int(m_pendingRequest)); + return false; /* others not allowed */ + } m_pendingRequest = qos; return true; } diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index 3fd069f2..66786b18 100644 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -59,7 +59,7 @@ inline bool compareWithTol(const T v1, const T v2, const T tol) int ChannelAccessIFTest::runAllTest() { - testPlan(152+EXTRA_STRESS_TESTS); + testPlan(153+EXTRA_STRESS_TESTS); epics::pvAccess::Configuration::shared_pointer base_config(ConfigurationBuilder() //.add("EPICS_PVA_DEBUG", "3") @@ -2007,6 +2007,13 @@ void ChannelAccessIFTest::test_channelArray() { return; } + succStatus = arrayReq->syncGetLength(false, getTimeoutSec()); + if (!succStatus) { + testFail("%s: an array getLength failed (3)", CURRENT_FUNCTION); + return; + } + testOk(arrayReq->getLength() == bigCapacity, "%s: retrieved length should be %lu", CURRENT_FUNCTION, (unsigned long) bigCapacity); + succStatus = arrayReq->syncGet(false, 0, 0, getTimeoutSec()); if (!succStatus) { testFail("%s: an array syncGet failed (9) ", CURRENT_FUNCTION); From 1e530bafe726466bf127e78286a313d2c502e94e Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 12 Apr 2024 15:59:45 -0500 Subject: [PATCH 64/82] remove pvans utility --- pvtoolsSrc/Makefile | 7 - pvtoolsSrc/nameServerImpl.cpp | 92 ------- pvtoolsSrc/nameServerImpl.h | 23 -- pvtoolsSrc/pvans.cpp | 234 ---------------- pvtoolsSrc/pvlist.cpp | 494 ++++++++++++++++++++++++++++++++-- pvtoolsSrc/pvutils.cpp | 432 ----------------------------- pvtoolsSrc/pvutils.h | 18 -- 7 files changed, 476 insertions(+), 824 deletions(-) delete mode 100644 pvtoolsSrc/nameServerImpl.cpp delete mode 100644 pvtoolsSrc/nameServerImpl.h delete mode 100644 pvtoolsSrc/pvans.cpp diff --git a/pvtoolsSrc/Makefile b/pvtoolsSrc/Makefile index b4a8b9b5..9b904e07 100644 --- a/pvtoolsSrc/Makefile +++ b/pvtoolsSrc/Makefile @@ -4,7 +4,6 @@ include $(TOP)/configure/CONFIG USR_CPPFLAGS += -I$(TOP)/src/utils USR_CPPFLAGS += -I$(TOP)/src/remote -USR_CPPFLAGS += -I$(TOP)/src/remoteClient PROD_DEFAULT += pvget pvget_SRCS += pvget.cpp @@ -28,12 +27,6 @@ pvinfo_SRCS += pvutils.cpp PROD_DEFAULT += pvlist pvlist_SRCS += pvlist.cpp -pvlist_SRCS += pvutils.cpp - -PROD_DEFAULT += pvans -pvans_SRCS += pvans.cpp -pvans_SRCS += pvutils.cpp -pvans_SRCS += nameServerImpl.cpp PROD_LIBS += pvAccessCA pvAccess pvData ca Com diff --git a/pvtoolsSrc/nameServerImpl.cpp b/pvtoolsSrc/nameServerImpl.cpp deleted file mode 100644 index 1563698b..00000000 --- a/pvtoolsSrc/nameServerImpl.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * pvAccessCPP is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ - - -#include -#include -#include - -#include "nameServerImpl.h" -#include "pvutils.h" - -using namespace std; -using namespace epics::pvData; -using epics::pvAccess::ChannelDiscovery::ChannelEntry; -using epics::pvAccess::ChannelDiscovery::ChannelMap; -using epics::pvAccess::ChannelDiscovery::ServerAddressList; - - -namespace epics { namespace pvAccess { - - -NameServerImpl::NameServerImpl(const epics::pvAccess::Configuration::shared_pointer& conf) - : NameServer(conf) -{ -} - -NameServerImpl::~NameServerImpl() -{ -} - -void NameServerImpl::discoverServers(ServerAddressList& serverAddressList) -{ - if (!autoDiscovery) { - LOG(logLevelDebug, "Skipping server discovery"); - return; - } - - LOG(logLevelDebug, "Starting server discovery"); - std::string nsGuid = ::toHex(nameServerGuid.value, sizeof(nameServerGuid.value)); - ServerMap serverMap; - ::discoverServers(timeout, serverMap); - - int nDiscoveredServers = 0; - for (ServerMap::const_iterator it = serverMap.begin(); it != serverMap.end(); ++it) { - const ServerEntry& entry = it->second; - if (nsGuid == entry.guid) { - LOG(logLevelDebug, "Ignoring our own server GUID 0x%s", entry.guid.c_str()); - continue; - } - size_t count = entry.addresses.size(); - std::string addresses = " "; - for (size_t i = 0; i < count; i++) { - addresses = addresses + inetAddrToString(entry.addresses[i]) + " "; - } - LOG(logLevelDebug, "Found server GUID 0x%s version %d: %s@[%s]", entry.guid.c_str(), int(entry.version), entry.protocol.c_str(), addresses.c_str()); - if (count > 0) { - std::string serverAddress = inetAddrToString(entry.addresses[0]); - if (addUniqueServerToList(serverAddress, serverAddressList)) { - nDiscoveredServers++; - } - } - } - LOG(logLevelDebug, "Discovered %d servers", nDiscoveredServers); -} - -void NameServerImpl::discoverServerChannels(const std::string& serverAddress, ChannelMap& channelMap) -{ - LOG(logLevelDebug, "Discovering channels for server %s", serverAddress.c_str()); - try { - PVStructure::shared_pointer ret = getChannelInfo(serverAddress, "channels", timeout); - PVStringArray::shared_pointer pvs(ret->getSubField("value")); - PVStringArray::const_svector val(pvs->view()); - epicsTimeStamp now; - epicsTimeGetCurrent(&now); - for (unsigned int i = 0; i < val.size(); i++) { - ChannelEntry channelEntry; - channelEntry.channelName = val[i]; - channelEntry.serverAddress = serverAddress; - channelEntry.updateTime = now; - channelMap[val[i]] = channelEntry; - } - LOG(logLevelDebug, "Discovered %d channels for server %s", int(val.size()), serverAddress.c_str()); - } - catch(std::exception& e) { - LOG(logLevelError, "Error retrieving channels for server %s: %s", serverAddress.c_str(), e.what()); - } -} - -}} diff --git a/pvtoolsSrc/nameServerImpl.h b/pvtoolsSrc/nameServerImpl.h deleted file mode 100644 index b05a0ae8..00000000 --- a/pvtoolsSrc/nameServerImpl.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef NAME_SERVER_IMPL_H -#define NAME_SERVER_IMPL_H - -#include - -namespace epics { namespace pvAccess { - -class NameServerImpl - : public NameServer - , public std::tr1::enable_shared_from_this -{ -public: - POINTER_DEFINITIONS(NameServerImpl); - NameServerImpl(const epics::pvAccess::Configuration::shared_pointer& conf); - virtual ~NameServerImpl(); - - virtual void discoverServers(ChannelDiscovery::ServerAddressList& serverAddressList); - virtual void discoverServerChannels(const std::string& serverAddress, ChannelDiscovery::ChannelMap& channelMap); -}; - -}} - -#endif // NAME_SERVER_IMPL_H diff --git a/pvtoolsSrc/pvans.cpp b/pvtoolsSrc/pvans.cpp deleted file mode 100644 index 0593ec06..00000000 --- a/pvtoolsSrc/pvans.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright information and license terms for this software can be - * found in the file LICENSE that is included with the distribution - */ - -/* - * PVA Name Server utility. It polls a set of PVA - * servers for a list of channels, and resolves channel queries. - * PVA servers can be discovered, they can be passed through the - * command line, or they can be specified via an input file which - * gets re-read at runtime. The utility also supports static channel - * map entries read from an input file. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "nameServerImpl.h" - -using namespace std; - -using namespace epics::pvData; -using namespace epics::pvAccess; -using epics::pvAccess::ChannelDiscovery::ChannelEntry; -using epics::pvAccess::ChannelDiscovery::ChannelMap; - -namespace { - -#define DEFAULT_PVA_TIMEOUT 3.0 -#define DEFAULT_POLL_PERIOD 900.0 -#define DEFAULT_CHANNEL_EXPIRATION_TIME 2*DEFAULT_POLL_PERIOD - -void usage (void) { - fprintf (stderr, - "\nPVA Name Server\n" - "\nUsage: pvans [options]...\n\n" - "\noptions:\n" - " -h|-H\t\t\t:\tHelp: Print this message\n" - " -V\t\t\t:\tPrint version and exit\n" - " -f \t:\tStatic server list file with '' entries\n" - " -F \t:\tStatic channel map file with ' ' entries\n" - " -s ,,...\t:\tComma-separated list of '' static server entries\n" - " -a\t\t\t:\tAuto mode, discover severs available on the network\n" - " -p \t:\tServer poll period in seconds (default: %.2f [s])\n" - " -w \t:\tServer wait time in seconds (default: %.2f [s])\n" - " -e \t:\tChannel entry expiration time in seconds (default: %.2f [s])\n" - " -d\t\t\t:\tEnable debug output\n" - "\nDifferent inputs for PVA server address will be combined." - "\nServer list file should contain '' entries separated by spaces or commas, or on different lines." - "\nChannel map file should contain ' ' entries separated by spaces or commas, or on different lines." - "\nChannel expiration time <= 0 indicates that channel entries" - "\nnever expire.\n\n" - , DEFAULT_POLL_PERIOD, DEFAULT_PVA_TIMEOUT, DEFAULT_CHANNEL_EXPIRATION_TIME); -} - -// Expected server address format: -// There can be multiple addresses per line, separated by spaces or commas. -std::string readServerAddressesFromFile(const std::string& inputFile, const std::string& existingAddresses = "") -{ - std::string serverAddresses = existingAddresses; - if (inputFile.empty()) { - return serverAddresses; - } - std::ifstream ifs(inputFile.c_str()); - std::string line; - while (std::getline(ifs, line)) { - line = StringUtility::replace(line, ',', " "); - serverAddresses = serverAddresses + " " + line; - } - return serverAddresses; -} - -// Expected channel entry format: -// There can be multiple entries per line, separated by spaces or commas. -void readChannelAddressesFromFile(const std::string& inputFile, ChannelMap& channelMap) -{ - if (inputFile.empty()) { - return; - } - bool ignoreEmptyTokens = true; - epicsTimeStamp now; - epicsTimeGetCurrent(&now); - std::ifstream ifs(inputFile.c_str()); - std::string line; - while (std::getline(ifs, line)) { - line = StringUtility::replace(line, ',', " "); - std::vector tokens = StringUtility::split(line, ' ', ignoreEmptyTokens); - int nTokens = int(tokens.size()); - for (int i = 0; i < nTokens-1; i+=2) { - std::string channelName = tokens[i]; - std::string serverAddress = tokens[i+1]; - ChannelEntry channelEntry(channelName, serverAddress, now); - channelMap[channelName] = channelEntry; - LOG(logLevelDebug, "Adding %s/%s channel entry", channelName.c_str(), serverAddress.c_str()); - } - } -} - -} // namespace - -int main(int argc, char *argv[]) -{ - int opt; /* getopt() current option */ - bool debug = false; - bool autoDiscovery = false; - double timeout = DEFAULT_PVA_TIMEOUT; - double pollPeriod = DEFAULT_POLL_PERIOD; - double channelExpirationTime = DEFAULT_CHANNEL_EXPIRATION_TIME; - std::string serverAddresses; - std::string serverListFile; - std::string channelMapFile; - - while ((opt = getopt(argc, argv, ":hHVw:e:p:das:f:F:")) != -1) { - switch (opt) { - case 'h': /* Print usage */ - case 'H': { /* Print usage */ - usage(); - return 0; - } - case 'V': { /* Print version */ - fprintf(stdout, "pvAccess %u.%u.%u%s\n", - EPICS_PVA_MAJOR_VERSION, - EPICS_PVA_MINOR_VERSION, - EPICS_PVA_MAINTENANCE_VERSION, - (EPICS_PVA_DEVELOPMENT_FLAG)?"-SNAPSHOT":""); - fprintf(stdout, "pvData %u.%u.%u%s\n", - EPICS_PVD_MAJOR_VERSION, - EPICS_PVD_MINOR_VERSION, - EPICS_PVD_MAINTENANCE_VERSION, - (EPICS_PVD_DEVELOPMENT_FLAG)?"-SNAPSHOT":""); - fprintf(stdout, "Base %s\n", EPICS_VERSION_FULL); - return 0; - } - case 'p': { /* Set poll period */ - if((epicsScanDouble(optarg, &pollPeriod)) != 1 || pollPeriod <= 0.0) { - fprintf(stderr, - "'%s' is not a valid poll period value " - "- ignored. ('pvans -h' for help.)\n", optarg); - timeout = DEFAULT_PVA_TIMEOUT; - } - break; - } - case 'w': { /* Set PVA timeout value */ - if((epicsScanDouble(optarg, &timeout)) != 1 || timeout <= 0.0) { - fprintf(stderr, - "'%s' is not a valid timeout value " - "- ignored. ('pvans -h' for help.)\n", optarg); - timeout = DEFAULT_PVA_TIMEOUT; - } - break; - } - case 'e': { /* Set channel expiration time */ - if((epicsScanDouble(optarg, &channelExpirationTime)) != 1) { - fprintf(stderr, - "'%s' is not a valid expiration time value " - "- ignored. ('pvans -h' for help.)\n", optarg); - channelExpirationTime = DEFAULT_CHANNEL_EXPIRATION_TIME; - } - break; - } - case 's': { /* Server list */ - serverAddresses = optarg; - break; - } - case 'f': { /* Server list file */ - serverListFile = optarg; - break; - } - case 'F': { /* Channel map file */ - channelMapFile = optarg; - break; - } - case 'd': { /* Debug log level */ - debug = true; - break; - } - case 'a': { /* Auto discovery */ - autoDiscovery = true; - break; - } - case '?': { - fprintf(stderr, - "Unrecognized option: '-%c'. ('pvans -h' for help.)\n", - optopt); - return 1; - } - case ':': { - fprintf(stderr, - "Option '-%c' requires an argument. ('pvans -h' for help.)\n", - optopt); - return 1; - } - default: { - usage(); - return 1; - } - } - } - - SET_LOG_LEVEL(debug ? logLevelDebug : logLevelError); - - NameServerImpl::shared_pointer srv(new NameServerImpl(ConfigurationBuilder() - .push_env() - .push_map() - .build())); - srv->setPollPeriod(pollPeriod); - srv->setPvaTimeout(timeout); - srv->setAutoDiscovery(autoDiscovery); - srv->setChannelEntryExpirationTime(channelExpirationTime); - while (true) { - // Reread input file before polling. - std::string staticServerAddresses = readServerAddressesFromFile(serverListFile, serverAddresses); - srv->setStaticServerAddresses(staticServerAddresses); - ChannelMap staticChannelMap; - readChannelAddressesFromFile(channelMapFile, staticChannelMap); - srv->setStaticChannelEntries(staticChannelMap); - srv->run(pollPeriod); - } - return 0; -} diff --git a/pvtoolsSrc/pvlist.cpp b/pvtoolsSrc/pvlist.cpp index bb3ef719..28df5a6c 100644 --- a/pvtoolsSrc/pvlist.cpp +++ b/pvtoolsSrc/pvlist.cpp @@ -20,12 +20,15 @@ #include #include +#include +#include +#include +#include #include #include #include - -#include "pvutils.h" +#include #if defined(_WIN32) && !defined(_MINGW) FILE *popen(const char *command, const char *mode) { @@ -43,6 +46,437 @@ using namespace epics::pvAccess; namespace { +/// Byte to hexchar mapping. +static const char lookup[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +/// Get hex representation of byte. +string toHex(int8* ba, size_t len) { + string sb; + + for (size_t i = 0; i < len; i++) + { + int8 b = ba[i]; + + int upper = (b>>4)&0x0F; + sb += lookup[upper]; + + int lower = b&0x0F; + sb += lookup[lower]; + } + + return sb; +} + + +std::size_t readSize(ByteBuffer* buffer) { + int8 b = buffer->getByte(); + if(b==-1) + return -1; + else if(b==-2) { + int32 s = buffer->getInt(); + if(s<0) THROW_BASE_EXCEPTION("negative size"); + return s; + } + else + return (std::size_t)(b<0 ? b+256 : b); +} + +string deserializeString(ByteBuffer* buffer) { + + std::size_t size = /*SerializeHelper::*/readSize(buffer); + if(size!=(size_t)-1) // TODO null strings check, to be removed in the future + { + // entire string is in buffer, simply create a string out of it (copy) + std::size_t pos = buffer->getPosition(); + string str(buffer->getBuffer()+pos, size); + buffer->setPosition(pos+size); + return str; + } + else + return std::string(); +} + +struct ServerEntry { + string guid; + string protocol; + vector addresses; + int8 version; +}; + + +typedef map ServerMap; +static ServerMap serverMap; + +// return true if new server response is recevived +bool processSearchResponse(osiSockAddr const & responseFrom, ByteBuffer & receiveBuffer) +{ + // first byte is PVA_MAGIC + int8 magic = receiveBuffer.getByte(); + if(magic != PVA_MAGIC) + return false; + + // second byte version + int8 version = receiveBuffer.getByte(); + if(version == 0) { + // 0 -> 1 included incompatible changes + return false; + } + + // only data for UDP + int8 flags = receiveBuffer.getByte(); + if (flags < 0) + { + // 7-bit set + receiveBuffer.setEndianess(EPICS_ENDIAN_BIG); + } + else + { + receiveBuffer.setEndianess(EPICS_ENDIAN_LITTLE); + } + + // command ID and paylaod + int8 command = receiveBuffer.getByte(); + if (command != (int8)0x04) + return false; + + size_t payloadSize = receiveBuffer.getInt(); + if (payloadSize < (12+4+16+2)) + return false; + + + epics::pvAccess::ServerGUID guid; + receiveBuffer.get(guid.value, 0, sizeof(guid.value)); + + /*int32 searchSequenceId = */receiveBuffer.getInt(); + + osiSockAddr serverAddress; + memset(&serverAddress, 0, sizeof(serverAddress)); + serverAddress.ia.sin_family = AF_INET; + + // 128-bit IPv6 address + if (!decodeAsIPv6Address(&receiveBuffer, &serverAddress)) + return false; + + // accept given address if explicitly specified by sender + if (serverAddress.ia.sin_addr.s_addr == INADDR_ANY) + serverAddress.ia.sin_addr = responseFrom.ia.sin_addr; + + // NOTE: htons might be a macro (e.g. vxWorks) + int16 port = receiveBuffer.getShort(); + serverAddress.ia.sin_port = htons(port); + + string protocol = /*SerializeHelper::*/deserializeString(&receiveBuffer); + + /*bool found =*/ receiveBuffer.getByte(); // != 0; + + + string guidString = toHex((int8*)guid.value, sizeof(guid.value)); + + ServerMap::iterator iter = serverMap.find(guidString); + if (iter != serverMap.end()) + { + bool found = false; + vector& vec = iter->second.addresses; + for (vector::const_iterator ai = vec.begin(); + ai != vec.end(); + ai++) + if (sockAddrAreIdentical(&(*ai), &serverAddress)) + { + found = true; + break; + } + + if (!found) + { + vec.push_back(serverAddress); + return true; + } + else + return false; + } + else + { + ServerEntry serverEntry; + serverEntry.guid = guidString; + serverEntry.protocol = protocol; + serverEntry.addresses.push_back(serverAddress); + serverEntry.version = version; + + serverMap[guidString] = serverEntry; + + return true; + } +} + +bool discoverServers(double timeOut) +{ + osiSockAttach(); + + SOCKET socket = epicsSocketCreate(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (socket == INVALID_SOCKET) + { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Failed to create a socket: %s\n", errStr); + return false; + } + + // + // read config + // + + Configuration::shared_pointer configuration(new SystemConfigurationImpl()); + + string addressList = configuration->getPropertyAsString("EPICS_PVA_ADDR_LIST", ""); + bool autoAddressList = configuration->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", true); + int broadcastPort = configuration->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", PVA_BROADCAST_PORT); + + // quary broadcast addresses of all IFs + InetAddrVector broadcastAddresses; + { + IfaceNodeVector ifaces; + if(discoverInterfaces(ifaces, socket, 0)) { + fprintf(stderr, "Unable to populate interface list\n"); + return false; + } + + for(IfaceNodeVector::const_iterator it(ifaces.begin()), end(ifaces.end()); it!=end; ++it) + { + if(it->validBcast && it->bcast.sa.sa_family == AF_INET) { + osiSockAddr bcast = it->bcast; + bcast.ia.sin_port = htons(broadcastPort); + broadcastAddresses.push_back(bcast); + } + } + } + + // set broadcast address list + if (!addressList.empty()) + { + // if auto is true, add it to specified list + InetAddrVector* appendList = 0; + if (autoAddressList) + appendList = &broadcastAddresses; + + InetAddrVector list; + getSocketAddressList(list, addressList, broadcastPort, appendList); + if (!list.empty()) { + // delete old list and take ownership of a new one + broadcastAddresses = list; + } + } + + for (size_t i = 0; i < broadcastAddresses.size(); i++) + LOG(logLevelDebug, + "Broadcast address #%zu: %s.", i, inetAddressToString(broadcastAddresses[i]).c_str()); + + // --- + + int optval = 1; + int status = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)); + if (status) + { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Error setting SO_BROADCAST: %s\n", errStr); + epicsSocketDestroy (socket); + return false; + } + + osiSockAddr bindAddr; + memset(&bindAddr, 0, sizeof(bindAddr)); + bindAddr.ia.sin_family = AF_INET; + bindAddr.ia.sin_port = htons(0); + bindAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY); + + status = ::bind(socket, (sockaddr*)&(bindAddr.sa), sizeof(sockaddr)); + if (status) + { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Failed to bind: %s\n", errStr); + epicsSocketDestroy(socket); + return false; + } + + // set timeout +#ifdef _WIN32 + // ms + DWORD timeout = 250; +#else + struct timeval timeout; + memset(&timeout, 0, sizeof(struct timeval)); + timeout.tv_sec = 0; + timeout.tv_usec = 250000; +#endif + status = ::setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, + (char*)&timeout, sizeof(timeout)); + if (status) + { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Error setting SO_RCVTIMEO: %s\n", errStr); + return false; + } + + osiSockAddr responseAddress; + osiSocklen_t sockLen = sizeof(sockaddr); + // read the actual socket info + status = ::getsockname(socket, &responseAddress.sa, &sockLen); + if (status) { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Failed to get local socket address: %s.", errStr); + return false; + } + + char buffer[1024]; + ByteBuffer sendBuffer(buffer, sizeof(buffer)/sizeof(char)); + + sendBuffer.putByte(PVA_MAGIC); + sendBuffer.putByte(PVA_CLIENT_PROTOCOL_REVISION); + sendBuffer.putByte((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) ? 0x80 : 0x00); // data + 7-bit endianess + sendBuffer.putByte((int8_t)CMD_SEARCH); // search + sendBuffer.putInt(4+1+3+16+2+1+2); // "zero" payload + + sendBuffer.putInt(0); // sequenceId + sendBuffer.putByte((int8_t)0x81); // reply required // TODO unicast vs multicast; for now we mark ourselves as unicast + sendBuffer.putByte((int8_t)0); // reserved + sendBuffer.putShort((int16_t)0); // reserved + + // NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0 + encodeAsIPv6Address(&sendBuffer, &responseAddress); + sendBuffer.putShort((int16_t)ntohs(responseAddress.ia.sin_port)); + + sendBuffer.putByte((int8_t)0x00); // protocol count + sendBuffer.putShort((int16_t)0); // name count + + bool oneOK = false; + for (size_t i = 0; i < broadcastAddresses.size(); i++) + { + if(pvAccessIsLoggable(logLevelDebug)) { + char strBuffer[64]; + sockAddrToDottedIP(&broadcastAddresses[i].sa, strBuffer, sizeof(strBuffer)); + LOG(logLevelDebug, "UDP Tx (%zu) -> %s", sendBuffer.getPosition(), strBuffer); + } + + status = ::sendto(socket, sendBuffer.getBuffer(), sendBuffer.getPosition(), 0, + &broadcastAddresses[i].sa, sizeof(sockaddr)); + if (status < 0) + { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Send error: %s\n", errStr); + } + else + oneOK = true; + } + + if (!oneOK) + return false; + + + char rxbuff[1024]; + ByteBuffer receiveBuffer(rxbuff, sizeof(rxbuff)/sizeof(char)); + + osiSockAddr fromAddress; + osiSocklen_t addrStructSize = sizeof(sockaddr); + + int sendCount = 0; + + while (true) + { + receiveBuffer.clear(); + + // receive packet from socket + int bytesRead = ::recvfrom(socket, (char*)receiveBuffer.getBuffer(), + receiveBuffer.getRemaining(), 0, + (sockaddr*)&fromAddress, &addrStructSize); + + if (bytesRead > 0) + { + if(pvAccessIsLoggable(logLevelDebug)) { + char strBuffer[64]; + sockAddrToDottedIP(&fromAddress.sa, strBuffer, sizeof(strBuffer)); + LOG(logLevelDebug, "UDP Rx (%d) <- %s", bytesRead, strBuffer); + } + receiveBuffer.setPosition(bytesRead); + receiveBuffer.flip(); + + processSearchResponse(fromAddress, receiveBuffer); + + } + else + { + if (bytesRead == -1) + { + int socketError = SOCKERRNO; + + // interrupted or timeout + if (socketError == SOCK_EINTR || + socketError == EAGAIN || // no alias in libCom + // windows times out with this + socketError == SOCK_ETIMEDOUT || + socketError == SOCK_EWOULDBLOCK) + { + // OK + } + else if (socketError == SOCK_ECONNREFUSED || // avoid spurious ECONNREFUSED in Linux + socketError == SOCK_ECONNRESET) // or ECONNRESET in Windows + { + // OK + } + else + { + // unexpected error + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Socket recv error: %s\n", errStr); + break; + } + + } + + if (++sendCount < 3) + { + // TODO duplicate code + bool oneOK = false; + for (size_t i = 0; i < broadcastAddresses.size(); i++) + { + // send the packet + status = ::sendto(socket, sendBuffer.getBuffer(), sendBuffer.getPosition(), 0, + &broadcastAddresses[i].sa, sizeof(sockaddr)); + if (status < 0) + { + char errStr[64]; + epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); + fprintf(stderr, "Send error: %s\n", errStr); + } + else + oneOK = true; + } + + if (!oneOK) + return false; + + } + else + break; + } + + } + + // TODO shutdown sockets? + // TODO this resouce is not released on failure + epicsSocketDestroy(socket); + + return true; +} + + #define DEFAULT_TIMEOUT 3.0 void usage (void) @@ -169,9 +603,8 @@ int main (int argc, char *argv[]) bool allOK = true; - ServerMap serverMap; if (noArgs || byGUIDSearch) - discoverServers(timeOut, serverMap); + discoverServers(timeOut); // just list all the discovered servers if (noArgs) @@ -232,27 +665,52 @@ int main (int argc, char *argv[]) } } - try - { - PVStructure::shared_pointer ret = getChannelInfo(serverAddress, printInfo ? "info" : "channels", timeOut); + StructureConstPtr argstype(getFieldCreate()->createFieldBuilder() + ->setId("epics:nt/NTURI:1.0") + ->add("scheme", pvString) + ->add("path", pvString) + ->addNestedStructure("query") + ->add("op", pvString) + ->endNested() + ->createStructure()); - if(!printInfo) - { - PVStringArray::shared_pointer pvs(ret->getSubField("value")); + PVStructure::shared_pointer args(getPVDataCreate()->createPVStructure(argstype)); - PVStringArray::const_svector val(pvs->view()); + args->getSubFieldT("scheme")->put("pva"); + args->getSubFieldT("path")->put("server"); + args->getSubFieldT("query.op")->put(printInfo ? "info" : "channels"); - std::copy(val.begin(), val.end(), std::ostream_iterator(std::cout, "\n")); - } - else { - std::cout<getSubField("value")); + + PVStringArray::const_svector val(pvs->view()); + + std::copy(val.begin(), + val.end(), + std::ostream_iterator(std::cout, "\n")); + } + else { + std::cout< #include -#include -#include -#include -#include #include "pvutils.h" -using namespace epics::pvData; -using namespace epics::pvAccess; - double timeout = 5.0; bool debugFlag = false; @@ -131,430 +124,5 @@ void jarray(pvd::shared_vector& out, const char *inp) throw std::runtime_error("Unknown token"); } } -} - -// Get hex representation of byte. -std::string toHex(char ba[], size_t len) -{ - // Byte to hexchar mapping. - static const char lookup[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; - - std::string sb; - - for (size_t i = 0; i < len; i++) - { - char b = ba[i]; - - int upper = (b>>4)&0x0F; - sb += lookup[upper]; - - int lower = b&0x0F; - sb += lookup[lower]; - } - - return sb; -} - -// Read size -std::size_t readSize(ByteBuffer* buffer) -{ - int8 b = buffer->getByte(); - if(b==-1) - return -1; - else if(b==-2) { - int32 s = buffer->getInt(); - if(s<0) THROW_BASE_EXCEPTION("negative size"); - return s; - } - else - return (std::size_t)(b<0 ? b+256 : b); -} - -// Deserialize string -std::string deserializeString(ByteBuffer* buffer) -{ - - std::size_t size = /*SerializeHelper::*/readSize(buffer); - if(size!=(size_t)-1) // TODO null strings check, to be removed in the future - { - // entire string is in buffer, simply create a string out of it (copy) - std::size_t pos = buffer->getPosition(); - std::string str(buffer->getBuffer()+pos, size); - buffer->setPosition(pos+size); - return str; - } - else - return std::string(); -} - -// Process search response -// Returns true if new server response is received -bool processSearchResponse(const osiSockAddr& responseFrom, ByteBuffer& receiveBuffer, ServerMap& serverMapByGuid) -{ - // first byte is PVA_MAGIC - int8 magic = receiveBuffer.getByte(); - if(magic != PVA_MAGIC) { - return false; - } - - // second byte version - int8 version = receiveBuffer.getByte(); - if(version == 0) { - // 0 -> 1 included incompatible changes - return false; - } - - // only data for UDP - int8 flags = receiveBuffer.getByte(); - if (flags < 0) { - // 7-bit set - receiveBuffer.setEndianess(EPICS_ENDIAN_BIG); - } - else { - receiveBuffer.setEndianess(EPICS_ENDIAN_LITTLE); - } - - // command ID and paylaod - int8 command = receiveBuffer.getByte(); - if (command != (int8)0x04) { - return false; - } - - size_t payloadSize = receiveBuffer.getInt(); - if (payloadSize < (12+4+16+2)) { - return false; - } - - ServerGUID guid; - receiveBuffer.get(guid.value, 0, sizeof(guid.value)); - - /*int32 searchSequenceId = */receiveBuffer.getInt(); - - osiSockAddr serverAddress; - memset(&serverAddress, 0, sizeof(serverAddress)); - serverAddress.ia.sin_family = AF_INET; - - // 128-bit IPv6 address - if (!decodeAsIPv6Address(&receiveBuffer, &serverAddress)) { - return false; - } - - // accept given address if explicitly specified by sender - if (serverAddress.ia.sin_addr.s_addr == INADDR_ANY) { - serverAddress.ia.sin_addr = responseFrom.ia.sin_addr; - } - - // NOTE: htons might be a macro (e.g. vxWorks) - int16 port = receiveBuffer.getShort(); - serverAddress.ia.sin_port = htons(port); - std::string protocol = /*SerializeHelper::*/deserializeString(&receiveBuffer); - - /*bool found =*/ receiveBuffer.getByte(); // != 0; - - - std::string guidString = toHex(guid.value, sizeof(guid.value)); - - ServerMap::iterator iter = serverMapByGuid.find(guidString); - if (iter != serverMapByGuid.end()) { - bool found = false; - std::vector& vec = iter->second.addresses; - for (std::vector::const_iterator ai = vec.begin(); ai != vec.end(); ++ai) { - if (sockAddrAreIdentical(&(*ai), &serverAddress)) { - found = true; - break; - } - } - - if (!found) { - vec.push_back(serverAddress); - return true; - } - else { - return false; - } - } - else { - ServerEntry serverEntry; - serverEntry.guid = guidString; - serverEntry.protocol = protocol; - serverEntry.addresses.push_back(serverAddress); - serverEntry.version = version; - serverMapByGuid[guidString] = serverEntry; - return true; - } -} - -// Discover servers -bool discoverServers(double timeOut, ServerMap& serverMapByGuid) -{ - osiSockAttach(); - - SOCKET socket = epicsSocketCreate(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (socket == INVALID_SOCKET) { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Failed to create a socket: %s\n", errStr); - return false; - } - - // - // read config - // - - Configuration::shared_pointer configuration(new SystemConfigurationImpl()); - - std::string addressList = configuration->getPropertyAsString("EPICS_PVA_ADDR_LIST", ""); - bool autoAddressList = configuration->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", true); - int broadcastPort = configuration->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", PVA_BROADCAST_PORT); - - // query broadcast addresses of all IFs - InetAddrVector broadcastAddresses; - { - IfaceNodeVector ifaces; - if(discoverInterfaces(ifaces, socket, 0)) { - fprintf(stderr, "Unable to populate interface list\n"); - return false; - } - - for(IfaceNodeVector::const_iterator it(ifaces.begin()), end(ifaces.end()); it!=end; ++it) - { - if(it->validBcast && it->bcast.sa.sa_family == AF_INET) { - osiSockAddr bcast = it->bcast; - bcast.ia.sin_port = htons(broadcastPort); - broadcastAddresses.push_back(bcast); - } - } - } - - // set broadcast address list - if (!addressList.empty()) { - // if auto is true, add it to specified list - InetAddrVector* appendList = 0; - if (autoAddressList) - appendList = &broadcastAddresses; - - InetAddrVector list; - getSocketAddressList(list, addressList, broadcastPort, appendList); - if (!list.empty()) { - // delete old list and take ownership of a new one - broadcastAddresses = list; - } - } - - for (size_t i = 0; i < broadcastAddresses.size(); i++) { - LOG(logLevelDebug, "Broadcast address #%d: %s.", int(i), inetAddressToString(broadcastAddresses[i]).c_str()); - } - - // --- - - int optval = 1; - int status = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&optval), sizeof(optval)); - if (status) { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Error setting SO_BROADCAST: %s\n", errStr); - epicsSocketDestroy (socket); - return false; - } - - osiSockAddr bindAddr; - memset(&bindAddr, 0, sizeof(bindAddr)); - bindAddr.ia.sin_family = AF_INET; - bindAddr.ia.sin_port = htons(0); - bindAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY); - - status = ::bind(socket, static_cast(&bindAddr.sa), sizeof(sockaddr)); - if (status) { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Failed to bind: %s\n", errStr); - epicsSocketDestroy(socket); - return false; - } - - // set timeout -#ifdef _WIN32 - // ms - DWORD timeout = 250; -#else - struct timeval timeout; - memset(&timeout, 0, sizeof(struct timeval)); - timeout.tv_sec = 0; - timeout.tv_usec = 250000; -#endif - status = ::setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&timeout), sizeof(timeout)); - if (status) { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Error setting SO_RCVTIMEO: %s\n", errStr); - return false; - } - - osiSockAddr responseAddress; - osiSocklen_t sockLen = sizeof(sockaddr); - // read the actual socket info - status = ::getsockname(socket, &responseAddress.sa, &sockLen); - if (status) { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Failed to get local socket address: %s.", errStr); - return false; - } - - char buffer[1024]; - ByteBuffer sendBuffer(buffer, sizeof(buffer)/sizeof(char)); - - sendBuffer.putByte(PVA_MAGIC); - sendBuffer.putByte(PVA_CLIENT_PROTOCOL_REVISION); - sendBuffer.putByte((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) ? 0x80 : 0x00); // data + 7-bit endianess - sendBuffer.putByte((int8_t)CMD_SEARCH); // search - sendBuffer.putInt(4+1+3+16+2+1+2); // "zero" payload - - sendBuffer.putInt(0); // sequenceId - sendBuffer.putByte((int8_t)0x81); // reply required // TODO unicast vs multicast; for now we mark ourselves as unicast - sendBuffer.putByte((int8_t)0); // reserved - sendBuffer.putShort((int16_t)0); // reserved - - // NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0 - encodeAsIPv6Address(&sendBuffer, &responseAddress); - sendBuffer.putShort((int16_t)ntohs(responseAddress.ia.sin_port)); - - sendBuffer.putByte((int8_t)0x00); // protocol count - sendBuffer.putShort((int16_t)0); // name count - - bool oneOK = false; - for (size_t i = 0; i < broadcastAddresses.size(); i++) { - if(pvAccessIsLoggable(logLevelDebug)) { - char strBuffer[64]; - sockAddrToDottedIP(&broadcastAddresses[i].sa, strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "UDP Tx (%lu) -> %s", sendBuffer.getPosition(), strBuffer); - } - - status = ::sendto(socket, sendBuffer.getBuffer(), sendBuffer.getPosition(), 0, - &broadcastAddresses[i].sa, sizeof(sockaddr)); - if (status < 0) { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Send error: %s\n", errStr); - } - else { - oneOK = true; - } - } - - if (!oneOK) { - return false; - } - - char rxbuff[1024]; - ByteBuffer receiveBuffer(rxbuff, sizeof(rxbuff)/sizeof(char)); - - osiSockAddr fromAddress; - osiSocklen_t addrStructSize = sizeof(sockaddr); - - int sendCount = 0; - - while (true) { - receiveBuffer.clear(); - - // receive packet from socket - int bytesRead = ::recvfrom(socket, const_cast(receiveBuffer.getBuffer()), - receiveBuffer.getRemaining(), 0, - static_cast(&fromAddress.sa), &addrStructSize); - - if (bytesRead > 0) { - if(pvAccessIsLoggable(logLevelDebug)) { - char strBuffer[64]; - sockAddrToDottedIP(&fromAddress.sa, strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "UDP Rx (%d) <- %s", bytesRead, strBuffer); - } - receiveBuffer.setPosition(bytesRead); - receiveBuffer.flip(); - - processSearchResponse(fromAddress, receiveBuffer, serverMapByGuid); - - } - else { - if (bytesRead == -1) { - int socketError = SOCKERRNO; - - // interrupted or timeout - if (socketError == SOCK_EINTR || - socketError == EAGAIN || // no alias in libCom - // windows times out with this - socketError == SOCK_ETIMEDOUT || - socketError == SOCK_EWOULDBLOCK) { - // OK - } - else if (socketError == SOCK_ECONNREFUSED || // avoid spurious ECONNREFUSED in Linux - socketError == SOCK_ECONNRESET) { // or ECONNRESET in Windows - // OK - } - else { - // unexpected error - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Socket recv error: %s\n", errStr); - break; - } - } - - if (++sendCount < 3) { - // TODO duplicate code - bool oneOK = false; - for (size_t i = 0; i < broadcastAddresses.size(); i++) { - // send the packet - status = ::sendto(socket, sendBuffer.getBuffer(), sendBuffer.getPosition(), 0, &broadcastAddresses[i].sa, sizeof(sockaddr)); - if (status < 0) { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - fprintf(stderr, "Send error: %s\n", errStr); - } - else { - oneOK = true; - } - } - - if (!oneOK) { - return false; - } - } - else { - break; - } - } - } - - // TODO shutdown sockets? - // TODO this resouce is not released on failure - epicsSocketDestroy(socket); - return true; -} - -PVStructure::shared_pointer getChannelInfo(const std::string& serverAddress, const std::string& queryOp, double timeOut) -{ - LOG(logLevelDebug, "Querying server %s for %s", serverAddress.c_str(), queryOp.c_str()); - StructureConstPtr argstype(getFieldCreate()->createFieldBuilder() - ->setId("epics:nt/NTURI:1.0") - ->add("scheme", pvString) - ->add("path", pvString) - ->addNestedStructure("query") - ->add("op", pvString) - ->endNested() - ->createStructure()); - - PVStructure::shared_pointer args(getPVDataCreate()->createPVStructure(argstype)); - - args->getSubFieldT("scheme")->put("pva"); - args->getSubFieldT("path")->put("server"); - args->getSubFieldT("query.op")->put(queryOp); - - PVStructure::shared_pointer ret; - RPCClient rpc("server", createRequest("field()"), ChannelProvider::shared_pointer(), serverAddress); - return rpc.request(args, timeOut, true); } diff --git a/pvtoolsSrc/pvutils.h b/pvtoolsSrc/pvutils.h index f0211033..3eea5949 100644 --- a/pvtoolsSrc/pvutils.h +++ b/pvtoolsSrc/pvutils.h @@ -8,18 +8,14 @@ #include #include #include -#include -#include #include #include #include -#include #include #include #include -#include typedef epicsGuard Guard; typedef epicsGuardRelease UnGuard; @@ -76,21 +72,7 @@ struct Tracker { EPICS_NOT_COPYABLE(Tracker) }; -struct ServerEntry { - std::string guid; - std::string protocol; - std::vector addresses; - pvd::int8 version; -}; -typedef std::map ServerMap; - void jarray(pvd::shared_vector& out, const char *inp); -std::string toHex(char ba[], size_t len); -std::size_t readSize(pvd::ByteBuffer* buffer); -std::string deserializeString(pvd::ByteBuffer* buffer); -bool processSearchResponse(const osiSockAddr& responseFrom, pvd::ByteBuffer& receiveBuffer, ServerMap& serverMapByGuid); -bool discoverServers(double timeOut, ServerMap& serverMapByGuid); -pvd::PVStructure::shared_pointer getChannelInfo(const std::string& serverAddress, const std::string& queryOp, double timeOut); #endif /* PVUTILS_H */ From afbd3085a25ee102d10a9c305d9fcaf4ccfe5615 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Fri, 12 Apr 2024 16:08:06 -0500 Subject: [PATCH 65/82] remove nameserver support classes --- src/server/Makefile | 2 - src/server/nameServer.cpp | 743 -------------------------------- src/server/pv/nameServer.h | 85 ---- src/utils/Makefile | 4 - src/utils/channelDiscovery.cpp | 27 -- src/utils/pv/channelDiscovery.h | 35 -- src/utils/pv/stringUtility.h | 30 -- src/utils/stringUtility.cpp | 116 ----- 8 files changed, 1042 deletions(-) delete mode 100644 src/server/nameServer.cpp delete mode 100644 src/server/pv/nameServer.h delete mode 100644 src/utils/channelDiscovery.cpp delete mode 100644 src/utils/pv/channelDiscovery.h delete mode 100644 src/utils/pv/stringUtility.h delete mode 100644 src/utils/stringUtility.cpp diff --git a/src/server/Makefile b/src/server/Makefile index f2cfd616..4a5fd934 100644 --- a/src/server/Makefile +++ b/src/server/Makefile @@ -4,7 +4,6 @@ SRC_DIRS += $(PVACCESS_SRC)/server INC += pv/serverContext.h INC += pv/beaconServerStatusProvider.h -INC += pv/nameServer.h INC += pva/server.h INC += pva/sharedstate.h @@ -15,7 +14,6 @@ pvAccess_SRCS += baseChannelRequester.cpp pvAccess_SRCS += beaconEmitter.cpp pvAccess_SRCS += beaconServerStatusProvider.cpp pvAccess_SRCS += server.cpp -pvAccess_SRCS += nameServer.cpp pvAccess_SRCS += sharedstate_pv.cpp pvAccess_SRCS += sharedstate_channel.cpp pvAccess_SRCS += sharedstate_rpc.cpp diff --git a/src/server/nameServer.cpp b/src/server/nameServer.cpp deleted file mode 100644 index 1bd1b329..00000000 --- a/src/server/nameServer.cpp +++ /dev/null @@ -1,743 +0,0 @@ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * pvAccessCPP is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ - -#define epicsExportSharedSymbols -#include -#include -#include -#include -#include -#include -#include "pv/responseHandlers.h" -#include "pv/serverContextImpl.h" -#include "pv/nameServer.h" - -using namespace std; -using namespace epics::pvData; -using std::tr1::dynamic_pointer_cast; -using std::tr1::static_pointer_cast; -using epics::pvAccess::ChannelDiscovery::ChannelEntry; -using epics::pvAccess::ChannelDiscovery::ChannelMap; -using epics::pvAccess::ChannelDiscovery::ServerAddressList; - -namespace epics { namespace pvAccess { - -/* - * Name server channel find requester - */ -class NameServerChannelFindRequesterImpl - : public ChannelFindRequester - , public TransportSender - , public epics::pvData::TimerCallback - , public std::tr1::enable_shared_from_this -{ -public: - NameServerChannelFindRequesterImpl(const ServerContextImpl::shared_pointer& context, const PeerInfo::const_shared_pointer& peerInfo, epics::pvData::int32 expectedResponseCount); - virtual ~NameServerChannelFindRequesterImpl(); - void clear(); - void set(const std::string& channelName, epics::pvData::int32 searchSequenceId, epics::pvData::int32 cid, const osiSockAddr& sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch); - virtual void channelFindResult(const epics::pvData::Status& status, const ChannelFind::shared_pointer& channelFind, bool wasFound) OVERRIDE FINAL; - virtual std::tr1::shared_ptr getPeerInfo() OVERRIDE FINAL; - virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) OVERRIDE FINAL; - virtual void callback() OVERRIDE FINAL; - virtual void timerStopped() OVERRIDE FINAL; - -private: - mutable epics::pvData::Mutex mutex; - ServerGUID nameServerGuid; - std::string nameServerAddress; - std::string channelName; - std::string channelServerAddress; - epics::pvData::int32 searchSequenceId; - epics::pvData::int32 cid; - osiSockAddr sendTo; - Transport::shared_pointer transport; - bool responseRequired; - bool channelWasFound; - const ServerContextImpl::shared_pointer context; - const PeerInfo::const_shared_pointer peer; - const epics::pvData::int32 expectedResponseCount; - epics::pvData::int32 responseCount; - bool serverSearch; -}; - -NameServerChannelFindRequesterImpl::NameServerChannelFindRequesterImpl(const ServerContextImpl::shared_pointer& context_, const PeerInfo::const_shared_pointer& peer_, int32 expectedResponseCount_) - : mutex() - , nameServerGuid(context_->getGUID()) - , nameServerAddress(inetAddressToString(*(context_->getServerInetAddress()))) - , sendTo() - , responseRequired(false) - , channelWasFound(false) - , context(context_) - , peer(peer_) - , expectedResponseCount(expectedResponseCount_) - , responseCount(0) - , serverSearch(false) -{ -} - -NameServerChannelFindRequesterImpl::~NameServerChannelFindRequesterImpl() -{ -} - -void NameServerChannelFindRequesterImpl::clear() -{ - Lock lock(mutex); - channelWasFound = false; - responseCount = 0; - serverSearch = false; -} - -void NameServerChannelFindRequesterImpl::callback() -{ - channelFindResult(Status::Ok, ChannelFind::shared_pointer(), false); -} - -void NameServerChannelFindRequesterImpl::timerStopped() -{ -} - -void NameServerChannelFindRequesterImpl::set(const std::string& channelName, int32 searchSequenceId, int32 cid, const osiSockAddr& sendTo, const Transport::shared_pointer& transport, bool responseRequired, bool serverSearch) -{ - Lock lock(mutex); - this->channelName = channelName; - this->searchSequenceId = searchSequenceId; - this->cid = cid; - this->sendTo = sendTo; - this->transport = transport; - this->responseRequired = responseRequired; - this->serverSearch = serverSearch; -} - -void NameServerChannelFindRequesterImpl::channelFindResult(const Status& /*status*/, const ChannelFind::shared_pointer& channelFind, bool wasFound) -{ - Lock lock(mutex); - responseCount++; - if (responseCount > expectedResponseCount) { - if ((responseCount+1) == expectedResponseCount) { - LOG(logLevelDebug,"[NameServerChannelFindRequesterImpl::channelFindResult] More responses received than expected for channel '%s'!", channelName.c_str()); - } - return; - } - - if (wasFound && channelWasFound) { - LOG(logLevelDebug,"[NameServerChannelFindRequesterImpl::channelFindResult] Channel '%s' is hosted by different channel providers!", channelName.c_str()); - return; - } - - if (wasFound || (responseRequired && (responseCount == expectedResponseCount))) { - if (wasFound && expectedResponseCount > 1) { - Lock L(context->_mutex); - context->s_channelNameToProvider[channelName] = channelFind->getChannelProvider(); - } - channelWasFound = wasFound; - if (channelFind && ! channelName.empty()) { - ChannelProvider::shared_pointer channelProvider = channelFind->getChannelProvider(); - NameServerChannelProvider::shared_pointer nsChannelProvider = dynamic_pointer_cast(channelProvider); - if (nsChannelProvider) { - channelServerAddress = nsChannelProvider->getChannelServerAddress(channelName); - } - } - if (transport && transport->getType() == "tcp") { - TransportSender::shared_pointer thisSender = shared_from_this(); - transport->enqueueSendRequest(thisSender); - } - else { - BlockingUDPTransport::shared_pointer bt = context->getBroadcastTransport(); - if (bt) { - TransportSender::shared_pointer thisSender = shared_from_this(); - bt->enqueueSendRequest(thisSender); - } - } - } -} - -std::tr1::shared_ptr NameServerChannelFindRequesterImpl::getPeerInfo() -{ - return peer; -} - -void NameServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) -{ - std::string sendToStr = inetAddressToString(sendTo); - LOG(logLevelDebug, "Name server search response will be sent to %s", sendToStr.c_str()); - control->startMessage(CMD_SEARCH_RESPONSE, 12+4+16+2); - - Lock lock(mutex); - buffer->put(nameServerGuid.value, 0, sizeof(nameServerGuid.value)); - buffer->putInt(searchSequenceId); - - int nameServerPort = context->getServerPort(); - osiSockAddr channelServerAddr; - channelServerAddr.ia.sin_port = htons(nameServerPort); - if (stringToInetAddress(channelServerAddress, channelServerAddr)) { - LOG(logLevelDebug, "Encoding channel server address %s into channel search response", channelServerAddress.c_str()); - } - else { - stringToInetAddress(nameServerAddress, channelServerAddr); - LOG(logLevelDebug, "Encoding name server address %s into channel search response", nameServerAddress.c_str()); - } - encodeAsIPv6Address(buffer, &channelServerAddr); - int16 port = ntohs(channelServerAddr.ia.sin_port); - buffer->putShort(port); - - SerializeHelper::serializeString(ServerSearchHandler::SUPPORTED_PROTOCOL, buffer, control); - - control->ensureBuffer(1); - buffer->putByte(channelWasFound ? (int8)1 : (int8)0); - - if (!serverSearch) { - // For now we do not gather search responses - buffer->putShort((int16)1); - buffer->putInt(cid); - } - else { - buffer->putShort((int16)0); - } - - control->setRecipient(sendTo); - - // send immediately - control->flush(true); -} - -/* - * Name server search handler - */ -class NameServerSearchHandler - : public AbstractServerResponseHandler -{ -public: - static const std::string SUPPORTED_PROTOCOL; - - explicit NameServerSearchHandler(const ServerContextImpl::shared_pointer& context); - virtual ~NameServerSearchHandler(); - - virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData::int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE FINAL; -}; - -const std::string NameServerSearchHandler::SUPPORTED_PROTOCOL = "tcp"; - -NameServerSearchHandler::NameServerSearchHandler(const ServerContextImpl::shared_pointer& context) - : AbstractServerResponseHandler(context, "Search request") -{ - // initialize random seed - srand(time(NULL)); -} - -NameServerSearchHandler::~NameServerSearchHandler() -{ -} - -void NameServerSearchHandler::handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, int8 version, int8 command, size_t payloadSize, ByteBuffer* payloadBuffer) -{ - std::string responseFromStr = inetAddressToString(*responseFrom); - LOG(logLevelDebug, "Name server search handler is handling request from %s", responseFromStr.c_str()); - AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); - transport->ensureData(4+1+3+16+2); - - size_t startPosition = payloadBuffer->getPosition(); - - const int32 searchSequenceId = payloadBuffer->getInt(); - const int8 qosCode = payloadBuffer->getByte(); - - // reserved part - payloadBuffer->getByte(); - payloadBuffer->getShort(); - - osiSockAddr responseAddress; - memset(&responseAddress, 0, sizeof(responseAddress)); - responseAddress.ia.sin_family = AF_INET; - - // 128-bit IPv6 address - if (!decodeAsIPv6Address(payloadBuffer, &responseAddress)) { - return; - } - - // accept given address if explicitly specified by sender - if (responseAddress.ia.sin_addr.s_addr == INADDR_ANY) { - responseAddress.ia.sin_addr = responseFrom->ia.sin_addr; - } - - int16 port = payloadBuffer->getShort(); - if (port) { - responseAddress.ia.sin_port = htons(port); - } - else { - LOG(logLevelDebug, "Server search handler is reusing connection port %d", ntohs(responseFrom->ia.sin_port)); - responseAddress.ia.sin_port = responseFrom->ia.sin_port; - } - - size_t protocolsCount = SerializeHelper::readSize(payloadBuffer, transport.get()); - bool allowed = (protocolsCount == 0); - for (size_t i = 0; i < protocolsCount; i++) { - string protocol = SerializeHelper::deserializeString(payloadBuffer, transport.get()); - if (SUPPORTED_PROTOCOL == protocol) { - allowed = true; - } - } - - transport->ensureData(2); - const int32 count = payloadBuffer->getShort() & 0xFFFF; - const bool responseRequired = (QOS_REPLY_REQUIRED & qosCode) != 0; - - // - // locally broadcast if unicast (qosCode & QOS_GET_PUT == QOS_GET_PUT) via UDP - // - if ((qosCode & QOS_GET_PUT) == QOS_GET_PUT) { - BlockingUDPTransport::shared_pointer bt = dynamic_pointer_cast(transport); - if (bt && bt->hasLocalMulticastAddress()) { - // RECEIVE_BUFFER_PRE_RESERVE allows to pre-fix message - size_t newStartPos = (startPosition-PVA_MESSAGE_HEADER_SIZE)-PVA_MESSAGE_HEADER_SIZE-16; - payloadBuffer->setPosition(newStartPos); - - // copy part of a header, and add: command, payloadSize, NIF address - payloadBuffer->put(payloadBuffer->getBuffer(), startPosition-PVA_MESSAGE_HEADER_SIZE, PVA_MESSAGE_HEADER_SIZE-5); - payloadBuffer->putByte(CMD_ORIGIN_TAG); - payloadBuffer->putInt(16); - // encode this socket bind address - encodeAsIPv6Address(payloadBuffer, bt->getBindAddress()); - - // clear unicast flag - payloadBuffer->put(startPosition+4, (int8)(qosCode & ~0x80)); - - // update response address - payloadBuffer->setPosition(startPosition+8); - encodeAsIPv6Address(payloadBuffer, &responseAddress); - - // set to end of a message - payloadBuffer->setPosition(payloadBuffer->getLimit()); - - bt->send(payloadBuffer->getBuffer()+newStartPos, payloadBuffer->getPosition()-newStartPos, bt->getLocalMulticastAddress()); - return; - } - } - - PeerInfo::shared_pointer info; - if(allowed) { - info.reset(new PeerInfo); - info->transport = "pva"; - info->peer = responseFromStr; - info->transportVersion = version; - } - - if (count > 0) { - // regular name search - for (int32 i = 0; i < count; i++) { - transport->ensureData(4); - const int32 cid = payloadBuffer->getInt(); - const string name = SerializeHelper::deserializeString(payloadBuffer, transport.get()); - LOG(logLevelDebug, "Search for channel %s, cid %d", name.c_str(), cid); - if (allowed) { - const std::vector& providers = _context->getChannelProviders(); - unsigned int providerCount = providers.size(); - std::tr1::shared_ptr channelFindRequester(new NameServerChannelFindRequesterImpl(_context, info, providerCount)); - channelFindRequester->set(name, searchSequenceId, cid, responseAddress, transport, responseRequired, false); - - for (unsigned int i = 0; i < providerCount; i++) { - providers[i]->channelFind(name, channelFindRequester); - } - } - } - } - else { - // Server discovery ping by pvlist - if (allowed) - { - // ~random hold-off to reduce impact of all servers responding. - // in [0.05, 0.15] - double delay = double(rand())/RAND_MAX; // [0, 1] - delay = delay*0.1 + 0.05; - std::tr1::shared_ptr channelFindRequester(new NameServerChannelFindRequesterImpl(_context, info, 1)); - channelFindRequester->set("", searchSequenceId, 0, responseAddress, transport, true, true); - - TimerCallback::shared_pointer tc = channelFindRequester; - _context->getTimer()->scheduleAfterDelay(tc, delay); - } - } -} - -/* - * Name server search response handler - */ -class NameServerSearchResponseHandler - : public ResponseHandler -{ -public: - explicit NameServerSearchResponseHandler(const ServerContextImpl::shared_pointer& context); - virtual ~NameServerSearchResponseHandler(); - virtual void handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, epics::pvData:: -int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE - FINAL; - -private: - ServerBadResponse badResponseHandler; - ServerNoopResponse beaconHandler; - ServerConnectionValidationHandler validationHandler; - ServerEchoHandler echoHandler; - NameServerSearchHandler searchHandler; - AuthNZHandler authnzHandler; - ServerCreateChannelHandler createChannelHandler; - ServerDestroyChannelHandler destroyChannelHandler; - ServerRPCHandler rpcHandler; - - // Table of response handlers for each command ID. - std::vector handlerTable; - -}; - -NameServerSearchResponseHandler::NameServerSearchResponseHandler(const ServerContextImpl::shared_pointer& context) - : ResponseHandler(context.get(), "NameServerSearchResponseHandler") - , badResponseHandler(context) - , beaconHandler(context, "Beacon") - , validationHandler(context) - , echoHandler(context) - , searchHandler(context) - , authnzHandler(context.get()) - , createChannelHandler(context) - , destroyChannelHandler(context) - , rpcHandler(context) - , handlerTable(CMD_CANCEL_REQUEST+1, &badResponseHandler) -{ - handlerTable[CMD_BEACON] = &badResponseHandler; /* 0 */ - handlerTable[CMD_CONNECTION_VALIDATION] = &validationHandler; /* 1 */ - handlerTable[CMD_ECHO] = &echoHandler; /* 2 */ - handlerTable[CMD_SEARCH] = &searchHandler; /* 3 */ - handlerTable[CMD_SEARCH_RESPONSE] = &badResponseHandler; - handlerTable[CMD_AUTHNZ] = &authnzHandler; /* 5 */ - handlerTable[CMD_ACL_CHANGE] = &badResponseHandler; /* 6 - access right change */ - handlerTable[CMD_CREATE_CHANNEL] = &createChannelHandler; /* 7 */ - handlerTable[CMD_DESTROY_CHANNEL] = &destroyChannelHandler; /* 8 */ - handlerTable[CMD_CONNECTION_VALIDATED] = &badResponseHandler; /* 9 */ - - handlerTable[CMD_GET] = &badResponseHandler; /* 10 - get response */ - handlerTable[CMD_PUT] = &badResponseHandler; /* 11 - put response */ - handlerTable[CMD_PUT_GET] = &badResponseHandler; /* 12 - put-get response */ - handlerTable[CMD_MONITOR] = &badResponseHandler; /* 13 - monitor response */ - handlerTable[CMD_ARRAY] = &badResponseHandler; /* 14 - array response */ - handlerTable[CMD_DESTROY_REQUEST] = &badResponseHandler; /* 15 - destroy request */ - handlerTable[CMD_PROCESS] = &badResponseHandler; /* 16 - process response */ - handlerTable[CMD_GET_FIELD] = &badResponseHandler; /* 17 - get field response */ - handlerTable[CMD_MESSAGE] = &badResponseHandler; /* 18 - message to Requester */ - handlerTable[CMD_MULTIPLE_DATA] = &badResponseHandler; /* 19 - grouped monitors */ - - handlerTable[CMD_RPC] = &rpcHandler; /* 20 - RPC response */ - handlerTable[CMD_CANCEL_REQUEST] = &badResponseHandler; /* 21 - cancel request */ -} - -NameServerSearchResponseHandler::~NameServerSearchResponseHandler() -{ -} - -void NameServerSearchResponseHandler::handleResponse(osiSockAddr* responseFrom, const Transport::shared_pointer& transport, int8 version, int8 command, size_t payloadSize, ByteBuffer* payloadBuffer) -{ - if(command<0||command>=(int8)handlerTable.size()) - { - LOG(logLevelError, "Invalid (or unsupported) command: %x.", (0xFF&command)); - if(IS_LOGGABLE(logLevelError)) { - std::ios::fmtflags initialflags = std::cerr.flags(); - std::cerr << "Invalid (or unsupported) command: " - << std::hex << (int)(0xFF&command) << "\n" - << HexDump(*payloadBuffer, payloadSize).limit(256u); - std::cerr.flags(initialflags); - } - return; - } - // delegate - handlerTable[command]->handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); -} - -/* - * Name server channel find - */ -class NameServerChannelFind - : public ChannelFind -{ -public: - POINTER_DEFINITIONS(NameServerChannelFind); - - explicit NameServerChannelFind(ChannelProvider::shared_pointer& provider); - virtual ~NameServerChannelFind(); - virtual void destroy(); - virtual ChannelProvider::shared_pointer getChannelProvider(); - virtual void cancel(); - -private: - ChannelProvider::weak_pointer channelProvider; -}; - -NameServerChannelFind::NameServerChannelFind(ChannelProvider::shared_pointer& provider) - : channelProvider(provider) -{ -} - -NameServerChannelFind::~NameServerChannelFind() -{ -} - -void NameServerChannelFind::destroy() -{ -} - -ChannelProvider::shared_pointer NameServerChannelFind::getChannelProvider() -{ - return channelProvider.lock(); -}; - -void NameServerChannelFind::cancel() -{ - throw std::runtime_error("Not supported"); -} - -/* - * Name server channel provider class - */ -const std::string NameServerChannelProvider::PROVIDER_NAME("remote"); - -NameServerChannelProvider::NameServerChannelProvider() - : nsChannelFind() - , channelEntryExpirationTime(0) -{ -} - -NameServerChannelProvider::~NameServerChannelProvider() -{ -} - -void NameServerChannelProvider::initialize() -{ - ChannelProvider::shared_pointer thisChannelProvider = shared_from_this(); - nsChannelFind.reset(new NameServerChannelFind(thisChannelProvider)); -} - -void NameServerChannelProvider::setChannelEntryExpirationTime(double expirationTime) -{ - this->channelEntryExpirationTime = expirationTime; -} - -void NameServerChannelProvider::setStaticChannelEntries(const ChannelMap& channelMap) -{ - Lock lock(channelMapMutex); - for (ChannelMap::const_iterator it = channelMap.begin(); it != channelMap.end(); ++it) { - std::string channelName = it->first; - ChannelEntry channelEntry = it->second; - this->channelMap[channelName] = channelEntry; - } - LOG(logLevelDebug, "Updated %d static channel entries", int(channelMap.size())); -} - -std::string NameServerChannelProvider::NameServerChannelProvider::getProviderName() -{ - return PROVIDER_NAME; -} - -void NameServerChannelProvider::destroy() -{ -} - -ChannelFind::shared_pointer NameServerChannelProvider::channelFind(const std::string& channelName, const ChannelFindRequester::shared_pointer& channelFindRequester) -{ - bool exists = false; - epicsTimeStamp now; - epicsTimeGetCurrent(&now); - { - Lock lock(channelMapMutex); - ChannelMap::iterator it = channelMap.find(channelName); - if (it != channelMap.end()) { - exists = true; - // Check expiration time if it is configured - if (channelEntryExpirationTime > 0) { - ChannelEntry channelEntry = it->second; - epicsTimeStamp channelUpdateTime = channelEntry.updateTime; - double timeSinceUpdate = epicsTimeDiffInSeconds(&now, &channelUpdateTime); - if (timeSinceUpdate > channelEntryExpirationTime) { - LOG(logLevelDebug, "Channel %s was last updated %.2f seconds ago, channel entry has expired", channelName.c_str(), timeSinceUpdate); - channelMap.erase(it); - exists = false; - } - } - } - } - channelFindRequester->channelFindResult(epics::pvData::Status::Ok, nsChannelFind, exists); - return nsChannelFind; -} - -ChannelFind::shared_pointer NameServerChannelProvider::channelList(const ChannelListRequester::shared_pointer& channelListRequester) -{ - if (!channelListRequester.get()) { - throw std::runtime_error("Null requester"); - } - - epics::pvData::PVStringArray::svector channelNames; - { - Lock lock(channelMapMutex); - for (ChannelMap::const_iterator it = channelMap.begin(); it != channelMap.end(); ++it) { - std::string channelName = it->first; - channelNames.push_back(channelName); - } - } - channelListRequester->channelListResult(epics::pvData::Status::Ok, nsChannelFind, freeze(channelNames), true); - return nsChannelFind; -} - -Channel::shared_pointer NameServerChannelProvider::createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short priority) -{ - return createChannel(channelName, channelRequester, priority, "local"); -} - -Channel::shared_pointer NameServerChannelProvider::createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short /*priority*/, const std::string& address) -{ - Channel::shared_pointer nullPtr; - epics::pvData::Status errorStatus(epics::pvData::Status::STATUSTYPE_ERROR, "Not supported"); - channelRequester->channelCreated(errorStatus, nullPtr); - return nullPtr; -} - -void NameServerChannelProvider::updateChannelMap(const ChannelMap& updatedChannelMap) -{ - Lock lock(channelMapMutex); - for (ChannelMap::const_iterator it = updatedChannelMap.begin(); it != updatedChannelMap.end(); ++it) { - std::string channelName = it->first; - ChannelEntry channelEntry = it->second; - channelMap[channelName] = channelEntry; - } - LOG(logLevelDebug, "Name server channel provider updated %d channels", int(updatedChannelMap.size())); -} - -std::string NameServerChannelProvider::getChannelServerAddress(const std::string& channelName) -{ - std::string serverAddress; - Lock lock(channelMapMutex); - ChannelMap::const_iterator it = channelMap.find(channelName); - if (it != channelMap.end()) { - serverAddress = it->second.serverAddress; - } - return serverAddress; -} - -/* - * Name server class - */ -NameServer::NameServer(const epics::pvAccess::Configuration::shared_pointer& conf) - : channelProvider(new NameServerChannelProvider) -{ - channelProvider->initialize(); - ServerContext::Config serverConfig = ServerContext::Config().config(conf).provider(channelProvider); - ServerContextImpl::shared_pointer contextImpl = ServerContextImpl::create(serverConfig); - ResponseHandler::shared_pointer searchResponseHandler(new NameServerSearchResponseHandler(contextImpl)); - contextImpl->initialize(searchResponseHandler, searchResponseHandler); - nameServerGuid = contextImpl->getGUID(); - context = contextImpl; -} - -NameServer::~NameServer() -{ - shutdown(); - context.reset(); -} - -void NameServer::setPollPeriod(double pollPeriod) -{ - LOG(logLevelDebug, "Setting server poll period to %.2f seconds", pollPeriod); - this->pollPeriod = pollPeriod; -} -void NameServer::setPvaTimeout(double timeout) -{ - LOG(logLevelDebug, "Setting PVA timeout to %.2f seconds", timeout); - this->timeout = timeout; -} -void NameServer::setAutoDiscovery(bool autoDiscovery) -{ - this->autoDiscovery = autoDiscovery; -} -void NameServer::setStaticServerAddresses(const std::string& serverAddresses) -{ - this->serverAddresses = serverAddresses; -} -void NameServer::setStaticChannelEntries(const ChannelMap& channelMap) -{ - this->channelProvider->setStaticChannelEntries(channelMap); -} -void NameServer::setChannelEntryExpirationTime(double expirationTime) -{ - LOG(logLevelDebug, "Setting channel entry expiration time to %.2f seconds", expirationTime); - this->channelProvider->setChannelEntryExpirationTime(expirationTime); -} - -void NameServer::run(double runtime) -{ - epicsTimeStamp startTime; - epicsTimeGetCurrent(&startTime); - while(true) { - ServerAddressList serverAddressList; - addServersFromAddresses(serverAddressList); - discoverServers(serverAddressList); - ChannelMap channelMap; - discoverChannels(serverAddressList, channelMap); - channelProvider->updateChannelMap(channelMap); - epicsTimeStamp now; - epicsTimeGetCurrent(&now); - double deltaT = epicsTimeDiffInSeconds(&now, &startTime); - if (runtime > 0 && deltaT > runtime) { - break; - } - double remainingTime = runtime-deltaT; - double waitTime = pollPeriod; - if (waitTime > remainingTime) { - waitTime = remainingTime; - } - epicsThreadSleep(waitTime); - } -} - -bool NameServer::addUniqueServerToList(const std::string& serverAddress, ServerAddressList& serverAddressList) -{ - std::list::const_iterator it = std::find(serverAddressList.begin(), serverAddressList.end(), serverAddress); - if (it == serverAddressList.end()) { - LOG(logLevelDebug, "Adding server address %s", serverAddress.c_str()); - serverAddressList.push_back(serverAddress); - return true; - } - LOG(logLevelDebug, "Ignoring duplicate server address %s", serverAddress.c_str()); - return false; -} - -void NameServer::addServersFromAddresses(ServerAddressList& serverAddressList) -{ - LOG(logLevelDebug, "Adding pre-configured server addresses"); - std::string addresses = StringUtility::replace(serverAddresses, ',', " "); - InetAddrVector inetAddrVector; - getSocketAddressList(inetAddrVector, addresses, context->getServerPort()); - int nAddedServers = 0; - for (unsigned int i = 0; i < inetAddrVector.size(); i++) { - std::string serverAddress = inetAddressToString(inetAddrVector[i]); - if (addUniqueServerToList(serverAddress, serverAddressList)) { - nAddedServers++; - } - } - LOG(logLevelDebug, "Added %d pre-configured server addresses", nAddedServers); -} - -void NameServer::discoverChannels(ServerAddressList& serverAddressList, ChannelMap& channelMap) -{ - LOG(logLevelDebug, "Discovering channels for %d servers", int(serverAddressList.size())); - for (ServerAddressList::const_iterator it = serverAddressList.begin(); it != serverAddressList.end(); ++it) { - std::string serverAddress = *it; - discoverServerChannels(serverAddress, channelMap); - } -} - -void NameServer::shutdown() -{ - context->shutdown(); -} - -std::string NameServer::inetAddrToString(const osiSockAddr& addr) -{ - return inetAddressToString(addr); -} - -}} diff --git a/src/server/pv/nameServer.h b/src/server/pv/nameServer.h deleted file mode 100644 index 05430ccd..00000000 --- a/src/server/pv/nameServer.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef NAME_SERVER_H -#define NAME_SERVER_H - -#include -#include - -#include -#include -#include -#include -#include - -#include - -namespace epics { namespace pvAccess { - -class NameServerChannelProvider - : public ChannelProvider - , public std::tr1::enable_shared_from_this -{ -public: - POINTER_DEFINITIONS(NameServerChannelProvider); - static const std::string PROVIDER_NAME; - - NameServerChannelProvider(); - virtual ~NameServerChannelProvider(); - void initialize(); - virtual std::string getProviderName(); - virtual void destroy(); - virtual ChannelFind::shared_pointer channelFind(const std::string& channelName, const ChannelFindRequester::shared_pointer& channelFindRequester); - virtual ChannelFind::shared_pointer channelList(const ChannelListRequester::shared_pointer& channelListRequester); - virtual Channel::shared_pointer createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short priority); - virtual Channel::shared_pointer createChannel(const std::string& channelName, const ChannelRequester::shared_pointer& channelRequester, short priority, const std::string& address); - void updateChannelMap(const ChannelDiscovery::ChannelMap& updatedChannelMap); - std::string getChannelServerAddress(const std::string& channelName); - void setChannelEntryExpirationTime(double expirationTime); - void setStaticChannelEntries(const ChannelDiscovery::ChannelMap& channelMap); - -private: - ChannelFind::shared_pointer nsChannelFind; - mutable epics::pvData::Mutex channelMapMutex; - ChannelDiscovery::ChannelMap channelMap; - double channelEntryExpirationTime; -}; - -class epicsShareClass NameServer -{ -public: - POINTER_DEFINITIONS(NameServer); - NameServer(const epics::pvAccess::Configuration::shared_pointer& conf); - virtual ~NameServer(); - - virtual void setPollPeriod(double pollPeriod); - virtual void setPvaTimeout(double timeout); - virtual void setAutoDiscovery(bool autoDiscovery); - virtual void setStaticServerAddresses(const std::string& serverAddresses); - virtual void setStaticChannelEntries(const ChannelDiscovery::ChannelMap& channelMap); - virtual void setChannelEntryExpirationTime(double expirationTime); - virtual void run(double runtime); - - virtual bool addUniqueServerToList(const std::string& serverAddress, ChannelDiscovery::ServerAddressList& serverAddressList); - virtual void addServersFromAddresses(ChannelDiscovery::ServerAddressList& serverAddressList); - virtual void discoverChannels(ChannelDiscovery::ServerAddressList& serverAddressList, ChannelDiscovery::ChannelMap& channelMap); - virtual void shutdown(); - - virtual void discoverServers(ChannelDiscovery::ServerAddressList& serverAddressList) = 0; - virtual void discoverServerChannels(const std::string& serverAddress, ChannelDiscovery::ChannelMap& channelMap) = 0; - - -protected: - - std::string inetAddrToString(const osiSockAddr& addr); - - ServerContext::shared_pointer context; - ServerGUID nameServerGuid; - NameServerChannelProvider::shared_pointer channelProvider; - double pollPeriod; - double timeout; - bool autoDiscovery; - std::string serverAddresses; -}; - -}} - -#endif // NAME_SERVER_H diff --git a/src/utils/Makefile b/src/utils/Makefile index ca46b0cb..bbc13eb1 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -12,8 +12,6 @@ INC += pv/wildcard.h INC += pv/fairQueue.h INC += pv/requester.h INC += pv/destroyable.h -INC += pv/stringUtility.h -INC += pv/channelDiscovery.h pvAccess_SRCS += getgroups.cpp pvAccess_SRCS += hexDump.cpp @@ -24,5 +22,3 @@ pvAccess_SRCS += configuration.cpp pvAccess_SRCS += referenceCountingLock.cpp pvAccess_SRCS += requester.cpp pvAccess_SRCS += wildcard.cpp -pvAccess_SRCS += stringUtility.cpp -pvAccess_SRCS += channelDiscovery.cpp diff --git a/src/utils/channelDiscovery.cpp b/src/utils/channelDiscovery.cpp deleted file mode 100644 index 4f69188f..00000000 --- a/src/utils/channelDiscovery.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * pvAccessCPP is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ - -#define epicsExportSharedSymbols -#include "pv/channelDiscovery.h" - -namespace epics { namespace pvAccess { namespace ChannelDiscovery { - -ChannelEntry::ChannelEntry() -{ -} - -ChannelEntry::ChannelEntry(const std::string& channelName_, const std::string& serverAddress_, const epicsTimeStamp& updateTime_) - : channelName(channelName_) - , serverAddress(serverAddress_) - , updateTime(updateTime_) -{ -} - -ChannelEntry::~ChannelEntry() -{ -} - -}}} diff --git a/src/utils/pv/channelDiscovery.h b/src/utils/pv/channelDiscovery.h deleted file mode 100644 index d68b2e37..00000000 --- a/src/utils/pv/channelDiscovery.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * pvAccessCPP is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ - -#ifndef CHANNEL_DISCOVERY_H -#define CHANNEL_DISCOVERY_H - -#include -#include -#include - -#include -#include - -namespace epics { namespace pvAccess { namespace ChannelDiscovery { - -/* - * Name server channel entry - */ -struct epicsShareClass ChannelEntry { - ChannelEntry(); - ChannelEntry(const std::string& channelName, const std::string& serverAddress, const epicsTimeStamp& updateTime); - virtual ~ChannelEntry(); - std::string channelName; - std::string serverAddress; - epicsTimeStamp updateTime; -}; -typedef std::map ChannelMap; -typedef std::list ServerAddressList; - -}}} - -#endif diff --git a/src/utils/pv/stringUtility.h b/src/utils/pv/stringUtility.h deleted file mode 100644 index 5067cca4..00000000 --- a/src/utils/pv/stringUtility.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * pvAccessCPP is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ - -#ifndef STRING_UTILITY_H -#define STRING_UTILITY_H - -#include -#include - -#include - -namespace epics { namespace pvAccess { namespace StringUtility { - -epicsShareFunc std::string leftTrim(const std::string& s); -epicsShareFunc std::string rightTrim(const std::string& s); -epicsShareFunc std::string trim(const std::string& s); -epicsShareFunc std::vector& split(const std::string& s, char delimiter, std::vector& elements, bool ignoreEmptyTokens = false); -epicsShareFunc std::vector split(const std::string& s, char delimiter, bool ignoreEmptyTokens = false); -epicsShareFunc std::string toLowerCase(const std::string& input); -epicsShareFunc std::string toUpperCase(const std::string& input); -epicsShareFunc std::string replace(const std::string& input, char oldChar, char newChar); -epicsShareFunc std::string replace(const std::string& input, char oldChar, const std::string& newString); -epicsShareFunc std::string replace(const std::string& input, const std::string& oldString, const std::string& newString); - -}}} // namespace epics::pvAccess::StringUtility - -#endif diff --git a/src/utils/stringUtility.cpp b/src/utils/stringUtility.cpp deleted file mode 100644 index 41377de3..00000000 --- a/src/utils/stringUtility.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * pvAccessCPP is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ - -#include -#include -#include - -#define epicsExportSharedSymbols -#include "pv/stringUtility.h" - -namespace epics { namespace pvAccess { namespace StringUtility { - -std::string leftTrim(const std::string& s) -{ - unsigned int i; - unsigned int n = (unsigned int)s.length(); - for (i = 0; i < n; i++) { - if (!isspace(s[i])) { - break; - } - } - return s.substr(i,n-i); -} - -std::string rightTrim(const std::string& s) -{ - unsigned int i; - unsigned int n = (unsigned int)s.length(); - for (i = n; i > 0; i--) { - if (!isspace(s[i-1])) { - break; - } - } - return s.substr(0,i); -} - -std::string trim(const std::string& s) -{ - return rightTrim(leftTrim(s)); -} - -std::vector& split(const std::string& s, char delimiter, std::vector& elements, bool ignoreEmptyTokens) -{ - std::stringstream ss(s); - std::string item; - while (std::getline(ss, item, delimiter)) { - item = trim(item); - if (!item.empty() || !ignoreEmptyTokens) { - elements.push_back(item); - } - } - return elements; -} - -std::vector split(const std::string& s, char delimiter, bool ignoreEmptyTokens) -{ - std::vector elements; - split(s, delimiter, elements, ignoreEmptyTokens); - return elements; -} - -std::string toLowerCase(const std::string& input) -{ - std::stringstream ss; - for (unsigned int i = 0; i < input.size(); i++) { - char c = std::tolower(input.at(i)); - ss << c; - } - return ss.str(); -} - -std::string toUpperCase(const std::string& input) -{ - std::stringstream ss; - for (unsigned int i = 0; i < input.size(); i++) { - char c = std::toupper(input.at(i)); - ss << c; - } - return ss.str(); -} - -std::string replace(const std::string& input, char oldChar, char newChar) -{ - std::string oldString; - oldString += oldChar; - std::string newString; - newString += newChar; - return replace(input, oldString, newString); -} - -std::string replace(const std::string& input, char oldChar, const std::string& newString) -{ - std::string oldString; - oldString += oldChar; - return replace(input, oldString, newString); -} - -std::string replace(const std::string& input, const std::string& oldString, const std::string& newString) -{ - if (oldString.empty()) { - return input; - } - std::string output = input; - std::string::size_type pos = input.find(oldString); - while (pos != std::string::npos) { - output = output.replace(pos, oldString.size(), newString); - pos = pos + newString.size(); - pos = output.find(oldString, pos); - } - return output; -} - -}}} From b521694a64ab9c67a3eb0c170b9d14e1a5a17478 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 15 Apr 2024 08:14:58 -0500 Subject: [PATCH 66/82] remove string utility tests --- testApp/utils/Makefile | 5 -- testApp/utils/testStringUtility.cpp | 83 ----------------------------- 2 files changed, 88 deletions(-) delete mode 100644 testApp/utils/testStringUtility.cpp diff --git a/testApp/utils/Makefile b/testApp/utils/Makefile index e4c4e2b8..c57c9030 100644 --- a/testApp/utils/Makefile +++ b/testApp/utils/Makefile @@ -33,8 +33,3 @@ TESTS += testWildcard TESTPROD_HOST += showauth showauth_SRCS += showauth.cpp - -TESTPROD_HOST += testStringUtility -testStringUtility_SRCS = testStringUtility.cpp -testHarness_SRCS += testStringUtility.cpp -TESTS += testStringUtility diff --git a/testApp/utils/testStringUtility.cpp b/testApp/utils/testStringUtility.cpp deleted file mode 100644 index f1bd9de4..00000000 --- a/testApp/utils/testStringUtility.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include - -#include - -#include - -#include - -#include -#include - -using namespace epics::pvAccess::StringUtility; - -namespace { - -void test_trim() -{ - testDiag("Test trim()"); - testOk1(trim(" abc123 ") == "abc123"); - testOk1(trim("abc123 ") == "abc123"); - testOk1(trim(" abc123") == "abc123"); -} - -void test_split() -{ - testDiag("Test split()"); - std::string testString = " a123 , b123 , c123 , d123,e123 "; - testDiag("Splitting by ',', input string: '%s'", testString.c_str()); - std::vector v = split(testString, ','); - testOk1(v.size() == 5); - testOk1(v[0] == "a123"); - testOk1(v[1] == "b123"); - testOk1(v[2] == "c123"); - testOk1(v[3] == "d123"); - testOk1(v[4] == "e123"); - testString = " a123 b123 c123 d123 e123 "; - testDiag("Splitting by ' ' and ignoring empty tokens, input string: '%s'", testString.c_str()); - bool ignoreEmptyTokens = true; - v = split(testString, ' ', ignoreEmptyTokens); - testOk1(v.size() == 5); - testOk1(v[0] == "a123"); - testOk1(v[1] == "b123"); - testOk1(v[2] == "c123"); - testOk1(v[3] == "d123"); - testOk1(v[4] == "e123"); -} - -void test_toLowerCase() -{ - testDiag("Test toLowerCase()"); - testOk1(toLowerCase("AbCdEfGhIj12345Kl") == "abcdefghij12345kl"); -} - -void test_toUpperCase() -{ - testDiag("Test toUpperCase()"); - testOk1(toUpperCase("AbCdEfGhIj12345Kl") == "ABCDEFGHIJ12345KL"); -} - -void test_replace() -{ - testDiag("Test replace()"); - testOk1(replace("a,b,c,d,e,f,1,2,3", ",", " ") == "a b c d e f 1 2 3"); - testOk1(replace("a,b,c", ',', ' ') == "a b c"); - testOk1(replace("a,b,c", ',', "aa") == "aaabaac"); - testOk1(replace("a,b,c", ",", ",X,") == "a,X,b,X,c"); -} - -} // namespace - -MAIN(testStringUtility) -{ - testPlan(3+12+1+1+4); - testDiag("Tests for string utilities"); - - test_trim(); - test_split(); - test_toLowerCase(); - test_toUpperCase(); - test_replace(); - return testDone(); -} From 731bba1db1f5472d8bfffa604d73cab99a060217 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 15 Apr 2024 08:25:21 -0500 Subject: [PATCH 67/82] remove ability to set udp sender port --- src/remoteClient/clientContextImpl.cpp | 3 --- src/server/serverContext.cpp | 6 ------ 2 files changed, 9 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 06e9c5c5..d6a3fb87 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -4215,7 +4215,6 @@ class InternalClientContextImpl : out << "CONNECTION_TIMEOUT : " << m_connectionTimeout << std::endl; out << "BEACON_PERIOD : " << m_beaconPeriod << std::endl; out << "BROADCAST_PORT : " << m_broadcastPort << std::endl;; - out << "UDP_SENDER_PORT : " << m_senderPort << std::endl;; out << "RCV_BUFFER_SIZE : " << m_receiveBufferSize << std::endl; out << "STATE : "; switch (m_contextState) @@ -4314,8 +4313,6 @@ class InternalClientContextImpl : m_beaconPeriod = m_configuration->getPropertyAsFloat("EPICS_PVA_BEACON_PERIOD", m_beaconPeriod); m_broadcastPort = m_configuration->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", m_broadcastPort); LOG(logLevelDebug, "Configured broadcast port: %d", m_broadcastPort); - m_senderPort = m_configuration->getPropertyAsInteger("EPICS_PVA_UDP_SENDER_PORT", m_senderPort); - LOG(logLevelDebug, "Configured udp sender port: %d", m_senderPort); m_receiveBufferSize = m_configuration->getPropertyAsInteger("EPICS_PVA_MAX_ARRAY_BYTES", m_receiveBufferSize); getSocketAddressList(m_nsAddresses, m_nsAddressList, m_serverPort); } diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index c465d9e0..a8671dbc 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -145,8 +145,6 @@ void ServerContextImpl::loadConfiguration() _broadcastPort = config->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", _broadcastPort); _broadcastPort = config->getPropertyAsInteger("EPICS_PVAS_BROADCAST_PORT", _broadcastPort); - _senderPort = config->getPropertyAsInteger("EPICS_PVA_UDP_SENDER_PORT", _senderPort); - _senderPort = config->getPropertyAsInteger("EPICS_PVAS_UDP_SENDER_PORT", _senderPort); _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVA_MAX_ARRAY_BYTES", _receiveBufferSize); _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVAS_MAX_ARRAY_BYTES", _receiveBufferSize); @@ -257,9 +255,6 @@ ServerContextImpl::getCurrentConfig() SET("EPICS_PVAS_BROADCAST_PORT", getBroadcastPort()); SET("EPICS_PVA_BROADCAST_PORT", getBroadcastPort()); - SET("EPICS_PVAS_UDP_SENDER_PORT", getSenderPort()); - SET("EPICS_PVA_UDP_SENDER_PORT", getSenderPort()); - SET("EPICS_PVAS_MAX_ARRAY_BYTES", getReceiveBufferSize()); SET("EPICS_PVA_MAX_ARRAY_BYTES", getReceiveBufferSize()); @@ -425,7 +420,6 @@ void ServerContextImpl::printInfo(ostream& str, int lvl) SHOW(EPICS_PVAS_AUTO_BEACON_ADDR_LIST) SHOW(EPICS_PVAS_BEACON_PERIOD) SHOW(EPICS_PVAS_BROADCAST_PORT) - SHOW(EPICS_PVAS_UDP_SENDER_PORT) SHOW(EPICS_PVAS_SERVER_PORT) SHOW(EPICS_PVAS_PROVIDER_NAMES) #undef SHOW From 0dca5d70e42d0987233cf796e73b5217ec2dd20c Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 15 Apr 2024 08:44:56 -0500 Subject: [PATCH 68/82] disable code that initiates direct connection to server based on EPICS_PVA_ADDR_LIST --- src/remoteClient/clientContextImpl.cpp | 33 ++++++----- testApp/remote/Makefile | 5 -- testApp/remote/dcChannelDiscoveryTest.cpp | 72 ----------------------- 3 files changed, 17 insertions(+), 93 deletions(-) delete mode 100644 testApp/remote/dcChannelDiscoveryTest.cpp diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index d6a3fb87..4d4f6f2c 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -2762,7 +2762,7 @@ class BeaconResponseHandler : public AbstractClientResponseHandler { serverAddress.ia.sin_port = htons(port); string protocol(SerializeHelper::deserializeString(payloadBuffer, transport.get())); - if(protocol != "tcp") + if(protocol!="tcp") return; // TODO optimize @@ -3690,21 +3690,22 @@ class InternalClientContextImpl : m_allowCreation = true; - if (!m_addresses.empty()) { - char strBuffer[24]; - int index = m_addressIndex % m_addresses.size(); - osiSockAddr* serverAddress = &m_addresses[index]; - ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); - uint16_t port = ntohs(serverAddress->ia.sin_port); - if (port > 0) { - double delay = (m_addressIndex / m_addresses.size())*STATIC_SEARCH_BASE_DELAY_SEC+STATIC_SEARCH_MIN_DELAY_SEC; - LOG(logLevelDebug, "Scheduling direct channel connection attempt for address %s with delay of %.3f seconds.", strBuffer, delay); - m_context->getTimer()->scheduleAfterDelay(internal_from_this(), delay); - } - else { - LOG(logLevelDebug, "Cannot schedule direct channel connection attempt for address %s (port not specified).", strBuffer); - } - } + // The following code forces direct tcp connection to server + // if (!m_addresses.empty()) { + // char strBuffer[24]; + // int index = m_addressIndex % m_addresses.size(); + // osiSockAddr* serverAddress = &m_addresses[index]; + // ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); + // uint16_t port = ntohs(serverAddress->ia.sin_port); + // if (port > 0) { + // double delay = (m_addressIndex / m_addresses.size())*STATIC_SEARCH_BASE_DELAY_SEC+STATIC_SEARCH_MIN_DELAY_SEC; + // LOG(logLevelDebug, "Scheduling direct channel connection attempt for address %s with delay of %.3f seconds.", strBuffer, delay); + // m_context->getTimer()->scheduleAfterDelay(internal_from_this(), delay); + // } + // else { + // LOG(logLevelDebug, "Cannot schedule direct channel connection attempt for address %s (port not specified).", strBuffer); + // } + // } m_context->getChannelSearchManager()->registerSearchInstance(internal_from_this(), penalize); } diff --git a/testApp/remote/Makefile b/testApp/remote/Makefile index 23416c6d..b75b31b0 100644 --- a/testApp/remote/Makefile +++ b/testApp/remote/Makefile @@ -15,17 +15,12 @@ testUdpChannelDiscovery_SRCS += channelDiscoveryTest.cpp TESTPROD_HOST += testNsChannelDiscovery testNsChannelDiscovery_SRCS = nsChannelDiscoveryTest.cpp testNsChannelDiscovery_SRCS += channelDiscoveryTest.cpp -TESTPROD_HOST += testDcChannelDiscovery -testDcChannelDiscovery_SRCS = dcChannelDiscoveryTest.cpp -testDcChannelDiscovery_SRCS += channelDiscoveryTest.cpp ifneq (RTEMS,$(OS_CLASS)) testHarness_SRCS += udpChannelDiscoveryTest.cpp testHarness_SRCS += nsChannelDiscoveryTest.cpp -testHarness_SRCS += dcChannelDiscoveryTest.cpp testHarness_SRCS += channelDiscoveryTest.cpp TESTS += testUdpChannelDiscovery TESTS += testNsChannelDiscovery -TESTS += testDcChannelDiscovery endif TESTPROD_HOST += testCodec diff --git a/testApp/remote/dcChannelDiscoveryTest.cpp b/testApp/remote/dcChannelDiscoveryTest.cpp deleted file mode 100644 index 181329be..00000000 --- a/testApp/remote/dcChannelDiscoveryTest.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// Test direct channel connection - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include "channelDiscoveryTest.h" - -#define TESTSERVERNOMAIN -#include "testServer.cpp" - -namespace EPVA = epics::pvAccess; - - -int runAllTests() { - ChannelDiscoveryTest cdTest; - testPlan(cdTest.getNumberOfTests()); - testDiag("Channel discovery type: direct connection"); - - EPVA::Configuration::shared_pointer baseConfig(ConfigurationBuilder() - .add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1") - .add("EPICS_PVA_SERVER_PORT", "0") - .add("EPICS_PVAS_BROADCAST_PORT", "0") - .push_map() - .build()); - - EPVA::Configuration::shared_pointer serverConfig(ConfigurationBuilder() - .push_config(baseConfig) - .push_map() - .build()); - - TestServer::shared_pointer testServer(new TestServer(serverConfig)); - std::ostringstream portStr; - portStr << "127.0.0.1:" << testServer->getServerPort(); - testDiag("Test server is using ports TCP: %u, TCP Search: %u, UDP Broadcast: %u", - testServer->getServerPort(), - testServer->getSearchServerPort(), - testServer->getBroadcastPort()); - - EPVA::Configuration::shared_pointer clientConfig(ConfigurationBuilder() - .push_config(baseConfig) - .add("EPICS_PVA_ADDR_LIST", portStr.str()) - .push_map() - .build()); - - ConfigurationFactory::registerConfiguration("pvAccess-client", clientConfig); - testDiag("Starting client factory"); - epics::pvAccess::ClientFactory::start(); - - return cdTest.runAllTests(); -} - -MAIN(testDcChannelDiscovery) -{ - try{ - SET_LOG_LEVEL(logLevelError); - return runAllTests(); - } - catch(std::exception& e) { - PRINT_EXCEPTION(e); - std::cerr << "Unhandled exception: " << e.what() << "\n"; - return 1; - } -} From 899cde9d0c052c2cdcbbd2b32590a7e23481024a Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 15 Apr 2024 09:24:09 -0500 Subject: [PATCH 69/82] remove search acceptor; name server searches have to go through the regular server port --- src/server/pv/serverContext.h | 6 ---- src/server/pv/serverContextImpl.h | 19 +---------- src/server/serverContext.cpp | 39 +--------------------- testApp/remote/nsChannelDiscoveryTest.cpp | 5 ++- testApp/remote/testServer.cpp | 5 --- testApp/remote/udpChannelDiscoveryTest.cpp | 3 +- 6 files changed, 5 insertions(+), 72 deletions(-) diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index bc1f7f0b..810a3e34 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -76,12 +76,6 @@ class epicsShareClass ServerContext */ virtual epics::pvData::int32 getServerPort() = 0; - /** - * Get search server port. - * @return search server port. - */ - virtual epics::pvData::int32 getSearchServerPort() = 0; - /** * Get broadcast port. * @return broadcast port. diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 18f074a5..66e4ff45 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -37,7 +37,7 @@ class ServerContextImpl : ServerContextImpl(); virtual ~ServerContextImpl(); - void initialize(const ResponseHandler::shared_pointer& responseHandler = ResponseHandler::shared_pointer(), const ResponseHandler::shared_pointer& searchResponseHandler = ResponseHandler::shared_pointer()); + void initialize(const ResponseHandler::shared_pointer& responseHandler = ResponseHandler::shared_pointer()); //**************** derived from ServerContext ****************// const ServerGUID& getGUID() OVERRIDE FINAL; @@ -86,12 +86,6 @@ class ServerContextImpl : */ epics::pvData::int32 getServerPort() OVERRIDE FINAL; - /** - * Get search server port. - * @return search server port. - */ - epics::pvData::int32 getSearchServerPort() OVERRIDE FINAL; - /** * Get broadcast port. * @return broadcast port. @@ -189,11 +183,6 @@ class ServerContextImpl : */ epics::pvData::int32 _serverPort; - /** - * Search server port. - */ - epics::pvData::int32 _searchServerPort; - /** * Length in bytes of the maximum buffer (payload) size that may pass through PVA. */ @@ -224,16 +213,10 @@ class ServerContextImpl : */ TransportRegistry _transportRegistry; - /** - * TCP search acceptor - */ - BlockingTCPAcceptor::shared_pointer _searchAcceptor; - /** * Response handlers */ ResponseHandler::shared_pointer _responseHandler; - ResponseHandler::shared_pointer _searchResponseHandler; // const after loadConfiguration() std::vector _channelProviders; diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index a8671dbc..c081a20b 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -39,13 +39,11 @@ ServerContextImpl::ServerContextImpl(): _broadcastPort(PVA_BROADCAST_PORT), _senderPort(PVA_UDP_SENDER_PORT), _serverPort(PVA_SERVER_PORT), - _searchServerPort(PVA_BROADCAST_PORT), _receiveBufferSize(MAX_TCP_RECV), _timer(new Timer("PVAS timers", lowerPriority)), _beaconEmitter(), _acceptor(), _transportRegistry(), - _searchAcceptor(), _channelProviders(), _beaconServerStatusProvider(), _startTime() @@ -149,12 +147,6 @@ void ServerContextImpl::loadConfiguration() _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVA_MAX_ARRAY_BYTES", _receiveBufferSize); _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVAS_MAX_ARRAY_BYTES", _receiveBufferSize); - // TCP search - memset(&_searchIfaceAddr, 0, sizeof(_searchIfaceAddr)); - _searchIfaceAddr.ia.sin_family = AF_INET; - _searchIfaceAddr.ia.sin_addr.s_addr = _ifaceAddr.ia.sin_addr.s_addr; - _searchIfaceAddr.ia.sin_port = htons(_broadcastPort); - if(_channelProviders.empty()) { std::string providers = config->getPropertyAsString("EPICS_PVAS_PROVIDER_NAMES", PVACCESS_DEFAULT_PROVIDER); @@ -271,7 +263,7 @@ bool ServerContextImpl::isChannelProviderNamePreconfigured() return config->hasProperty("EPICS_PVAS_PROVIDER_NAMES"); } -void ServerContextImpl::initialize(const ResponseHandler::shared_pointer& responseHandler, const ResponseHandler::shared_pointer& searchResponseHandler) +void ServerContextImpl::initialize(const ResponseHandler::shared_pointer& responseHandler) { Lock guard(_mutex); @@ -288,24 +280,11 @@ void ServerContextImpl::initialize(const ResponseHandler::shared_pointer& respon { _responseHandler.reset(new ServerResponseHandler(thisServerContext)); } - if (searchResponseHandler) - { - _searchResponseHandler = searchResponseHandler; - } - else - { - _searchResponseHandler.reset(new ServerSearchResponseHandler(thisServerContext)); - } _acceptor.reset(new BlockingTCPAcceptor(thisServerContext, _responseHandler, _ifaceAddr, _receiveBufferSize)); _serverPort = ntohs(_acceptor->getBindAddress()->ia.sin_port); LOG(logLevelDebug, "Server port: %d", _serverPort); - // TCP search listener - _searchAcceptor.reset(new BlockingTCPAcceptor(thisServerContext, _searchResponseHandler, _searchIfaceAddr, MAX_TCP_RECV)); - _searchServerPort = ntohs(_searchAcceptor->getBindAddress()->ia.sin_port); - LOG(logLevelDebug, "Search server port: %d", _searchServerPort); - // setup broadcast UDP transport initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, _broadcastPort, _senderPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); @@ -375,14 +354,6 @@ void ServerContextImpl::shutdown() _acceptor.reset(); } - // clear search acceptor - if (_searchAcceptor) - { - _searchAcceptor->destroy(); - LEAK_CHECK(_searchAcceptor, "_searchAcceptor") - _searchAcceptor.reset(); - } - // this will also destroy all channels _transportRegistry.clear(); @@ -392,9 +363,6 @@ void ServerContextImpl::shutdown() // response handlers hold strong references to us, // so must break the cycles - LEAK_CHECK(_searchResponseHandler, "_searchResponseHandler") - _searchResponseHandler.reset(); - LEAK_CHECK(_responseHandler, "_responseHandler") _responseHandler.reset(); @@ -520,11 +488,6 @@ int32 ServerContextImpl::getServerPort() return _serverPort; } -int32 ServerContextImpl::getSearchServerPort() -{ - return _searchServerPort; -} - int32 ServerContextImpl::getBroadcastPort() { return _broadcastPort; diff --git a/testApp/remote/nsChannelDiscoveryTest.cpp b/testApp/remote/nsChannelDiscoveryTest.cpp index 5b075f4e..c74ec0b0 100644 --- a/testApp/remote/nsChannelDiscoveryTest.cpp +++ b/testApp/remote/nsChannelDiscoveryTest.cpp @@ -39,10 +39,9 @@ int runAllTests() { TestServer::shared_pointer testServer(new TestServer(serverConfig)); std::ostringstream portStr; - portStr << "127.0.0.1:" << testServer->getSearchServerPort(); - testDiag("Test server is using ports TCP: %u, TCP Search: %u, UDP Broadcast: %u", + portStr << "127.0.0.1:" << testServer->getServerPort(); + testDiag("Test server is using ports TCP: %u, UDP Broadcast: %u", testServer->getServerPort(), - testServer->getSearchServerPort(), testServer->getBroadcastPort()); EPVA::Configuration::shared_pointer clientConfig(ConfigurationBuilder() diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index ec7901a6..2e0c157a 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -2731,11 +2731,6 @@ struct TestServer { return context->getServerPort(); } - // Use with EPICS_PVA_BROADCAST_PORT==0 for dynamic port (unit-tests) - unsigned short getSearchServerPort() - { - return context->getSearchServerPort(); - } unsigned short getBroadcastPort() { return context->getBroadcastPort(); diff --git a/testApp/remote/udpChannelDiscoveryTest.cpp b/testApp/remote/udpChannelDiscoveryTest.cpp index 44b762be..480a8d9c 100644 --- a/testApp/remote/udpChannelDiscoveryTest.cpp +++ b/testApp/remote/udpChannelDiscoveryTest.cpp @@ -39,9 +39,8 @@ int runAllTests() { .build()); TestServer::shared_pointer testServer(new TestServer(serverConfig)); - testDiag("Test server is using ports TCP: %u, TCP Search: %u, UDP Broadcast: %u", + testDiag("Test server is using ports TCP: %u, UDP Broadcast: %u", testServer->getServerPort(), - testServer->getSearchServerPort(), testServer->getBroadcastPort()); EPVA::Configuration::shared_pointer clientConfig(ConfigurationBuilder() From 487b11e6e32ca188a6349ac5172a91be1a9153d3 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 15 Apr 2024 09:31:15 -0500 Subject: [PATCH 70/82] remove unused method --- src/server/pv/serverContext.h | 6 ------ src/server/pv/serverContextImpl.h | 6 ------ src/server/serverContext.cpp | 5 ----- 3 files changed, 17 deletions(-) diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index 810a3e34..5369103b 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -82,12 +82,6 @@ class epicsShareClass ServerContext */ virtual epics::pvData::int32 getBroadcastPort() = 0; - /** - * Get UDP sender port. - * @return UDP sender port. - */ - virtual epics::pvData::int32 getSenderPort() = 0; - /** Return a Configuration with the actual values being used, * including defaults used, and bounds limits applied. */ diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 66e4ff45..00289074 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -92,12 +92,6 @@ class ServerContextImpl : */ epics::pvData::int32 getBroadcastPort() OVERRIDE FINAL; - /** - * Get UDP sender port. - * @return UDP sender port. - */ - epics::pvData::int32 getSenderPort() OVERRIDE FINAL; - /** * Get registered beacon server status provider. * @return registered beacon server status provider. diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index c081a20b..b5294bcc 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -493,11 +493,6 @@ int32 ServerContextImpl::getBroadcastPort() return _broadcastPort; } -int32 ServerContextImpl::getSenderPort() -{ - return _senderPort; -} - BeaconServerStatusProvider::shared_pointer ServerContextImpl::getBeaconServerStatusProvider() { return _beaconServerStatusProvider; From 4e8569abc6a827b07e8f2bccb0305154ac01e741 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 15 Apr 2024 09:43:46 -0500 Subject: [PATCH 71/82] add default implementation of isUsed() --- src/remote/pv/blockingUDP.h | 5 ----- src/remote/pv/codec.h | 5 ----- src/remote/pv/remote.h | 2 +- src/server/pv/serverContextImpl.h | 1 - 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index 4bbf0bce..c204c51f 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -196,11 +196,6 @@ class BlockingUDPTransport : virtual void release(pvAccessID /*clientId*/) OVERRIDE FINAL {} - virtual bool isUsed() OVERRIDE FINAL - { - return false; - } - /** * Set ignore list. * @param address list of ignored addresses. diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index 51d390b3..06fe5c79 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -477,11 +477,6 @@ class BlockingServerTCPTransportCodec : virtual void release(pvAccessID /*clientId*/) OVERRIDE FINAL {} - virtual bool isUsed() OVERRIDE FINAL - { - return false; - } - pvAccessID preallocateChannelSID(); void depreallocateChannelSID(pvAccessID /*sid*/) {} diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 3ff68413..4e4fe1c1 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -186,7 +186,7 @@ class epicsShareClass Transport : public epics::pvData::DeserializableControl { /** * Is transport used */ - virtual bool isUsed() = 0; + virtual bool isUsed() {return false;} /** * Get protocol type (tcp, udp, ssl, etc.). diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 00289074..4efdd786 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -144,7 +144,6 @@ class ServerContextImpl : IfaceNodeVector _ifaceList; osiSockAddr _ifaceAddr; - osiSockAddr _searchIfaceAddr; /** * A space-separated list of address from which to ignore name resolution requests. From 046c1f2590fcbc54a14d1c1697883cfae508ade5 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Mon, 15 Apr 2024 09:49:50 -0500 Subject: [PATCH 72/82] add default implementation name server search methods --- src/remote/pv/remote.h | 4 ++-- src/server/pv/serverContextImpl.h | 2 -- src/server/serverContext.cpp | 10 ---------- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 4e4fe1c1..86f6d905 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -309,8 +309,8 @@ class Context { virtual std::tr1::shared_ptr getChannel(pvAccessID id) = 0; virtual Transport::shared_pointer getSearchTransport() = 0; - virtual Transport::shared_pointer getNameServerSearchTransport() = 0; - virtual void releaseNameServerSearchTransport() = 0; + virtual Transport::shared_pointer getNameServerSearchTransport() {return Transport::shared_pointer();} + virtual void releaseNameServerSearchTransport() {} }; /** diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 4efdd786..65af3b8e 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -50,8 +50,6 @@ class ServerContextImpl : epics::pvData::Timer::shared_pointer getTimer() OVERRIDE FINAL; Channel::shared_pointer getChannel(pvAccessID id) OVERRIDE FINAL; Transport::shared_pointer getSearchTransport() OVERRIDE FINAL; - Transport::shared_pointer getNameServerSearchTransport() OVERRIDE FINAL; - void releaseNameServerSearchTransport() OVERRIDE FINAL; Configuration::const_shared_pointer getConfiguration() OVERRIDE FINAL; TransportRegistry* getTransportRegistry() OVERRIDE FINAL; static ServerContextImpl::shared_pointer create(const Config& conf = Config()); diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index b5294bcc..7d3e9628 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -539,16 +539,6 @@ Transport::shared_pointer ServerContextImpl::getSearchTransport() return Transport::shared_pointer(); } -Transport::shared_pointer ServerContextImpl::getNameServerSearchTransport() -{ - // not used - return Transport::shared_pointer(); -} - -void ServerContextImpl::releaseNameServerSearchTransport() -{ -} - void ServerContextImpl::newServerDetected() { // not used From 80c708cfc77cc0b55611bc5175e1c539ead22cc6 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 17 Apr 2024 17:08:35 -0500 Subject: [PATCH 73/82] remove pvaConstants.cpp, restore pvaVersion.cpp, remove PVA_UDP_SENDER_PORT constant --- src/pva/Makefile | 1 - src/pva/pv/pvaConstants.h | 10 ++++------ src/pva/pvaConstants.cpp | 16 ---------------- src/pva/pvaVersion.cpp | 4 ++++ 4 files changed, 8 insertions(+), 23 deletions(-) delete mode 100644 src/pva/pvaConstants.cpp diff --git a/src/pva/Makefile b/src/pva/Makefile index e538dfce..0a030ff9 100644 --- a/src/pva/Makefile +++ b/src/pva/Makefile @@ -8,6 +8,5 @@ INC += pv/pvaVersion.h INC += pv/pvaVersionNum.h INC += pv/clientFactory.h -pvAccess_SRCS += pvaConstants.cpp pvAccess_SRCS += pvaVersion.cpp pvAccess_SRCS += clientFactory.cpp diff --git a/src/pva/pv/pvaConstants.h b/src/pva/pv/pvaConstants.h index 878a03cf..5aafe1e1 100644 --- a/src/pva/pv/pvaConstants.h +++ b/src/pva/pv/pvaConstants.h @@ -22,7 +22,8 @@ #endif #include -namespace epics { namespace pvAccess { +namespace epics { +namespace pvAccess { /** PVA protocol magic number */ const epics::pvData::int8 PVA_MAGIC = static_cast(0xCA); @@ -42,9 +43,6 @@ const epics::pvData::int32 PVA_SERVER_PORT = 5075; /** Default PVA beacon port. */ const epics::pvData::int32 PVA_BROADCAST_PORT = 5076; -/** Default UDP sender port. */ -const epics::pvData::int32 PVA_UDP_SENDER_PORT = 0; - /** PVA protocol message header size. */ const epics::pvData::int16 PVA_MESSAGE_HEADER_SIZE = 8; @@ -88,7 +86,7 @@ epicsShareExtern const std::string PVACCESS_ALL_PROVIDERS; /** Name of the system env. variable to turn on debugging. */ epicsShareExtern const std::string PVACCESS_DEBUG; - -}} +} +} #endif /* PVACONSTANTS_H_ */ diff --git a/src/pva/pvaConstants.cpp b/src/pva/pvaConstants.cpp deleted file mode 100644 index 7b4e5ac8..00000000 --- a/src/pva/pvaConstants.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/** -* Copyright - See the COPYRIGHT that is included with this distribution. -* pvAccessCPP is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -*/ - -#define epicsExportSharedSymbols -#include - -namespace epics { namespace pvAccess { - -const std::string PVACCESS_DEFAULT_PROVIDER("local"); -const std::string PVACCESS_ALL_PROVIDERS(""); -const std::string PVACCESS_DEBUG("EPICS_PVA_DEBUG"); - -}} diff --git a/src/pva/pvaVersion.cpp b/src/pva/pvaVersion.cpp index f15f9fc1..815a3a5d 100644 --- a/src/pva/pvaVersion.cpp +++ b/src/pva/pvaVersion.cpp @@ -16,6 +16,10 @@ using std::string; namespace epics { namespace pvAccess { +const std::string PVACCESS_DEFAULT_PROVIDER("local"); +const std::string PVACCESS_ALL_PROVIDERS(""); +const std::string PVACCESS_DEBUG("EPICS_PVA_DEBUG"); + Version::Version(std::string const & productName, std::string const & implementationLangugage, int majorVersion, int minorVersion, From 5f001f5c38f3f6411257a5050c5dd6da4bf726fb Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 17 Apr 2024 17:09:27 -0500 Subject: [PATCH 74/82] remove udp sender port variables --- src/remote/abstractResponseHandler.cpp | 1 - src/remote/blockingUDPTransport.cpp | 3 +-- src/remote/pv/blockingUDP.h | 3 +-- src/remote/pv/codec.h | 2 +- src/remote/pv/remote.h | 1 + src/remoteClient/clientContextImpl.cpp | 9 ++------- src/server/pv/serverContextImpl.h | 5 ----- src/server/serverContext.cpp | 3 +-- 8 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/remote/abstractResponseHandler.cpp b/src/remote/abstractResponseHandler.cpp index 7d3f1686..6b93c320 100644 --- a/src/remote/abstractResponseHandler.cpp +++ b/src/remote/abstractResponseHandler.cpp @@ -10,7 +10,6 @@ #include #define epicsExportSharedSymbols -#include #include #include diff --git a/src/remote/blockingUDPTransport.cpp b/src/remote/blockingUDPTransport.cpp index f7d2cf9d..caa2d0d3 100644 --- a/src/remote/blockingUDPTransport.cpp +++ b/src/remote/blockingUDPTransport.cpp @@ -580,7 +580,6 @@ void initializeUDPTransports(bool serverFlag, const ResponseHandler::shared_pointer& responseHandler, BlockingUDPTransport::shared_pointer& sendTransport, int32& listenPort, - int32& senderPort, bool autoAddressList, const std::string& addressList, const std::string& ignoreAddressList) @@ -596,7 +595,7 @@ void initializeUDPTransports(bool serverFlag, osiSockAddr anyAddress; memset(&anyAddress, 0, sizeof(anyAddress)); anyAddress.ia.sin_family = AF_INET; - anyAddress.ia.sin_port = htons(senderPort); + anyAddress.ia.sin_port = htons(0); anyAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY); sendTransport = connector.connect(responseHandler, anyAddress, protoVer); diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index c204c51f..97cedeb7 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -76,7 +76,7 @@ class BlockingUDPTransport : } virtual std::string getType() const OVERRIDE FINAL { - return "udp"; + return std::string("udp"); } virtual std::size_t getReceiveBufferSize() const OVERRIDE FINAL { @@ -401,7 +401,6 @@ void initializeUDPTransports( const ResponseHandler::shared_pointer& responseHandler, BlockingUDPTransport::shared_pointer& sendTransport, epics::pvData::int32& listenPort, - epics::pvData::int32& senderPort, bool autoAddressList, const std::string& addressList, const std::string& ignoreAddressList); diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index 06fe5c79..0eb8f886 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -303,7 +303,7 @@ class BlockingTCPTransportCodec: virtual void invalidDataStreamHandler() OVERRIDE FINAL; virtual std::string getType() const OVERRIDE FINAL { - return "tcp"; + return std::string("tcp"); } virtual void processControlMessage() OVERRIDE FINAL { diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 86f6d905..f67624e7 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -29,6 +29,7 @@ # undef remoteEpicsExportSharedSymbols #endif +#include #include #include diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 4d4f6f2c..bd32d496 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -4090,7 +4090,7 @@ class InternalClientContextImpl : InternalClientContextImpl(const Configuration::shared_pointer& conf) : m_addressList(""), m_autoAddressList(true), m_serverPort(PVA_SERVER_PORT), m_nsAddressList(""), m_nsAddressIndex(0), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), - m_broadcastPort(PVA_BROADCAST_PORT), m_senderPort(PVA_UDP_SENDER_PORT), m_receiveBufferSize(MAX_TCP_RECV), + m_broadcastPort(PVA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), m_lastCID(0x10203040), m_lastIOID(0x80706050), m_version("pvAccess Client", "cpp", @@ -4366,7 +4366,7 @@ class InternalClientContextImpl : epicsSocketDestroy (socket); initializeUDPTransports(false, m_udpTransports, ifaceList, m_responseHandler, m_searchTransport, - m_broadcastPort, m_senderPort, m_autoAddressList, m_addressList, std::string()); + m_broadcastPort, m_autoAddressList, m_addressList, std::string()); } @@ -4699,11 +4699,6 @@ class InternalClientContextImpl : */ int32 m_broadcastPort; - /** - * UDP sender port - */ - int32 m_senderPort; - /** * Receive buffer size (max size of payload). */ diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 65af3b8e..c8ebfd8a 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -164,11 +164,6 @@ class ServerContextImpl : */ epics::pvData::int32 _broadcastPort; - /** - * UDP sender port. - */ - epics::pvData::int32 _senderPort; - /** * Port number for the server to listen to. */ diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 7d3e9628..b25ed7c6 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -37,7 +37,6 @@ ServerContextImpl::ServerContextImpl(): _autoBeaconAddressList(true), _beaconPeriod(15.0), _broadcastPort(PVA_BROADCAST_PORT), - _senderPort(PVA_UDP_SENDER_PORT), _serverPort(PVA_SERVER_PORT), _receiveBufferSize(MAX_TCP_RECV), _timer(new Timer("PVAS timers", lowerPriority)), @@ -286,7 +285,7 @@ void ServerContextImpl::initialize(const ResponseHandler::shared_pointer& respon LOG(logLevelDebug, "Server port: %d", _serverPort); // setup broadcast UDP transport - initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, _broadcastPort, _senderPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); + initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, _broadcastPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); _beaconEmitter.reset(new BeaconEmitter("tcp", _broadcastTransport, thisServerContext)); From fd15386cb4363b9afea5241124a56d72c4315e88 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 16 May 2024 10:17:54 -0500 Subject: [PATCH 75/82] remove unused utility method for converting string to inet address --- src/utils/inetAddressUtil.cpp | 16 ---------------- src/utils/pv/inetAddressUtil.h | 16 ---------------- testApp/utils/testInetAddressUtils.cpp | 20 +++----------------- 3 files changed, 3 insertions(+), 49 deletions(-) diff --git a/src/utils/inetAddressUtil.cpp b/src/utils/inetAddressUtil.cpp index 9b7af7b8..1bf9f307 100644 --- a/src/utils/inetAddressUtil.cpp +++ b/src/utils/inetAddressUtil.cpp @@ -129,22 +129,6 @@ string inetAddressToString(const osiSockAddr &addr, return saddr.str(); } -bool stringToInetAddress(const std::string& addrStr, osiSockAddr& addr) { - - if (addrStr.empty()) { - return false; - } - unsigned short defaultPort = 0; - if(addr.sa.sa_family == AF_INET) { - defaultPort = ntohs(addr.ia.sin_port); - } - addr.ia.sin_family = AF_INET; - if (aToIPAddr(addrStr.c_str(), defaultPort, &addr.ia)) { - return false; - } - return true; -} - ifaceNode::ifaceNode() { memset(&addr, 0, sizeof(addr)); diff --git a/src/utils/pv/inetAddressUtil.h b/src/utils/pv/inetAddressUtil.h index 05229dc2..ecdcd216 100644 --- a/src/utils/pv/inetAddressUtil.h +++ b/src/utils/pv/inetAddressUtil.h @@ -66,25 +66,9 @@ epicsShareFunc bool isMulticastAddress(const osiSockAddr* address); epicsShareFunc void getSocketAddressList(InetAddrVector& ret, const std::string & list, int defaultPort, const InetAddrVector* appendList = NULL); -/** - * Convert socket address to string. - * @param addr inet address - * @param displayPort flag to display port number (default: true) - * @param displayHex flag to display hex format (default: false) - * @return inet address string - */ epicsShareFunc std::string inetAddressToString(const osiSockAddr &addr, bool displayPort = true, bool displayHex = false); -/** - * Convert string to socket address - * @param addrStr input address[:port] string - * @param addr resulting inet address - * @return true if conversion was successful, false otherwise - */ -epicsShareFunc bool stringToInetAddress(const std::string& addrStr, - osiSockAddr& addr); - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // comparators for osiSockAddr diff --git a/testApp/utils/testInetAddressUtils.cpp b/testApp/utils/testInetAddressUtils.cpp index f296e4ec..94176799 100644 --- a/testApp/utils/testInetAddressUtils.cpp +++ b/testApp/utils/testInetAddressUtils.cpp @@ -39,39 +39,25 @@ void test_getSocketAddressList() testOk1(static_cast(3) == vec.size()); osiSockAddr addr; - osiSockAddr addr2; addr = vec.at(0); testOk1(AF_INET == addr.ia.sin_family); testOk1(htons(555) == addr.ia.sin_port); testOk1(htonl(0x7F000001) == addr.ia.sin_addr.s_addr); testOk1("127.0.0.1:555" == inetAddressToString(addr)); - testOk1(stringToInetAddress("127.0.0.1:555", addr2)); - testOk1(AF_INET == addr2.ia.sin_family); - testOk1(htons(555) == addr2.ia.sin_port); - testOk1(htonl(0x7F000001) == addr2.ia.sin_addr.s_addr); - testOk1(sockAddrAreIdentical(&addr2, &addr)); addr = vec.at(1); testOk1(AF_INET == addr.ia.sin_family); testOk1(htons(1234) == addr.ia.sin_port); testOk1(htonl(0x0A0A0C0B) == addr.ia.sin_addr.s_addr); testOk1("10.10.12.11:1234" == inetAddressToString(addr)); - testOk1(stringToInetAddress("10.10.12.11:1234", addr2)); - testOk1(AF_INET == addr2.ia.sin_family); - testOk1(htons(1234) == addr2.ia.sin_port); - testOk1(htonl(0x0A0A0C0B) == addr2.ia.sin_addr.s_addr); - testOk1(sockAddrAreIdentical(&addr2, &addr)); addr = vec.at(2); testOk1(AF_INET == addr.ia.sin_family); testOk1(htons(555) == addr.ia.sin_port); testOk1(htonl(0xC0A80304) == addr.ia.sin_addr.s_addr); testOk1("192.168.3.4:555" == inetAddressToString(addr)); - testOk1(stringToInetAddress("192.168.3.4:555", addr2)); - testOk1(AF_INET == addr2.ia.sin_family); - testOk1(htons(555) == addr2.ia.sin_port); - testOk1(htonl(0xC0A80304) == addr2.ia.sin_addr.s_addr); - testOk1(sockAddrAreIdentical(&addr2, &addr)); + + InetAddrVector vec1; @@ -373,7 +359,7 @@ void test_discoverInterfaces() MAIN(testInetAddressUtils) { - testPlan(80); + testPlan(65); testDiag("Tests for InetAddress utils"); test_getSocketAddressList(); From 0179b3ca38f3e0d628f6ce14d8516e2c0ce40623 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 16 May 2024 10:20:57 -0500 Subject: [PATCH 76/82] remove unused methods, restore original initialize() method for server context impl class --- src/remote/pv/remote.h | 3 +-- src/server/pv/serverContext.h | 2 -- src/server/pv/serverContextImpl.h | 7 +----- src/server/serverContext.cpp | 38 ++++--------------------------- 4 files changed, 6 insertions(+), 44 deletions(-) diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index f67624e7..d5d08c43 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -22,7 +22,6 @@ #include #include #include -#include #ifdef remoteEpicsExportSharedSymbols # define epicsExportSharedSymbols @@ -32,6 +31,7 @@ #include #include #include +#include /// TODO only here because of the Lockable #include @@ -282,7 +282,6 @@ class epicsShareClass Transport : public epics::pvData::DeserializableControl { class Channel; class SecurityPlugin; class AuthenticationRegistry; -class Configuration; /** * Not public IF, used by Transports, etc. diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index 5369103b..bbe361fb 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -112,8 +112,6 @@ class epicsShareClass ServerContext Config& providers(const std::vector& p) { _providers = p; return *this; } //! short hand for providers() with a length 1 vector. Config& provider(const ChannelProvider::shared_pointer& p) { _providers.push_back(p); return *this; } - Configuration::const_shared_pointer getConfiguration() const {return _conf;}; - std::vector getProviders() const {return _providers;} }; /** Start a new PVA server diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index c8ebfd8a..c148c18b 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -37,11 +37,10 @@ class ServerContextImpl : ServerContextImpl(); virtual ~ServerContextImpl(); - void initialize(const ResponseHandler::shared_pointer& responseHandler = ResponseHandler::shared_pointer()); - //**************** derived from ServerContext ****************// const ServerGUID& getGUID() OVERRIDE FINAL; const Version& getVersion() OVERRIDE FINAL; + void initialize(); void run(epics::pvData::uint32 seconds) OVERRIDE FINAL; void shutdown() OVERRIDE FINAL; void printInfo(std::ostream& str, int lvl) OVERRIDE FINAL; @@ -52,7 +51,6 @@ class ServerContextImpl : Transport::shared_pointer getSearchTransport() OVERRIDE FINAL; Configuration::const_shared_pointer getConfiguration() OVERRIDE FINAL; TransportRegistry* getTransportRegistry() OVERRIDE FINAL; - static ServerContextImpl::shared_pointer create(const Config& conf = Config()); virtual void newServerDetected() OVERRIDE FINAL; @@ -199,9 +197,6 @@ class ServerContextImpl : */ TransportRegistry _transportRegistry; - /** - * Response handlers - */ ResponseHandler::shared_pointer _responseHandler; // const after loadConfiguration() diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index b25ed7c6..82151e9f 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -262,7 +262,7 @@ bool ServerContextImpl::isChannelProviderNamePreconfigured() return config->hasProperty("EPICS_PVAS_PROVIDER_NAMES"); } -void ServerContextImpl::initialize(const ResponseHandler::shared_pointer& responseHandler) +void ServerContextImpl::initialize() { Lock guard(_mutex); @@ -271,21 +271,14 @@ void ServerContextImpl::initialize(const ResponseHandler::shared_pointer& respon ServerContextImpl::shared_pointer thisServerContext = shared_from_this(); // we create reference cycles here which are broken by our shutdown() method, - if (responseHandler) - { - _responseHandler = responseHandler; - } - else - { - _responseHandler.reset(new ServerResponseHandler(thisServerContext)); - } + _responseHandler.reset(new ServerResponseHandler(thisServerContext)); _acceptor.reset(new BlockingTCPAcceptor(thisServerContext, _responseHandler, _ifaceAddr, _receiveBufferSize)); _serverPort = ntohs(_acceptor->getBindAddress()->ia.sin_port); - LOG(logLevelDebug, "Server port: %d", _serverPort); // setup broadcast UDP transport - initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, _broadcastPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); + initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, + _broadcastPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); _beaconEmitter.reset(new BeaconEmitter("tcp", _broadcastTransport, thisServerContext)); @@ -582,29 +575,6 @@ struct shutdown_dtor { }; } -ServerContextImpl::shared_pointer ServerContextImpl::create(const Config &conf) -{ - ServerContextImpl::shared_pointer ret(new ServerContextImpl()); - ret->configuration = conf.getConfiguration(); - ret->_channelProviders = conf.getProviders(); - - if (!ret->configuration) - { - ConfigurationProvider::shared_pointer configurationProvider = ConfigurationFactory::getProvider(); - ret->configuration = configurationProvider->getConfiguration("pvAccess-server"); - if (!ret->configuration) - { - ret->configuration = configurationProvider->getConfiguration("system"); - } - } - if(!ret->configuration) { - ret->configuration = ConfigurationBuilder().push_env().build(); - } - - ret->loadConfiguration(); - return ret; -} - ServerContext::shared_pointer ServerContext::create(const Config &conf) { ServerContextImpl::shared_pointer ret(new ServerContextImpl()); From fe0be2679b4684339b65c7844fec516a43021125 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 16 May 2024 10:58:45 -0500 Subject: [PATCH 77/82] remove unused server search response handler class --- src/server/pv/responseHandlers.h | 30 ---------------- src/server/responseHandlers.cpp | 62 -------------------------------- 2 files changed, 92 deletions(-) diff --git a/src/server/pv/responseHandlers.h b/src/server/pv/responseHandlers.h index 86c0d51b..9888d5f0 100644 --- a/src/server/pv/responseHandlers.h +++ b/src/server/pv/responseHandlers.h @@ -839,36 +839,6 @@ class ServerResponseHandler : public ResponseHandler { }; -/** - * PVAS search request handler - */ -class ServerSearchResponseHandler : public ResponseHandler { -public: - ServerSearchResponseHandler(ServerContextImpl::shared_pointer const & context); - - virtual ~ServerSearchResponseHandler() {} - - virtual void handleResponse(osiSockAddr* responseFrom, - Transport::shared_pointer const & transport, epics::pvData::int8 version, epics::pvData::int8 command, - std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) OVERRIDE FINAL; -private: - ServerBadResponse handle_bad; - - ServerNoopResponse handle_beacon; - ServerConnectionValidationHandler handle_validation; - ServerEchoHandler handle_echo; - ServerSearchHandler handle_search; - AuthNZHandler handle_authnz; - ServerCreateChannelHandler handle_create; - ServerDestroyChannelHandler handle_destroy; - ServerRPCHandler handle_rpc; - /** - * Table of response handlers for each command ID. - */ - std::vector m_handlerTable; - -}; - } } diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 89ded60c..0b4b31bb 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -172,68 +172,6 @@ void ServerResponseHandler::handleResponse(osiSockAddr* responseFrom, version, command, payloadSize, payloadBuffer); } -ServerSearchResponseHandler::ServerSearchResponseHandler(ServerContextImpl::shared_pointer const & context) - :ResponseHandler(context.get(), "ServerSearchResponseHandler") - ,handle_bad(context) - ,handle_beacon(context, "Beacon") - ,handle_validation(context) - ,handle_echo(context) - ,handle_search(context) - ,handle_authnz(context.get()) - ,handle_create(context) - ,handle_destroy(context) - ,handle_rpc(context) - ,m_handlerTable(CMD_CANCEL_REQUEST+1, &handle_bad) -{ - m_handlerTable[CMD_BEACON] = &handle_bad; /* 0 */ - m_handlerTable[CMD_CONNECTION_VALIDATION] = &handle_validation; /* 1 */ - m_handlerTable[CMD_ECHO] = &handle_echo; /* 2 */ - m_handlerTable[CMD_SEARCH] = &handle_search; /* 3 */ - m_handlerTable[CMD_SEARCH_RESPONSE] = &handle_bad; - m_handlerTable[CMD_AUTHNZ] = &handle_authnz; /* 5 */ - m_handlerTable[CMD_ACL_CHANGE] = &handle_bad; /* 6 - access right change */ - m_handlerTable[CMD_CREATE_CHANNEL] = &handle_create; /* 7 */ - m_handlerTable[CMD_DESTROY_CHANNEL] = &handle_destroy; /* 8 */ - m_handlerTable[CMD_CONNECTION_VALIDATED] = &handle_bad; /* 9 */ - - m_handlerTable[CMD_GET] = &handle_bad; /* 10 - get response */ - m_handlerTable[CMD_PUT] = &handle_bad; /* 11 - put response */ - m_handlerTable[CMD_PUT_GET] = &handle_bad; /* 12 - put-get response */ - m_handlerTable[CMD_MONITOR] = &handle_bad; /* 13 - monitor response */ - m_handlerTable[CMD_ARRAY] = &handle_bad; /* 14 - array response */ - m_handlerTable[CMD_DESTROY_REQUEST] = &handle_bad; /* 15 - destroy request */ - m_handlerTable[CMD_PROCESS] = &handle_bad; /* 16 - process response */ - m_handlerTable[CMD_GET_FIELD] = &handle_bad; /* 17 - get field response */ - m_handlerTable[CMD_MESSAGE] = &handle_bad; /* 18 - message to Requester */ - m_handlerTable[CMD_MULTIPLE_DATA] = &handle_bad; /* 19 - grouped monitors */ - - m_handlerTable[CMD_RPC] = &handle_rpc; /* 20 - RPC response */ - m_handlerTable[CMD_CANCEL_REQUEST] = &handle_bad; /* 21 - cancel request */ -} - -void ServerSearchResponseHandler::handleResponse(osiSockAddr* responseFrom, - Transport::shared_pointer const & transport, int8 version, int8 command, - size_t payloadSize, ByteBuffer* payloadBuffer) -{ - if(command<0||command>=(int8)m_handlerTable.size()) - { - LOG(logLevelError, - "Invalid (or unsupported) command: %x.", (0xFF&command)); - - if(IS_LOGGABLE(logLevelError)) { - std::ios::fmtflags initialflags = std::cerr.flags(); - std::cerr<<"Invalid (or unsupported) command: "<handleResponse(responseFrom, transport, - version, command, payloadSize, payloadBuffer); -} - void ServerConnectionValidationHandler::handleResponse( osiSockAddr* responseFrom, Transport::shared_pointer const & transport, int8 version, int8 command, size_t payloadSize, From 39c610692e572d5c6c92187036360887e257e699 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 16 May 2024 18:19:40 -0500 Subject: [PATCH 78/82] reduce logging for request start --- src/remoteClient/clientContextImpl.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index bd32d496..6a1ec4a4 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -234,10 +234,9 @@ class BaseRequestImpl : {/* cancel overrides all but destroy */} else if(m_pendingRequest==NULL_REQUEST) {/* anything whenidle */} - else { - LOG(logLevelError, "Request qos %d cannot be started, pending request %d", int(qos), int(m_pendingRequest)); - return false; /* others not allowed */ - } + else + {return false; /* others not allowed */} + m_pendingRequest = qos; return true; } From 238340713c9260ba0bf39f7400c7d70a540d33a6 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 16 May 2024 18:22:16 -0500 Subject: [PATCH 79/82] force name server transport release if channel is not found after max nubmer of attempts --- src/remote/channelSearchManager.cpp | 22 ++++++++++++++++++---- src/remote/pv/channelSearchManager.h | 7 ++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/remote/channelSearchManager.cpp b/src/remote/channelSearchManager.cpp index a87f3aed..eeaeed6d 100644 --- a/src/remote/channelSearchManager.cpp +++ b/src/remote/channelSearchManager.cpp @@ -71,12 +71,14 @@ static const int MAX_FALLBACK_COUNT_VALUE = (1 << 7) + 1; static const int MAX_FRAMES_AT_ONCE = 10; static const int DELAY_BETWEEN_FRAMES_MS = 50; +static const int MAX_NAME_SERVER_SEARCH_COUNT = 3; ChannelSearchManager::ChannelSearchManager(Context::shared_pointer const & context) : m_context(context), m_responseAddress(), // initialized in activate() m_canceled(), m_sequenceNumber(0), + m_nsSearchCounter(0), m_sendBuffer(MAX_UDP_UNFRAGMENTED_SEND), m_channels(), m_lastTimeSent(), @@ -194,10 +196,11 @@ void ChannelSearchManager::searchResponse(const ServerGUID & guid, pvAccessID ci releaseNameServerTransport(); } -void ChannelSearchManager::releaseNameServerTransport() +void ChannelSearchManager::releaseNameServerTransport(bool forceRelease) { - if(m_channels.size() == 0) + if(m_channels.size() == 0 || forceRelease) { + m_nsSearchCounter = 0; m_context.lock()->releaseNameServerSearchTransport(); } } @@ -297,11 +300,22 @@ void ChannelSearchManager::flushSendBuffer() m_sendBuffer.putByte(CAST_POSITION, (int8_t)0x00); // b/m-cast, no reply required ut->send(&m_sendBuffer, inetAddressType_broadcast_multicast); - // Name server search + // Name server search. + // Reset name server transport after max. number of attempts is reached. Transport::shared_pointer nsTransport = m_context.lock()->getNameServerSearchTransport(); if(nsTransport) { - LOG(logLevelDebug, "Initiating name server search for %d channels", int(m_channels.size())); + if (m_nsSearchCounter >= MAX_NAME_SERVER_SEARCH_COUNT) + { + LOG(logLevelDebug, "Resetting name server transport after %d search attempts", m_nsSearchCounter); + releaseNameServerTransport(true); + } + nsTransport = m_context.lock()->getNameServerSearchTransport(); + } + if(nsTransport) + { + m_nsSearchCounter++; + LOG(logLevelDebug, "Initiating name server search for %d channels, search attempt %d", int(m_channels.size()), m_nsSearchCounter); nsTransport->enqueueSendRequest(shared_from_this()); } initializeSendBuffer(); diff --git a/src/remote/pv/channelSearchManager.h b/src/remote/pv/channelSearchManager.h index 0aa7789a..bc57ec93 100644 --- a/src/remote/pv/channelSearchManager.h +++ b/src/remote/pv/channelSearchManager.h @@ -111,7 +111,7 @@ class ChannelSearchManager : void activate(); // Releases name server transport. - void releaseNameServerTransport(); + void releaseNameServerTransport(bool forceRelease=false); private: @@ -147,6 +147,11 @@ class ChannelSearchManager : */ int32_t m_sequenceNumber; + /** + * Name server search attempt counter. + */ + int m_nsSearchCounter; + /** * Send byte buffer (frame) */ From 7a64947bf2facde35d2913ac9d3cfcfab104b814 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 29 May 2024 09:44:02 -0500 Subject: [PATCH 80/82] remove blocking call for getting name server connections, and instead use timers; if multiple name servers are configured, connections to all of them are obtained at the same time --- src/remote/channelSearchManager.cpp | 24 ++-- src/remote/pv/channelSearchManager.h | 5 + src/remote/pv/remote.h | 2 +- src/remoteClient/clientContextImpl.cpp | 173 ++++++++++++++++++++----- 4 files changed, 162 insertions(+), 42 deletions(-) diff --git a/src/remote/channelSearchManager.cpp b/src/remote/channelSearchManager.cpp index eeaeed6d..c08c4506 100644 --- a/src/remote/channelSearchManager.cpp +++ b/src/remote/channelSearchManager.cpp @@ -201,7 +201,8 @@ void ChannelSearchManager::releaseNameServerTransport(bool forceRelease) if(m_channels.size() == 0 || forceRelease) { m_nsSearchCounter = 0; - m_context.lock()->releaseNameServerSearchTransport(); + m_context.lock()->releaseNameServerSearchTransport(m_nsTransport); + m_nsTransport.reset(); } } @@ -291,32 +292,39 @@ void ChannelSearchManager::flushSendBuffer() { Lock guard(m_mutex); + // UDP transport Transport::shared_pointer tt = m_context.lock()->getSearchTransport(); BlockingUDPTransport::shared_pointer ut = std::tr1::static_pointer_cast(tt); + // UDP search m_sendBuffer.putByte(CAST_POSITION, (int8_t)0x80); // unicast, no reply required ut->send(&m_sendBuffer, inetAddressType_unicast); m_sendBuffer.putByte(CAST_POSITION, (int8_t)0x00); // b/m-cast, no reply required ut->send(&m_sendBuffer, inetAddressType_broadcast_multicast); - // Name server search. - // Reset name server transport after max. number of attempts is reached. - Transport::shared_pointer nsTransport = m_context.lock()->getNameServerSearchTransport(); - if(nsTransport) + // Name server transport + if(m_nsTransport) { + // Reset transport after max. number of attempts is reached. if (m_nsSearchCounter >= MAX_NAME_SERVER_SEARCH_COUNT) { LOG(logLevelDebug, "Resetting name server transport after %d search attempts", m_nsSearchCounter); releaseNameServerTransport(true); } - nsTransport = m_context.lock()->getNameServerSearchTransport(); } - if(nsTransport) + + if(!m_nsTransport) + { + m_nsTransport = m_context.lock()->getNameServerSearchTransport(); + } + + // Name server search + if(m_nsTransport) { m_nsSearchCounter++; LOG(logLevelDebug, "Initiating name server search for %d channels, search attempt %d", int(m_channels.size()), m_nsSearchCounter); - nsTransport->enqueueSendRequest(shared_from_this()); + m_nsTransport->enqueueSendRequest(shared_from_this()); } initializeSendBuffer(); } diff --git a/src/remote/pv/channelSearchManager.h b/src/remote/pv/channelSearchManager.h index bc57ec93..e57ba717 100644 --- a/src/remote/pv/channelSearchManager.h +++ b/src/remote/pv/channelSearchManager.h @@ -152,6 +152,11 @@ class ChannelSearchManager : */ int m_nsSearchCounter; + /** + * Name server transport + */ + Transport::shared_pointer m_nsTransport; + /** * Send byte buffer (frame) */ diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index d5d08c43..1729c12f 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -310,7 +310,7 @@ class Context { virtual std::tr1::shared_ptr getChannel(pvAccessID id) = 0; virtual Transport::shared_pointer getSearchTransport() = 0; virtual Transport::shared_pointer getNameServerSearchTransport() {return Transport::shared_pointer();} - virtual void releaseNameServerSearchTransport() {} + virtual void releaseNameServerSearchTransport(const Transport::shared_pointer& nsTransport = Transport::shared_pointer()) {} }; /** diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 6a1ec4a4..495f22b0 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ #include #include +#include #include #include #include @@ -44,6 +46,7 @@ //#include #define PVA_CHANNEL_SEARCH_PRIORITY 98 +#define MAX_NS_TRANSPORT_WAIT_TIME 0.1 using std::tr1::dynamic_pointer_cast; using std::tr1::static_pointer_cast; @@ -4132,61 +4135,78 @@ class InternalClientContextImpl : virtual Transport::shared_pointer getNameServerSearchTransport() { - if (m_nsTransport) - { - return m_nsTransport; - } - if (!m_nsAddresses.size()) { return Transport::shared_pointer(); } createNameServerConnector(); - if (!m_nsConnector.get()) { return Transport::shared_pointer(); } + m_nsTransportEvent.tryWait(); + Transport::shared_pointer nsTransport; for (unsigned int i = 0; i < m_nsAddresses.size(); i++) { - char strBuffer[24]; - osiSockAddr* serverAddress = &m_nsAddresses[m_nsAddressIndex]; - ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "Getting name server transport for address %s", strBuffer); - m_nsAddressIndex = (m_nsAddressIndex+1) % m_nsAddresses.size(); - - try { - m_nsTransport = m_nsConnector->connect(m_nsChannel, m_nsResponseHandler, *serverAddress, EPICS_PVA_MINOR_VERSION, PVA_CHANNEL_SEARCH_PRIORITY); - LOG(logLevelDebug, "Got name server transport for address %s", strBuffer); - return m_nsTransport; + Lock L(m_nsTransportMapMutex); + NsTransportMap::iterator it = m_nsTransportMap.find(m_nsAddressIndex); + if (it != m_nsTransportMap.end()) + { + nsTransport = it->second; + break; + } + else + { + NsTransportConnectCallback::shared_pointer c = m_nsTransportConnectCallbackMap[m_nsAddressIndex]; + Timer::shared_pointer t = m_nsTransportConnectCallbackTimerMap[m_nsAddressIndex]; + if (!c->inProgress()) + { + t->scheduleAfterDelay(c, 0); + } + } + m_nsAddressIndex = (m_nsAddressIndex+1) % m_nsAddresses.size(); } - catch (std::exception& e) + } + + if (!nsTransport) + { + // Wait to get transport if we do not have it + m_nsTransportEvent.wait(MAX_NS_TRANSPORT_WAIT_TIME); + Lock L(m_nsTransportMapMutex); + if (!m_nsTransportMap.empty()) { - LOG(logLevelDebug, "Could not get name server transport for %s: %s", strBuffer, e.what()); + nsTransport = m_nsTransportMap.begin()->second; } } - return Transport::shared_pointer(); + return nsTransport; } - virtual void releaseNameServerSearchTransport() + virtual void releaseNameServerSearchTransport(const Transport::shared_pointer& nsTransport = Transport::shared_pointer()) { - if (!m_nsTransport) - { - return; - } - LOG(logLevelDebug, "Releasing transport used for name server channel %d", m_nsChannel->getID()); - m_nsTransport->release(m_nsChannel->getID()); - if (m_nsTransport->isUsed()) + if (nsTransport) { - LOG(logLevelDebug, "Name server transport is still in use by other clients"); + LOG(logLevelDebug, "Releasing transport used for name server channel %d", m_nsChannel->getID()); + nsTransport->release(m_nsChannel->getID()); } - else { - LOG(logLevelDebug, "Closing name server transport"); - m_nsTransport->close(); - m_nsTransport.reset(); + Lock L(m_nsTransportMapMutex); + for (unsigned int i = 0; i < m_nsAddresses.size(); i++) + { + NsTransportMap::iterator it = m_nsTransportMap.find(i); + if (it != m_nsTransportMap.end()) + { + Transport::shared_pointer nst = it->second; + if (!nst->isUsed()) + { + LOG(logLevelDebug, "Closing name server transport for address %s", m_nsTransportConnectCallbackMap[i]->getNsAddress().c_str()); + nst->close(); + nst.reset(); + m_nsTransportMap.erase(it); + } + } + } } } @@ -4248,6 +4268,7 @@ class InternalClientContextImpl : // // cleanup // + releaseNameServerSearchTransport(); m_timer->close(); @@ -4321,6 +4342,7 @@ class InternalClientContextImpl : { if (!m_nsConnector.get() && m_nsAddresses.size()) { + // Create NS connector LOG(logLevelDebug, "Creating internal name server channel and connector"); InetAddrVector nsAddresses; // avoid direct connection attempts InternalClientContextImpl::shared_pointer thisPointer(internal_from_this()); @@ -4328,6 +4350,15 @@ class InternalClientContextImpl : bool initiateSearch = false; m_nsChannel = createChannelInternal(nsChannelName, DefaultChannelRequester::build(), PVA_CHANNEL_SEARCH_PRIORITY, nsAddresses, initiateSearch); m_nsConnector.reset(new BlockingTCPConnector(thisPointer, m_receiveBufferSize, m_connectionTimeout)); + + // Create callback timers for each address + for (unsigned int i = 0; i < m_nsAddresses.size(); i++) + { + NsTransportConnectCallback::shared_pointer c(new NsTransportConnectCallback(thisPointer, i)); + m_nsTransportConnectCallbackMap[i] = c; + Timer::shared_pointer t(new Timer("NS connection timer", highPriority)); + m_nsTransportConnectCallbackTimerMap[i] = t; + } } } @@ -4678,7 +4709,83 @@ class InternalClientContextImpl : /** * Name server transport */ - Transport::shared_pointer m_nsTransport; + Event m_nsTransportEvent; + typedef std::map NsTransportMap; + NsTransportMap m_nsTransportMap; + Mutex m_nsTransportMapMutex; + class NsTransportConnectCallback : public TimerCallback + { + public: + POINTER_DEFINITIONS(NsTransportConnectCallback); + NsTransportConnectCallback(const InternalClientContextImpl::shared_pointer& iccImpl, int nsAddrIndex) : + TimerCallback(), + m_iccImpl(iccImpl), + m_nsAddrIndex(nsAddrIndex), + m_inProgress(false) + { + char strBuffer[24]; + osiSockAddr* serverAddress = &iccImpl->m_nsAddresses[nsAddrIndex]; + ipAddrToDottedIP(&serverAddress->ia, strBuffer, sizeof(strBuffer)); + LOG(logLevelDebug, "Initializing name server transport callback for address %s", strBuffer); + m_nsAddr = strBuffer; + } + virtual ~NsTransportConnectCallback() {} + virtual void callback() OVERRIDE FINAL + { + { + Lock L(m_iccImpl->m_nsTransportMapMutex); + if (m_iccImpl->m_nsTransportMap.find(m_nsAddrIndex) != m_iccImpl->m_nsTransportMap.end()) + { + LOG(logLevelDebug, "Already have name server transport for address %s", m_nsAddr.c_str()); + return; + } + LOG(logLevelDebug, "No name server transport for address %s", m_nsAddr.c_str()); + } + if (m_inProgress) + { + LOG(logLevelDebug, "Connection in progress to the name server with address %s", m_nsAddr.c_str()); + return; + } + m_inProgress = true; + try + { + osiSockAddr* serverAddress = &m_iccImpl->m_nsAddresses[m_nsAddrIndex]; + LOG(logLevelDebug, "Getting name server transport for address %s", m_nsAddr.c_str()); + Transport::shared_pointer nsTransport = m_iccImpl->m_nsConnector->connect(m_iccImpl->m_nsChannel, m_iccImpl->m_nsResponseHandler, *serverAddress, EPICS_PVA_MINOR_VERSION, PVA_CHANNEL_SEARCH_PRIORITY); + LOG(logLevelDebug, "Got name server transport for address %s", m_nsAddr.c_str()); + { + Lock L(m_iccImpl->m_nsTransportMapMutex); + m_iccImpl->m_nsTransportMap[m_nsAddrIndex] = nsTransport; + m_iccImpl->m_nsTransportEvent.signal(); + } + } + catch (std::exception& e) + { + LOG(logLevelDebug, "Could not get name server transport for %s: %s", m_nsAddr.c_str(), e.what()); + } + m_inProgress = false; + } + virtual void timerStopped() OVERRIDE FINAL + { + } + string getNsAddress() const + { + return m_nsAddr; + } + bool inProgress() const + { + return m_inProgress; + } + private: + InternalClientContextImpl::shared_pointer m_iccImpl; + int m_nsAddrIndex; + string m_nsAddr; + bool m_inProgress; + }; + typedef std::map NsTransportConnectCallbackMap; + NsTransportConnectCallbackMap m_nsTransportConnectCallbackMap; + typedef std::map NsTransportConnectCallbackTimerMap; + NsTransportConnectCallbackTimerMap m_nsTransportConnectCallbackTimerMap; /** * If the context doesn't see a beacon from a server that it is connected to for From bb5fce62d78ccd62cc3b08501b657ab0c0d555f5 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Wed, 29 May 2024 10:59:25 -0500 Subject: [PATCH 81/82] do not release all name server connections if channel search was unsuccessful --- src/remote/channelSearchManager.cpp | 20 +++++++++++++++++--- src/remote/pv/remote.h | 2 +- src/remoteClient/clientContextImpl.cpp | 20 +++++++++++++------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/remote/channelSearchManager.cpp b/src/remote/channelSearchManager.cpp index c08c4506..545288e5 100644 --- a/src/remote/channelSearchManager.cpp +++ b/src/remote/channelSearchManager.cpp @@ -193,15 +193,28 @@ void ChannelSearchManager::searchResponse(const ServerGUID & guid, pvAccessID ci if(si) si->searchResponse(guid, minorRevision, serverAddress); } + // Release all NS connections if there are + // no more channels to search for releaseNameServerTransport(); } void ChannelSearchManager::releaseNameServerTransport(bool forceRelease) { - if(m_channels.size() == 0 || forceRelease) + bool releaseAllConnections = true; + if(m_channels.size() == 0) { + // No more channels to search for, release all connections m_nsSearchCounter = 0; - m_context.lock()->releaseNameServerSearchTransport(m_nsTransport); + m_context.lock()->releaseNameServerSearchTransport(m_nsTransport, releaseAllConnections); + m_nsTransport.reset(); + } + else if(forceRelease) + { + // There are channels to search for, release only connection + // that is currently used + releaseAllConnections = false; + m_nsSearchCounter = 0; + m_context.lock()->releaseNameServerSearchTransport(m_nsTransport, releaseAllConnections); m_nsTransport.reset(); } } @@ -306,7 +319,8 @@ void ChannelSearchManager::flushSendBuffer() // Name server transport if(m_nsTransport) { - // Reset transport after max. number of attempts is reached. + // Reset transport (current connection only) + // after max. number of attempts is reached. if (m_nsSearchCounter >= MAX_NAME_SERVER_SEARCH_COUNT) { LOG(logLevelDebug, "Resetting name server transport after %d search attempts", m_nsSearchCounter); diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 1729c12f..46c6cfe3 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -310,7 +310,7 @@ class Context { virtual std::tr1::shared_ptr getChannel(pvAccessID id) = 0; virtual Transport::shared_pointer getSearchTransport() = 0; virtual Transport::shared_pointer getNameServerSearchTransport() {return Transport::shared_pointer();} - virtual void releaseNameServerSearchTransport(const Transport::shared_pointer& nsTransport = Transport::shared_pointer()) {} + virtual void releaseNameServerSearchTransport(const Transport::shared_pointer& nsTransport=Transport::shared_pointer(), bool releaseAllConnections=true) {} }; /** diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 495f22b0..9d0b4029 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -2610,8 +2610,9 @@ class SearchResponseHandler : public AbstractClientResponseHandler { { if (transport->getType() == "tcp") { - LOG(logLevelDebug, "No channels found, releasing name server transport"); - csm->releaseNameServerTransport(); + // Release only current NS connection + LOG(logLevelDebug, "No channels found, releasing current name server transport"); + csm->releaseNameServerTransport(true); } return; } @@ -4183,7 +4184,7 @@ class InternalClientContextImpl : return nsTransport; } - virtual void releaseNameServerSearchTransport(const Transport::shared_pointer& nsTransport = Transport::shared_pointer()) + virtual void releaseNameServerSearchTransport(const Transport::shared_pointer& nsTransport=Transport::shared_pointer(), bool releaseAllConnections=true) { if (nsTransport) { @@ -4200,10 +4201,15 @@ class InternalClientContextImpl : Transport::shared_pointer nst = it->second; if (!nst->isUsed()) { - LOG(logLevelDebug, "Closing name server transport for address %s", m_nsTransportConnectCallbackMap[i]->getNsAddress().c_str()); - nst->close(); - nst.reset(); - m_nsTransportMap.erase(it); + // Release unused given connection only, unless + // other connections are no longer needed + if (nst == nsTransport || releaseAllConnections) + { + LOG(logLevelDebug, "Closing name server transport for address %s", m_nsTransportConnectCallbackMap[i]->getNsAddress().c_str()); + nst->close(); + nst.reset(); + m_nsTransportMap.erase(it); + } } } } From 0a1f8f642cd2582ed6546d72f83a6df2660664d8 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Thu, 25 Jul 2024 08:53:04 -0500 Subject: [PATCH 82/82] wait for name server transport only if the search has been just scheduled --- src/remoteClient/clientContextImpl.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 9d0b4029..0ff0330b 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -4148,6 +4148,7 @@ class InternalClientContextImpl : m_nsTransportEvent.tryWait(); Transport::shared_pointer nsTransport; + bool nsSearchScheduled = false; for (unsigned int i = 0; i < m_nsAddresses.size(); i++) { { @@ -4165,15 +4166,17 @@ class InternalClientContextImpl : if (!c->inProgress()) { t->scheduleAfterDelay(c, 0); + nsSearchScheduled = true; } } m_nsAddressIndex = (m_nsAddressIndex+1) % m_nsAddresses.size(); } } - if (!nsTransport) + if (!nsTransport && nsSearchScheduled) { - // Wait to get transport if we do not have it + // Wait to get transport if we do not have it and if + // we just scheduled name server search m_nsTransportEvent.wait(MAX_NS_TRANSPORT_WAIT_TIME); Lock L(m_nsTransportMapMutex); if (!m_nsTransportMap.empty())