From 932406e84754a3bc0049901d1c61300c504bbde6 Mon Sep 17 00:00:00 2001 From: Gasper Jansa Date: Fri, 7 Jan 2011 18:46:25 +0100 Subject: [PATCH 1/2] configuration implementation and test --- pvAccessApp/Makefile | 2 + pvAccessApp/remote/channelSearchManager.cpp | 4 +- pvAccessApp/utils/configuration.cpp | 348 ++++++++++++++++++++ pvAccessApp/utils/configuration.h | 216 ++++++++++++ testApp/utils/Makefile | 4 + testApp/utils/configurationTest.cpp | 75 +++++ 6 files changed, 647 insertions(+), 2 deletions(-) create mode 100644 pvAccessApp/utils/configuration.cpp create mode 100644 pvAccessApp/utils/configuration.h create mode 100644 testApp/utils/configurationTest.cpp diff --git a/pvAccessApp/Makefile b/pvAccessApp/Makefile index fb1b425..bd26f53 100644 --- a/pvAccessApp/Makefile +++ b/pvAccessApp/Makefile @@ -21,6 +21,7 @@ INC += introspectionRegistry.h INC += transportRegistry.h INC += namedLockPattern.h INC += referenceCountingLock.h +INC += configuration.h LIBSRCS += hexDump.cpp LIBSRCS += wildcharMatcher.cpp LIBSRCS += inetAddressUtil.cpp @@ -29,6 +30,7 @@ LIBSRCS += introspectionRegistry.cpp LIBSRCS += transportRegistry.cpp LIBSRCS += namedLockPattern.cpp LIBSRCS += referenceCountingLock.cpp +LIBSRCS += configuration.cpp SRC_DIRS += $(PVACCESS)/client diff --git a/pvAccessApp/remote/channelSearchManager.cpp b/pvAccessApp/remote/channelSearchManager.cpp index 1c6110c..e879dcc 100644 --- a/pvAccessApp/remote/channelSearchManager.cpp +++ b/pvAccessApp/remote/channelSearchManager.cpp @@ -435,7 +435,7 @@ ChannelSearchManager::ChannelSearchManager(ClientContextImpl* context): // create timers _timers = new SearchTimer*[numberOfTimers]; - for(int i = 0; i < numberOfTimers; i++) + for(int32 i = 0; i < numberOfTimers; i++) { _timers[i] = new SearchTimer(this, i, i > _beaconAnomalyTimerIndex, i != (numberOfTimers-1)); } @@ -446,7 +446,7 @@ ChannelSearchManager::ChannelSearchManager(ClientContextImpl* context): ChannelSearchManager::~ChannelSearchManager() { - for(int i = 0; i < _numberOfTimers; i++) + for(int32 i = 0; i < _numberOfTimers; i++) { if(_timers[i]) delete _timers[i]; } diff --git a/pvAccessApp/utils/configuration.cpp b/pvAccessApp/utils/configuration.cpp new file mode 100644 index 0000000..b017329 --- /dev/null +++ b/pvAccessApp/utils/configuration.cpp @@ -0,0 +1,348 @@ +/* + * configuration.cpp + */ + +#include "configuration.h" + +namespace epics { namespace pvAccess { + +Properties::Properties() +{ + _fileName = ""; + _infile = new ifstream(); + _infile->exceptions (ifstream::failbit | ifstream::badbit ); + _outfile = new ofstream(); + _outfile->exceptions (ofstream::failbit | ofstream::badbit ); +} + +Properties::Properties(const string fileName) +{ + _fileName = fileName; + _infile = new ifstream(); + _infile->exceptions (ifstream::failbit | ifstream::badbit ); + _outfile = new ofstream(); + _outfile->exceptions (ofstream::failbit | ofstream::badbit ); +} + +Properties::~Properties() +{ + delete _infile; + delete _outfile; + //clear map + for(_propertiesIterator = _properties.begin() ; + _propertiesIterator != _properties.end(); + _propertiesIterator++ ) + { + delete [] _propertiesIterator->first; + delete [] _propertiesIterator->second; + } + _properties.clear(); +} + +void Properties::setProperty(const string key,const string value) +{ + string oldValue; + _propertiesIterator = _properties.find(key.c_str()); + + if(_propertiesIterator != _properties.end()) //found in map + { + delete[] _propertiesIterator->first; + delete[] _propertiesIterator->second; + _properties.erase(_propertiesIterator); + } + + char* chKey = new char[key.length() + 1]; + strncpy(chKey,key.c_str(),key.length()+ 1); + char* chValue = new char[value.length() + 1]; + strncpy(chValue,value.c_str(),value.length() + 1); + _properties[chKey] = chValue; +} + +string Properties::getProperty(const string key) +{ + _propertiesIterator = _properties.find(key.c_str()); + if(_propertiesIterator != _properties.end()) //found in map + { + return string(_propertiesIterator->second); + } + else + { + string errMsg = "Property not found in the map: " + key; + throw BaseException(errMsg.c_str(), __FILE__, __LINE__); + } +} + +string Properties::getProperty(const string key, const string defaultValue) +{ + _propertiesIterator = _properties.find(key.c_str()); + if(_propertiesIterator != _properties.end()) //found in map + { + return string(_propertiesIterator->second); + } + + char* chKey = new char[key.length() + 1]; + strncpy(chKey,key.c_str(),key.length()+ 1); + char* chValue = new char[defaultValue.length() + 1]; + strncpy(chValue,defaultValue.c_str(),defaultValue.length() + 1); + _properties[chKey] = chValue; + return defaultValue; +} + +void Properties::load() +{ + for (_propertiesIterator = _properties.begin() ; + _propertiesIterator != _properties.end(); + _propertiesIterator++ ) + { + delete [] _propertiesIterator->first; + delete [] _propertiesIterator->second; + } + _properties.clear(); + + try + { + _infile->open(_fileName.c_str(),ifstream::in); + } + catch (ifstream::failure& e) { + string errMsg = "Error opening file: " + string(_fileName.c_str()); + throw BaseException(errMsg.c_str(), __FILE__, __LINE__); + } + + string line; + string property; + string key; + try + { + while(!_infile->eof()) + { + line.clear(); + std::getline(*_infile,line); + + //remove trailing spaces + truncate(line); + + //empty line + if(line.length() == 0) + { + continue; + } + // comment + if(line.at(0) == '#') + { + continue; + } + + //line is in format: propertyName=propertyValue + size_t pos = line.find_first_of('=',0); + if(pos == string::npos) //bad value (= not found) + { + string errMsg = "Bad property line found: " + line; + throw BaseException(errMsg.c_str(), __FILE__, __LINE__); + } + + key = line.substr(0,pos); + truncate(key); + property = line.substr(pos + 1,line.length()); + truncate(property); + + char* chKey = new char[key.length() + 1]; + strncpy(chKey,key.c_str(),key.length()+ 1); + char* chProperty = new char[property.length() +1]; + strncpy(chProperty,property.c_str(),property.length() + 1); + _properties[chKey] = chProperty; + } + } + catch (ifstream::failure& e) + { + _infile->close(); + if(_infile->eof()) + { + return; //end of file + } + string errMsg = "Error reading file: " + _fileName; + throw BaseException(errMsg.c_str(), __FILE__, __LINE__); + } + _infile->close(); +} + +void Properties::load(const string fileName) +{ + _fileName = fileName; + load(); +} + +void Properties::store() +{ + try + { + _outfile->open(_fileName.c_str(),ifstream::trunc); + } + catch (ofstream::failure& e) { + string errMsg = "Error opening file: " + string(_fileName.c_str()); + throw BaseException(errMsg.c_str(), __FILE__, __LINE__); + } + + + for (_propertiesIterator = _properties.begin() ; + _propertiesIterator != _properties.end(); + _propertiesIterator++ ) + { + try + { + string line = string(_propertiesIterator->first) + string("=") + string(_propertiesIterator->second) + string("\n"); + _outfile->write(line.c_str(),line.length()); + } + catch (ofstream::failure& e) { + _outfile->close(); + string errMsg = "Error writing to file: " + string(_fileName.c_str()); + throw BaseException(errMsg.c_str(), __FILE__, __LINE__); + } + } + _outfile->close(); +} + +void Properties::store(const string fileName) +{ + _fileName = fileName; + store(); +} + +void Properties::list() +{ + for (_propertiesIterator = _properties.begin() ; + _propertiesIterator != _properties.end(); + _propertiesIterator++ ) + { + cout << "Key:" << _propertiesIterator->first << ",Value: " << _propertiesIterator->second << endl; + } +} + +SystemConfigurationImpl::SystemConfigurationImpl() +{ + _envParam.name = new char[MAX_NAME_LENGHT]; + _envParam.pdflt = NULL; + _ibuffer.exceptions ( ifstream::failbit | ifstream::badbit ); + _obuffer.exceptions ( ifstream::failbit | ifstream::badbit ); + _properties = new Properties(); +} + +SystemConfigurationImpl::~SystemConfigurationImpl() +{ + if(_envParam.name) delete[] _envParam.name; + if(_properties) delete _properties; +} + +bool SystemConfigurationImpl::getPropertyAsBoolean(const string name, const bool defaultValue) +{ + bool retval; + _ibuffer.clear(); + _obuffer.clear(); + _obuffer.str(""); + _obuffer << defaultValue; + _ibuffer.str(getPropertyAsString(name,_obuffer.str())); + _ibuffer >> retval; + return retval; +} + +int32 SystemConfigurationImpl::getPropertyAsInteger(const string name, const int32 defaultValue) +{ + int32 retval; + _ibuffer.clear(); + _obuffer.clear(); + _obuffer.str(""); + _obuffer << defaultValue; + _ibuffer.str(getPropertyAsString(name, _obuffer.str())); + _ibuffer >> retval; + return retval; +} + +float SystemConfigurationImpl::getPropertyAsFloat(const string name, const float defaultValue) +{ + float retval; + _ibuffer.clear(); + _obuffer.clear(); + _obuffer.str(""); + _obuffer << defaultValue; + _ibuffer.str(getPropertyAsString(name, _obuffer.str())); + _ibuffer >> retval; + return retval; +} + +float SystemConfigurationImpl::getPropertyAsDouble(const string name, const double defaultValue) +{ + float retval; + _ibuffer.clear(); + _obuffer.clear(); + _obuffer.str(""); + _obuffer << defaultValue; + _ibuffer.str(getPropertyAsString(name, _obuffer.str())); + _ibuffer >> retval; + return retval; +} + +string SystemConfigurationImpl::getPropertyAsString(const string name, const string defaultValue) +{ + strncpy(_envParam.name,name.c_str(),name.length() + 1); + const char* val = envGetConfigParamPtr(&_envParam); + if(val != NULL) + { + return _properties->getProperty(name, string(val)); + } + return _properties->getProperty(name,defaultValue); +} + +ConfigurationProviderImpl::ConfigurationProviderImpl() +{ + +} + +ConfigurationProviderImpl::~ConfigurationProviderImpl() +{ + for(_configsIter = _configs.begin() ; + _configsIter != _configs.end(); + _configsIter++ ) + { + delete [] _configsIter->first; + } + _configs.clear(); +} + +void ConfigurationProviderImpl::registerConfiguration(const string name, const Configuration* configuration) +{ + Lock guard(&_mutex); + _configsIter = _configs.find(name.c_str()); + if(_configsIter != _configs.end()) + { + string msg = "configuration with name " + name + " already registered"; + throw BaseException(msg.c_str(), __FILE__, __LINE__); + } + char* chKey = new char[name.length() + 1]; + strncpy(chKey,name.c_str(),name.length()+ 1); + _configs[chKey] = configuration; +} + +Configuration* ConfigurationProviderImpl::getConfiguration(const string name) +{ + _configsIter = _configs.find(name.c_str()); + if(_configsIter != _configs.end()) + { + return const_cast(_configsIter->second); + } + return NULL; +} + +ConfigurationProviderImpl* ConfigurationFactory::_configurationProvider = NULL; +Mutex ConfigurationFactory::_conf_factory_mutex = Mutex(); + +ConfigurationProviderImpl* ConfigurationFactory::getProvider() +{ + Lock guard(&_conf_factory_mutex); + if(_configurationProvider == NULL) + { + _configurationProvider = new ConfigurationProviderImpl(); + } + return _configurationProvider; +} + +}} + diff --git a/pvAccessApp/utils/configuration.h b/pvAccessApp/utils/configuration.h new file mode 100644 index 0000000..75e5bf0 --- /dev/null +++ b/pvAccessApp/utils/configuration.h @@ -0,0 +1,216 @@ +/* + * configuration.h + */ + +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +#include "pvType.h" +#include "noDefaultMethods.h" +#include "lock.h" +#include "epicsException.h" + +#include "envDefs.h" + + +#include +#include +#include +#include +#include + + +using namespace epics::pvData; +using namespace std; + +namespace epics { namespace pvAccess { + +#define MAX_NAME_LENGHT 300 + +struct conf_cmp_str +{ + bool operator()(char const *a, char const *b) + { + return strcmp(a, b) < 0; + } +}; + +/** + * Properties + */ +class Properties +{ +public: + Properties(); + Properties(const string fileName); + virtual ~Properties(); + + void setProperty(const string key,const string value); + string getProperty(const string key); + string getProperty(const string key, const string defaultValue); + + void store(); + void store(const string fileName); + void load(); + void load(const string fileName); + void list(); + +private: + map _properties; + map::iterator _propertiesIterator; + ifstream* _infile; + ofstream* _outfile; + string _fileName; + + inline void truncate(string& str) + { + while(str.length() != 0 && (str.at(0) == ' ' || str.at(0) == '\t')) + { + str.erase(0,1); + } + while(str.length() != 0 && (str.at(str.length()-1) == ' ' || str.at(str.length()-1) == '\t')) + { + str.erase(str.length()-1,1); + } + } +}; + + + +/** + * Configuration + */ +class Configuration : private NoDefaultMethods +{ +public: + /* + * Get the environment variable specified by name or return default value + * if it does not exist. + * + * @param name name of the environment variable to return. + * @param defualtValue default value to return if environment variable does not exists. + * + * @return environment variable value as bool or default value if it does not exist. + */ + virtual bool getPropertyAsBoolean(const string name, const bool defaultValue) = 0; + /* + * Get the environment variable specified by name or return default value + * if it does not exist. + * + * @param name name of the environment variable to return. + * @param defualtValue default value to return if environment variable does not exists. + * + * @return environment variable value as int32 or default value if it does not exist. + */ + virtual int32 getPropertyAsInteger(const string name, const int32 defaultValue) = 0; + /* + * Get the environment variable specified by name or return default value + * if it does not exist. + * + * @param name name of the environment variable to return. + * @param defualtValue default value to return if environment variable does not exists. + * + * @return environment variable value as float or default value if it does not exist. + */ + virtual float getPropertyAsFloat(const string name, const float defaultValue) = 0; + /* + * Get the environment variable specified by name or return default value + * if it does not exist. + * + * @param name name of the environment variable to return. + * @param defualtValue default value to return if environment variable does not exists. + * + * @return environment variable value as double or default value if it does not exist. + */ + virtual float getPropertyAsDouble(const string name, const double defaultValue) = 0; + /* + * Get the environment variable specified by name or return default value + * if it does not exist. + * + * @param name name of the environment variable to return. + * @param defualtValue default value to return if environment variable does not exists. + * + * @return environment variable value as string or default value if it does not exist. + */ + virtual string getPropertyAsString(const string name, const string defaultValue) = 0; +}; + +class SystemConfigurationImpl: public Configuration +{ +public: + SystemConfigurationImpl(); + virtual ~SystemConfigurationImpl(); + bool getPropertyAsBoolean(const string name, const bool defaultValue); + int32 getPropertyAsInteger(const string name, const int32 defaultValue); + float getPropertyAsFloat(const string name, const float defaultValue); + float getPropertyAsDouble(const string name, const double defaultValue); + string getPropertyAsString(const string name, string defaultValue); + Properties* _properties; +private: + ENV_PARAM _envParam; + istringstream _ibuffer; + ostringstream _obuffer; + +}; + +/** + * Configuration provider. + */ +class ConfigurationProvider : private NoDefaultMethods +{ +public: + /* + * Return configuration specified by name. + * + * @param name name of the configuration to return. + * + * @return configuration specified by name or NULL if it does not exists. + */ + virtual Configuration* getConfiguration(const string name) = 0; + /* + * Register configuration. + * + * @param name name of the configuration to register. + * @param configuration configuration to register. + */ + virtual void registerConfiguration(const string name, const Configuration* configuration) = 0; +}; + +class ConfigurationProviderImpl: public ConfigurationProvider +{ +public: + ConfigurationProviderImpl(); + virtual ~ConfigurationProviderImpl(); + Configuration* getConfiguration(const string name); + void registerConfiguration(const string name, const Configuration* configuration); +private: + Mutex _mutex; + map _configs; + map::iterator _configsIter; +}; + +/** + * Configuration factory. + */ +class ConfigurationFactory : private NoDefaultMethods +{ +public: + /* + * Lazily creates configuration provider. + * + * @param name name of the configuration to register. + * @param configuration configuration to register. + * + * @return configuration provider + */ + static ConfigurationProviderImpl* getProvider(); + +private: + ConfigurationFactory() {}; + static ConfigurationProviderImpl* _configurationProvider; + static Mutex _conf_factory_mutex; +}; + +}} + +#endif /* CONFIGURATION_H */ diff --git a/testApp/utils/Makefile b/testApp/utils/Makefile index ba2628e..e3ecbf7 100644 --- a/testApp/utils/Makefile +++ b/testApp/utils/Makefile @@ -38,6 +38,10 @@ PROD_HOST += namedLockPatternTest namedLockPatternTest_SRCS += namedLockPatternTest.cpp namedLockPatternTest_LIBS += pvAccess Com pvData +PROD_HOST += configurationTest +configurationTest_SRCS += configurationTest.cpp +configurationTest_LIBS += pvAccess Com pvData + include $(TOP)/configure/RULES #---------------------------------------- # ADD RULES AFTER THIS LINE diff --git a/testApp/utils/configurationTest.cpp b/testApp/utils/configurationTest.cpp new file mode 100644 index 0000000..78c4226 --- /dev/null +++ b/testApp/utils/configurationTest.cpp @@ -0,0 +1,75 @@ +/* + * configurationTest.cpp + * + */ + +#include "configuration.h" +#include "showConstructDestruct.h" + +#include +#include +#include +#include + +using namespace epics::pvAccess; +using namespace std; + +int main(int argc, char *argv[]) +{ + SystemConfigurationImpl* configuration = new SystemConfigurationImpl(); + bool boolProperty = configuration->getPropertyAsBoolean("boolProperty", true); + assert(boolProperty == true); + + int32 intProperty = configuration->getPropertyAsInteger("intProperty", 1); + assert(intProperty == 1); + + float floatProperty = configuration->getPropertyAsFloat("floatProperty", 3); + assert(floatProperty == 3); + + double doubleProperty = configuration->getPropertyAsDouble("doubleProperty", -3); + assert(doubleProperty == -3); + + string stringProperty = configuration->getPropertyAsString("stringProperty", "string"); + assert(stringProperty == string("string")); + + ConfigurationProviderImpl* configProvider = ConfigurationFactory::getProvider(); + configProvider->registerConfiguration("conf1",static_cast(configuration)); + + SystemConfigurationImpl* configurationOut = static_cast(configProvider->getConfiguration("conf1")); + assert(configurationOut == configuration); + + intProperty = configuration->getPropertyAsInteger("intProperty", 2); + assert(intProperty == 1); + + floatProperty = configuration->getPropertyAsFloat("floatProperty", 4); + assert(floatProperty == 3); + + doubleProperty = configuration->getPropertyAsDouble("doubleProperty", -4); + assert(doubleProperty == -3); + + stringProperty = configuration->getPropertyAsString("stringProperty", "string1"); + assert(stringProperty == string("string")); + + setenv("boolProperty1", "1", 1); + boolProperty = configuration->getPropertyAsInteger("boolProperty1", 0); + assert(boolProperty == true); + + setenv("intProperty1", "45", 1); + intProperty = configuration->getPropertyAsInteger("intProperty1", 2); + assert(intProperty == 45); + + setenv("floatProperty1", "22", 1); + floatProperty = configuration->getPropertyAsFloat("floatProperty1", 3); + assert(floatProperty == 22); + + setenv("dobuleProperty1", "42", 1); + doubleProperty = configuration->getPropertyAsDouble("dobuleProperty1", -3); + assert(doubleProperty == 42); + + if(configuration) delete configuration; + getShowConstructDestruct()->constuctDestructTotals(stdout); + return 0; +} + + + From 5c5305635b88530754ad4f282f6e4d0864f98a83 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Sun, 9 Jan 2011 20:07:03 +0100 Subject: [PATCH 2/2] first successful message test --- pvAccessApp/remote/blockingTCPTransport.cpp | 4 +- pvAccessApp/remote/blockingUDPTransport.cpp | 4 +- pvAccessApp/remote/channelSearchManager.cpp | 4 +- testApp/remote/testRemoteClientImpl.cpp | 273 +++++++++++++++++--- 4 files changed, 239 insertions(+), 46 deletions(-) diff --git a/pvAccessApp/remote/blockingTCPTransport.cpp b/pvAccessApp/remote/blockingTCPTransport.cpp index 113cd48..a4778ec 100644 --- a/pvAccessApp/remote/blockingTCPTransport.cpp +++ b/pvAccessApp/remote/blockingTCPTransport.cpp @@ -92,12 +92,12 @@ namespace epics { _sendThreadRunning(false) { _socketBuffer = new ByteBuffer(max(MAX_TCP_RECV - +MAX_ENSURE_DATA_BUFFER_SIZE, receiveBufferSize)); + +MAX_ENSURE_DATA_BUFFER_SIZE, receiveBufferSize), EPICS_ENDIAN_BIG); _socketBuffer->setPosition(_socketBuffer->getLimit()); _startPosition = _socketBuffer->getPosition(); // allocate buffer - _sendBuffer = new ByteBuffer(_socketBuffer->getSize()); + _sendBuffer = new ByteBuffer(_socketBuffer->getSize(), EPICS_ENDIAN_BIG); _maxPayloadSize = _sendBuffer->getSize()-2*CA_MESSAGE_HEADER_SIZE; // one for header, one for flow control // get send buffer size diff --git a/pvAccessApp/remote/blockingUDPTransport.cpp b/pvAccessApp/remote/blockingUDPTransport.cpp index 3f53a8a..bb61ea9 100644 --- a/pvAccessApp/remote/blockingUDPTransport.cpp +++ b/pvAccessApp/remote/blockingUDPTransport.cpp @@ -39,8 +39,8 @@ namespace epics { _closed(false), _responseHandler(responseHandler), _channel(channel), _sendAddresses(sendAddresses), _ignoredAddresses(NULL), _sendTo(NULL), _receiveBuffer( - new ByteBuffer(MAX_UDP_RECV)), _sendBuffer( - new ByteBuffer(MAX_UDP_RECV)), + new ByteBuffer(MAX_UDP_RECV, EPICS_ENDIAN_BIG)), _sendBuffer( + new ByteBuffer(MAX_UDP_RECV, EPICS_ENDIAN_BIG)), _lastMessageStartPosition(0), _readBuffer( new char[MAX_UDP_RECV]), _mutex(new Mutex()), _threadId(NULL) { diff --git a/pvAccessApp/remote/channelSearchManager.cpp b/pvAccessApp/remote/channelSearchManager.cpp index 1c6110c..7d00dd5 100644 --- a/pvAccessApp/remote/channelSearchManager.cpp +++ b/pvAccessApp/remote/channelSearchManager.cpp @@ -415,7 +415,7 @@ ChannelSearchManager::ChannelSearchManager(ClientContextImpl* context): _sequenceNumber(0) { // create and initialize send buffer - _sendBuffer = new ByteBuffer(MAX_UDP_SEND); + _sendBuffer = new ByteBuffer(MAX_UDP_SEND, EPICS_ENDIAN_BIG); initializeSendBuffer(); // TODO should be configurable @@ -550,7 +550,7 @@ void ChannelSearchManager::initializeSendBuffer() _sendBuffer->clear(); _sendBuffer->putShort(CA_MAGIC_AND_VERSION); _sendBuffer->putByte((int8)0); // data - _sendBuffer->putByte((int8)3); // beacon + _sendBuffer->putByte((int8)3); // search _sendBuffer->putInt(sizeof(int32)/sizeof(int8) + 1); // "zero" payload _sendBuffer->putInt(_sequenceNumber); diff --git a/testApp/remote/testRemoteClientImpl.cpp b/testApp/remote/testRemoteClientImpl.cpp index 846d7c7..f917251 100644 --- a/testApp/remote/testRemoteClientImpl.cpp +++ b/testApp/remote/testRemoteClientImpl.cpp @@ -1,3 +1,4 @@ + /* testRemoteClientImpl.cpp */ /* Author: Matej Sekoranja Date: 2011.1.1 */ @@ -13,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -428,7 +431,38 @@ typedef std::map IOIDResponseRequestMap; class ClientContextImpl; + class DebugResponse : public ResponseHandler, private epics::pvData::NoDefaultMethods { + public: + /** + * @param context + */ + DebugResponse() + { + } + virtual ~DebugResponse() { + } + + virtual void handleResponse(osiSockAddr* responseFrom, + Transport* transport, int8 version, int8 command, + int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) + { + char ipAddrStr[48]; + std::cout << "ole" << std::endl; + ipAddrToA(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr)); + std::cout << "ole2" << std::endl; + + ostringstream prologue; + prologue<<"Message [0x"<getArray(), + payloadBuffer->getPosition(), payloadSize); + + } + }; /** * CA response handler - main handler which dispatches responses to appripriate handlers. @@ -458,7 +492,7 @@ class ClientResponseHandler : public ResponseHandler, private epics::pvData::NoD * @param context */ ClientResponseHandler(ClientContextImpl* context) : m_context(context) { - static ResponseHandler* badResponse = 0; //new BadResponse(context); + static ResponseHandler* badResponse = new DebugResponse(); static ResponseHandler* dataResponse = 0; //new DataResponseHandler(context); #define HANDLER_COUNT 28 @@ -497,6 +531,8 @@ class ClientResponseHandler : public ResponseHandler, private epics::pvData::NoD Transport* transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { + int c = command+0; + std::cout << "received " << c << std::endl; if (command < 0 || command >= HANDLER_COUNT) { // TODO context.getLogger().fine("Invalid (or unsupported) command: " + command + "."); @@ -509,12 +545,28 @@ class ClientResponseHandler : public ResponseHandler, private epics::pvData::NoD } // delegate - m_handlerTable[command]->handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); + m_handlerTable[c]->handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); } }; + class TCI : public TransportSendControl { + public: + virtual void flushSerializeBuffer() { + } + + virtual void ensureBuffer(int size) { + } + + virtual void startMessage(int8 command, int ensureCapacity){} + virtual void endMessage() {} + + virtual void flush(bool lastMessageCompleted) {} + + virtual void setRecipient(const osiSockAddr& sendTo) {} + }; + #include @@ -548,19 +600,37 @@ class BaseSearchInstance : public SearchInstance virtual void removeAndUnsetListOwnership() {} virtual int getOwnerIndex() { return 0; } - virtual bool generateSearchRequestMessage(ByteBuffer* buffer, TransportSendControl* control) { return false; }; + virtual bool generateSearchRequestMessage(ByteBuffer* requestMessage, TransportSendControl* control) + { +const int DATA_COUNT_POSITION = CA_MESSAGE_HEADER_SIZE + sizeof(int32)/sizeof(int8) + 1; +const int PAYLOAD_POSITION = sizeof(int16)/sizeof(int8) + 2; + + int16 dataCount = requestMessage->getShort(DATA_COUNT_POSITION); + + dataCount++; + if(dataCount >= MAX_SEARCH_BATCH_COUNT) + { + return false; + } + + const string name = getChannelName(); + // not nice... + const int addedPayloadSize = sizeof(int32)/sizeof(int8) + (1 + sizeof(int32)/sizeof(int8) + name.length()); + + if(requestMessage->getRemaining() < addedPayloadSize) + { + return false; + } + + requestMessage->putInt(getChannelID()); + SerializeHelper::serializeString(name, requestMessage, control); + + requestMessage->putInt(PAYLOAD_POSITION, requestMessage->getPosition() - CA_MESSAGE_HEADER_SIZE); + requestMessage->putShort(DATA_COUNT_POSITION, dataCount); + return true; + }; }; -class ChannelSearchManager { // tODO no default, etc. - public: - virtual void registerChannel(SearchInstance* channel) = 0; - virtual void unregisterChannel(SearchInstance* channel) = 0; -}; - - - -class BlockingTCPConnector; -class NamedLockPattern; class BeaconHandlerImpl; @@ -591,9 +661,52 @@ enum ContextState { }; -class ClientContextImpl : public ClientContext +class ClientContextImpl : public ClientContext, +public Context /* TODO */ { + + + + + + +class ChannelSearchManager { // tODO no default, etc. +ClientContextImpl* _context; + public: +ChannelSearchManager(ClientContextImpl* context): + _context(context) { +} + + + virtual void registerChannel(SearchInstance* channel) { + + ByteBuffer sendBuffer(100, EPICS_ENDIAN_BIG); + // new buffer + sendBuffer.clear(); + sendBuffer.putShort(CA_MAGIC_AND_VERSION); + sendBuffer.putByte((int8)0); // data + sendBuffer.putByte((int8)3); // search + sendBuffer.putInt(5); // "zero" payload + + sendBuffer.putInt(0); + + + sendBuffer.putByte((int8)0); + sendBuffer.putShort((int16)0); // count + + TCI tci; + + channel->generateSearchRequestMessage(&sendBuffer, &tci); + std::cout << "sending..." << sendBuffer.getPosition() << " bytes." << std::endl; + _context->getSearchTransport()->send(&sendBuffer); + + }; + virtual void unregisterChannel(SearchInstance* channel) {}; +}; + + + /** * Implementation of CAJ JCA Channel. * @author Matej Sekoranja @@ -1196,7 +1309,6 @@ class ChannelImpl : // TODO } - virtual void getField(GetFieldRequester *requester,epics::pvData::String subField) { requester->getDone(getStatusCreate()->getStatusOK(),m_pvStructure->getSubField(subField)->getField()); @@ -1394,7 +1506,25 @@ class ChannelImpl : Lock lock(&m_contextMutex); return m_provider; } - + + virtual Timer* getTimer() + { + Lock lock(&m_contextMutex); + return m_timer; + } + + virtual TransportRegistry* getTransportRegistry() + { + Lock lock(&m_contextMutex); + return m_transportRegistry; + } + + virtual BlockingUDPTransport* getSearchTransport() + { + Lock lock(&m_contextMutex); + return m_searchTransport; + } + virtual void initialize() { Lock lock(&m_contextMutex); @@ -1484,36 +1614,92 @@ class ChannelImpl : void internalInitialize() { m_timer = new Timer("pvAccess-client timer", lowPriority); - /* TODO - connector = new BlockingTCPConnector(this, receiveBufferSize, beaconPeriod); - transportRegistry = new TransportRegistry(); - namedLocker = new NamedLockPattern(); - */ + m_connector = new BlockingTCPConnector(this, m_receiveBufferSize, m_beaconPeriod); + m_transportRegistry = new TransportRegistry(); + m_namedLocker = new NamedLockPattern(); // setup UDP transport initializeUDPTransport(); - // TODO // setup search manager - //channelSearchManager = new ChannelSearchManager(this); + m_channelSearchManager = new ChannelSearchManager(this); } - void initializeUDPTransport() { - // TODO - } + /** + * Initialized UDP transport (broadcast socket and repeater connection). + */ + void initializeUDPTransport() { + // setup UDP transport + try + { + // where to bind (listen) address + osiSockAddr listenLocalAddress; + listenLocalAddress.ia.sin_family = AF_INET; + listenLocalAddress.ia.sin_port = htons(m_broadcastPort); + listenLocalAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY); + + // where to send address + InetAddrVector* broadcastAddresses = getSocketAddressList("192.168.1.255", m_broadcastPort); + // TODO getBroadcastAddresses(broadcastPort) + +/// TOD !!!! addresses !!!!! by pointer and not copied + + BlockingUDPConnector* broadcastConnector = new BlockingUDPConnector(true, broadcastAddresses, true); + + m_broadcastTransport = (BlockingUDPTransport*)broadcastConnector->connect( + 0, new ClientResponseHandler(this), + listenLocalAddress, CA_MINOR_PROTOCOL_REVISION, + CA_DEFAULT_PRIORITY); + + BlockingUDPConnector* searchConnector = new BlockingUDPConnector(false, broadcastAddresses, true); + + // undefined address + osiSockAddr undefinedAddress; + undefinedAddress.ia.sin_family = AF_INET; + undefinedAddress.ia.sin_port = htons(0); + undefinedAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY); + + m_searchTransport = (BlockingUDPTransport*)searchConnector->connect( + 0, new ClientResponseHandler(this), + undefinedAddress, CA_MINOR_PROTOCOL_REVISION, + CA_DEFAULT_PRIORITY); + + // set broadcast address list + if (!m_addressList.empty()) + { + // if auto is true, add it to specified list + InetAddrVector* appendList = 0; + if (m_autoAddressList) + appendList = m_broadcastTransport->getSendAddresses(); + + InetAddrVector* list = getSocketAddressList(m_addressList, m_broadcastPort, appendList); + // TODO delete !!!! + if (list && list->size()) { + m_broadcastTransport->setBroadcastAddresses(list); + m_searchTransport->setBroadcastAddresses(list); + } + } + + m_broadcastTransport->start(); + m_searchTransport->start(); + + } + catch (...) + { + // TODO + } + } void internalDestroy() { // stop searching - /* TODO if (m_channelSearchManager) - channelSearchManager->destroy(); - */ + delete m_channelSearchManager; //->destroy(); // stop timer if (m_timer) delete m_timer; - + // // cleanup // @@ -1521,13 +1707,15 @@ class ChannelImpl : // this will also close all CA transports destroyAllChannels(); - // close broadcast transport - /* TODO + // TODO destroy !!! if (m_broadcastTransport) - m_broadcastTransport->destroy(true); - if (m_searchTransport != null) - m_searchTransport->destroy(true); - */ + delete m_broadcastTransport; //->destroy(true); + if (m_searchTransport) + delete m_searchTransport; //->destroy(true); + + if (m_namedLocker) delete m_namedLocker; + if (m_transportRegistry) delete m_transportRegistry; + if (m_connector) delete m_connector; m_provider->destroy(); delete m_version; @@ -1779,7 +1967,7 @@ class ChannelImpl : /** * Context instance. */ - NamedLockPattern* m_namedLocker; + NamedLockPattern* m_namedLocker; /** * Context instance. @@ -2077,13 +2265,17 @@ int main(int argc,char *argv[]) { ClientContextImpl* context = new ClientContextImpl(); context->printInfo(); + + context->initialize(); + context->printInfo(); + epicsThreadSleep ( 1.0 ); - ChannelFindRequesterImpl findRequester; - context->getProvider()->channelFind("something", &findRequester); + //ChannelFindRequesterImpl findRequester; + //context->getProvider()->channelFind("something", &findRequester); ChannelRequesterImpl channelRequester; - Channel* channel = context->getProvider()->createChannel("test", &channelRequester); + Channel* channel = context->getProvider()->createChannel("structureArrayTest", &channelRequester); channel->printInfo(); /* GetFieldRequesterImpl getFieldRequesterImpl; @@ -2122,6 +2314,7 @@ int main(int argc,char *argv[]) monitor->destroy(); */ + epicsThreadSleep ( 10.0 ); channel->destroy(); context->destroy();