diff --git a/.cproject b/.cproject index e91f269..0e0c996 100644 --- a/.cproject +++ b/.cproject @@ -307,7 +307,6 @@ make - all true true @@ -315,7 +314,6 @@ make - clean true true @@ -323,11 +321,20 @@ make + uninstall true true false + + make + + clean all DEBUG=1 + true + true + false + diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index 287667b..7f70b02 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -24,4 +24,11 @@ # take effect. #IOCS_APPL_TOP = -USR_LDFLAGS += -lpthread +ifeq ($(DEBUG),1) + DEBUG_CFLAGS=-O0 -g -ggdb +endif + +ifeq ($(EPICS_HOST_ARCH),linux-x86) + USR_LDFLAGS += -lpthread +endif + diff --git a/pvAccessApp/Makefile b/pvAccessApp/Makefile index bd26f53..ce364c2 100644 --- a/pvAccessApp/Makefile +++ b/pvAccessApp/Makefile @@ -67,6 +67,12 @@ LIBSRCS += blockingTCPConnector.cpp LIBSRCS += blockingServerTCPTransport.cpp LIBSRCS += blockingTCPAcceptor.cpp LIBSRCS += channelSearchManager.cpp +LIBSRCS += abstractResponseHandler.cpp + + +SRC_DIRS += $(PVACCESS)/remoteClient +INC += clientContextImpl.h + LIBRARY = pvAccess pvAccess_LIBS += Com diff --git a/pvAccessApp/remote/abstractResponseHandler.cpp b/pvAccessApp/remote/abstractResponseHandler.cpp new file mode 100644 index 0000000..2d5f0b3 --- /dev/null +++ b/pvAccessApp/remote/abstractResponseHandler.cpp @@ -0,0 +1,42 @@ +/* + * abstractResponseHandler.cpp + * + * Created on: Jan 10, 2011 + * Author: Miha Vitorovic + */ + +#include "remote.h" +#include "hexDump.h" + +#include + +#include + +#include + +using std::ostringstream; +using std::hex; + +using namespace epics::pvData; + +namespace epics { + namespace pvAccess { + + void AbstractResponseHandler::handleResponse(osiSockAddr* responseFrom, + Transport* transport, int8 version, int8 command, + int payloadSize, ByteBuffer* payloadBuffer) { + if(_debug) { + char ipAddrStr[48]; + ipAddrToDottedIP(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr)); + + ostringstream prologue; + prologue<<"Message [0x"<getArray(), + payloadBuffer->getPosition(), payloadSize); + } + } + } +} diff --git a/pvAccessApp/remote/beaconHandler.h b/pvAccessApp/remote/beaconHandler.h index 2a033a6..ed9b93a 100644 --- a/pvAccessApp/remote/beaconHandler.h +++ b/pvAccessApp/remote/beaconHandler.h @@ -18,8 +18,9 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { - //TODO delete this + class ClientContextImpl; + /** * BeaconHandler */ diff --git a/pvAccessApp/remote/blockingClientTCPTransport.cpp b/pvAccessApp/remote/blockingClientTCPTransport.cpp index a18f7a5..b793374 100644 --- a/pvAccessApp/remote/blockingClientTCPTransport.cpp +++ b/pvAccessApp/remote/blockingClientTCPTransport.cpp @@ -97,7 +97,7 @@ namespace epics { if(_closed) return false; char ipAddrStr[48]; - ipAddrToA(&_socketAddress->ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&_socketAddress->ia, ipAddrStr, sizeof(ipAddrStr)); errlogSevPrintf(errlogInfo, "Acquiring transport to %s.", ipAddrStr); _ownersMutex->lock(); @@ -127,7 +127,7 @@ namespace epics { int refs = _owners->size(); if(refs>0) { char ipAddrStr[48]; - ipAddrToA(&_socketAddress->ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&_socketAddress->ia, ipAddrStr, sizeof(ipAddrStr)); errlogSevPrintf( errlogInfo, "Transport to %s still has %d client(s) active and closing...", @@ -145,7 +145,7 @@ namespace epics { if(_closed) return; char ipAddrStr[48]; - ipAddrToA(&_socketAddress->ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&_socketAddress->ia, ipAddrStr, sizeof(ipAddrStr)); errlogSevPrintf(errlogInfo, "Releasing transport to %s.", ipAddrStr); diff --git a/pvAccessApp/remote/blockingServerTCPTransport.cpp b/pvAccessApp/remote/blockingServerTCPTransport.cpp index b051e2c..042a2b8 100644 --- a/pvAccessApp/remote/blockingServerTCPTransport.cpp +++ b/pvAccessApp/remote/blockingServerTCPTransport.cpp @@ -52,14 +52,14 @@ namespace epics { if(_channels->size()==0) return; char ipAddrStr[64]; - ipAddrToA(&_socketAddress->ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&_socketAddress->ia, ipAddrStr, sizeof(ipAddrStr)); errlogSevPrintf( errlogInfo, "Transport to %s still has %d channel(s) active and closing...", ipAddrStr, _channels->size()); - map::iterator it = _channels->begin(); + map::iterator it = _channels->begin(); for(; it!=_channels->end(); it++) it->second->destroy(); @@ -71,30 +71,30 @@ namespace epics { destroyAllChannels(); } - int BlockingServerTCPTransport::preallocateChannelSID() { + pvAccessID BlockingServerTCPTransport::preallocateChannelSID() { Lock lock(_channelsMutex); // search first free (theoretically possible loop of death) - int sid = ++_lastChannelSID; + pvAccessID sid = ++_lastChannelSID; while(_channels->find(sid)!=_channels->end()) sid = ++_lastChannelSID; return sid; } - void BlockingServerTCPTransport::registerChannel(int sid, + void BlockingServerTCPTransport::registerChannel(pvAccessID sid, ServerChannel* channel) { Lock lock(_channelsMutex); (*_channels)[sid] = channel; } - void BlockingServerTCPTransport::unregisterChannel(int sid) { + void BlockingServerTCPTransport::unregisterChannel(pvAccessID sid) { Lock lock(_channelsMutex); _channels->erase(sid); } - ServerChannel* BlockingServerTCPTransport::getChannel(int sid) { + ServerChannel* BlockingServerTCPTransport::getChannel(pvAccessID sid) { Lock lock(_channelsMutex); - map::iterator it = _channels->find(sid); + map::iterator it = _channels->find(sid); if(it!=_channels->end()) return it->second; return NULL; diff --git a/pvAccessApp/remote/blockingTCP.h b/pvAccessApp/remote/blockingTCP.h index d7302e3..b017341 100644 --- a/pvAccessApp/remote/blockingTCP.h +++ b/pvAccessApp/remote/blockingTCP.h @@ -547,13 +547,13 @@ namespace epics { * Preallocate new channel SID. * @return new channel server id (SID). */ - virtual int preallocateChannelSID(); + virtual pvAccessID preallocateChannelSID(); /** * De-preallocate new channel SID. * @param sid preallocated channel SID. */ - virtual void depreallocateChannelSID(int sid) { + virtual void depreallocateChannelSID(pvAccessID sid) { // noop } @@ -562,20 +562,20 @@ namespace epics { * @param sid preallocated channel SID. * @param channel channel to register. */ - virtual void registerChannel(int sid, ServerChannel* channel); + virtual void registerChannel(pvAccessID sid, ServerChannel* channel); /** * Unregister a new channel (and deallocates its handle). * @param sid SID */ - virtual void unregisterChannel(int sid); + virtual void unregisterChannel(pvAccessID sid); /** * Get channel by its SID. * @param sid channel SID * @return channel with given SID, NULL otherwise */ - virtual ServerChannel* getChannel(int sid); + virtual ServerChannel* getChannel(pvAccessID sid); /** * Get channel count. @@ -640,12 +640,12 @@ namespace epics { /** * Last SID cache. */ - volatile int _lastChannelSID; + volatile pvAccessID _lastChannelSID; /** * Channel table (SID -> channel mapping). */ - std::map* _channels; + std::map* _channels; Mutex* _channelsMutex; diff --git a/pvAccessApp/remote/blockingTCPAcceptor.cpp b/pvAccessApp/remote/blockingTCPAcceptor.cpp index c5bfcb7..10c5f21 100644 --- a/pvAccessApp/remote/blockingTCPAcceptor.cpp +++ b/pvAccessApp/remote/blockingTCPAcceptor.cpp @@ -51,7 +51,7 @@ namespace epics { char strBuffer[64]; char ipAddrStr[48]; - ipAddrToA(&_bindAddress->ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&_bindAddress->ia, ipAddrStr, sizeof(ipAddrStr)); int tryCount = 0; while(tryCount<2) { @@ -150,7 +150,7 @@ namespace epics { void BlockingTCPAcceptor::handleEvents() { // rise level if port is assigned dynamically char ipAddrStr[48]; - ipAddrToA(&_bindAddress->ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&_bindAddress->ia, ipAddrStr, sizeof(ipAddrStr)); errlogSevPrintf(errlogInfo, "Accepting connections at %s.", ipAddrStr); @@ -183,7 +183,8 @@ namespace epics { _serverSocketChannel, &address.sa, &len); if(newClient!=INVALID_SOCKET) { // accept succeeded - ipAddrToA(&address.ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&address.ia, ipAddrStr, + sizeof(ipAddrStr)); errlogSevPrintf(errlogInfo, "Accepted connection from CA client: %s", ipAddrStr); @@ -273,7 +274,8 @@ namespace epics { if(_serverSocketChannel!=INVALID_SOCKET) { char ipAddrStr[48]; - ipAddrToA(&_bindAddress->ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&_bindAddress->ia, ipAddrStr, + sizeof(ipAddrStr)); errlogSevPrintf(errlogInfo, "Stopped accepting connections at %s.", ipAddrStr); diff --git a/pvAccessApp/remote/blockingTCPConnector.cpp b/pvAccessApp/remote/blockingTCPConnector.cpp index 4a066b6..5c3b021 100644 --- a/pvAccessApp/remote/blockingTCPConnector.cpp +++ b/pvAccessApp/remote/blockingTCPConnector.cpp @@ -38,7 +38,7 @@ namespace epics { if(tryCount>0) epicsThreadSleep(0.1); char strBuffer[64]; - ipAddrToA(&address.ia, strBuffer, sizeof(strBuffer)); + ipAddrToDottedIP(&address.ia, strBuffer, sizeof(strBuffer)); errlogSevPrintf(errlogInfo, "Opening socket to CA server %s, attempt %d.", @@ -73,7 +73,7 @@ namespace epics { SOCKET socket = INVALID_SOCKET; char ipAddrStr[64]; - ipAddrToA(&address.ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&address.ia, ipAddrStr, sizeof(ipAddrStr)); // first try to check cache w/o named lock... BlockingClientTCPTransport @@ -106,6 +106,17 @@ namespace epics { ipAddrStr); socket = tryConnect(address, 3); + // verify + if(socket==INVALID_SOCKET) { + errlogSevPrintf( + errlogMajor, + "Connection to CA server %s failed.", + ipAddrStr); + ostringstream temp; + temp<<"Failed to verify TCP connection to '"<waitUntilVerified(3.0)) { transport->close(true); errlogSevPrintf( - errlogInfo, + errlogMinor, "Connection to CA server %s failed to be validated, closing it.", ipAddrStr); ostringstream temp; diff --git a/pvAccessApp/remote/channelSearchManager.h b/pvAccessApp/remote/channelSearchManager.h index c18ca62..93a1873 100644 --- a/pvAccessApp/remote/channelSearchManager.h +++ b/pvAccessApp/remote/channelSearchManager.h @@ -24,216 +24,6 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { -typedef int32 pvAccessID; - -enum QoS { - /** - * Default behavior. - */ - DEFAULT = 0x00, - /** - * Require reply (acknowledgment for reliable operation). - */ - REPLY_REQUIRED = 0x01, - /** - * Best-effort option (no reply). - */ - BESY_EFFORT = 0x02, - /** - * Process option. - */ - PROCESS = 0x04, - /** - * Initialize option. - */ - INIT = 0x08, - /** - * Destroy option. - */ - DESTROY = 0x10, - /** - * Share data option. - */ - SHARE = 0x20, - /** - * Get. - */ - GET = 0x40, - /** - * Get-put. - */ - GET_PUT =0x80 -}; - - -//TODO this will be deleted -class ChannelImpl; -class ChannelSearchManager; -class ClientContextImpl : public ClientContext -{ -private: - Timer* _timer; - public: - - ClientContextImpl() - { - _timer = new Timer("krneki",lowPriority); - } - - virtual Version* getVersion() { - return NULL; - } - - virtual ChannelProvider* getProvider() { - return NULL; - } - - Timer* getTimer() - { - return _timer; - } - - virtual void initialize() { - - } - - virtual void printInfo() { - - } - - virtual void printInfo(epics::pvData::StringBuilder out) { - - } - - virtual void destroy() - { - - } - - virtual void dispose() - { - - } - - BlockingUDPTransport* getSearchTransport() - { - return NULL; - } - - /** - * Searches for a channel with given channel ID. - * @param channelID CID. - * @return channel with given CID, 0 if non-existent. - */ - ChannelImpl* getChannel(pvAccessID channelID) - { - return NULL; - } - - ~ClientContextImpl() { delete _timer;}; - private: - - - void loadConfiguration() { - - } - - void internalInitialize() { - - - } - - void initializeUDPTransport() { - - } - - void internalDestroy() { - - } - - void destroyAllChannels() { - - } - - /** - * Check channel name. - */ - void checkChannelName(String& name) { - - } - - /** - * Check context state and tries to establish necessary state. - */ - void checkState() { - - } - - - - /** - * Generate Client channel ID (CID). - * @return Client channel ID (CID). - */ - pvAccessID generateCID() - { - return 0; - } - - /** - * Free generated channel ID (CID). - */ - void freeCID(int cid) - { - - } - - - /** - * Get, or create if necessary, transport of given server address. - * @param serverAddress required transport address - * @param priority process priority. - * @return transport for given address - */ - Transport* getTransport(TransportClient* client, osiSockAddr* serverAddress, int16 minorRevision, int16 priority) - { - - return NULL; - } - - /** - * Internal create channel. - */ - // TODO no minor version with the addresses - // TODO what if there is an channel with the same name, but on different host! - Channel* createChannelInternal(String name, ChannelRequester* requester, short priority, - InetAddrVector* addresses) { - return NULL; - } - - /** - * Destroy channel. - * @param channel - * @param force - * @throws CAException - * @throws IllegalStateException - */ - void destroyChannel(ChannelImpl* channel, bool force) { - - - } - - /** - * Get channel search manager. - * @return channel search manager. - */ - ChannelSearchManager* getChannelSearchManager() { - return NULL; - } -}; - - - //TODO check the const of paramerers /** @@ -250,13 +40,13 @@ public: * * @return channel ID. */ - virtual pvAccessID getChannelID() = 0; + virtual pvAccessID getSearchInstanceID() = 0; /** - * Return channel name. + * Return search instance, e.g. channel, name. * * @return channel channel name. */ - virtual String getChannelName() = 0; + virtual String getSearchInstanceName() = 0; /** * Removes the owner of this search instance. */ @@ -303,8 +93,8 @@ class BaseSearchInstance : public SearchInstance { public: virtual ~BaseSearchInstance() {}; - virtual pvAccessID getChannelID() = 0; - virtual string getChannelName() = 0; + virtual pvAccessID getSearchInstanceID() = 0; + virtual String getSearchInstanceName() = 0; virtual void unsetListOwnership(); virtual void addAndSetListOwnership(ArrayFIFO* newOwner, Mutex* ownerMutex, int32 index); virtual void removeAndUnsetListOwnership(); @@ -479,7 +269,7 @@ public: * Constructor. * @param context */ - ChannelSearchManager(ClientContextImpl* context); + ChannelSearchManager(Context* context); /** * Constructor. * @param context @@ -533,7 +323,7 @@ private: /** * Context. */ - ClientContextImpl* _context; + Context* _context; /** * Canceled flag. */ diff --git a/pvAccessApp/remote/remote.h b/pvAccessApp/remote/remote.h index 9f0c547..496c818 100644 --- a/pvAccessApp/remote/remote.h +++ b/pvAccessApp/remote/remote.h @@ -11,7 +11,7 @@ #include "caConstants.h" #include "transportRegistry.h" #include "introspectionRegistry.h" -#include "serverContext.h" +#include "configuration.h" #include #include @@ -31,6 +31,47 @@ namespace epics { TCP, UDP, SSL }; + enum QoS { + /** + * Default behavior. + */ + DEFAULT = 0x00, + /** + * Require reply (acknowledgment for reliable operation). + */ + REPLY_REQUIRED = 0x01, + /** + * Best-effort option (no reply). + */ + BESY_EFFORT = 0x02, + /** + * Process option. + */ + PROCESS = 0x04, + /** + * Initialize option. + */ + INIT = 0x08, + /** + * Destroy option. + */ + DESTROY = 0x10, + /** + * Share data option. + */ + SHARE = 0x20, + /** + * Get. + */ + GET = 0x40, + /** + * Get-put. + */ + GET_PUT = 0x80 + }; + + typedef int32 pvAccessID; + enum MessageCommands { CMD_BEACON = 0, CMD_CONNECTION_VALIDATION = 1, CMD_ECHO = 2, CMD_SEARCH = 3, CMD_SEARCH_RESPONSE = 4, @@ -212,6 +253,35 @@ namespace epics { }; + class Channel; + + /** + * Not public IF, used by Transports, etc. + */ + class Context { + public: + virtual ~Context() { + } + /** + * Get timer. + * @return timer. + */ + virtual Timer* getTimer() = 0; + + /** + * Get transport (virtual circuit) registry. + * @return transport (virtual circuit) registry. + */ + virtual TransportRegistry* getTransportRegistry() = 0; + + virtual Channel* getChannel(pvAccessID id) = 0; + + virtual Transport* getSearchTransport() = 0; + + virtual Configuration* getConfiguration() = 0; + + }; + /** * Interface defining response handler. * @author Matej Sekoranja @@ -219,12 +289,9 @@ namespace epics { */ class ResponseHandler { public: - virtual ~ResponseHandler() { - } - /** * Handle response. - * @param[in] responseFrom remote address of the responder, null if unknown. + * @param[in] responseFrom remote address of the responder, 0 if unknown. * @param[in] transport response source transport. * @param[in] version message version. * @param[in] payloadSize size of this message data available in the payloadBuffer. @@ -248,9 +315,9 @@ namespace epics { /** * @param description */ - AbstractResponseHandler(String description) : - _description(description), _debug(true) { - //debug = System.getProperties().containsKey(CAConstants.CAJ_DEBUG); + AbstractResponseHandler(Context* context, String description) : + _description(description), + _debug(context->getConfiguration()->getPropertyAsBoolean("PVACCESS_DEBUG", false)) { } virtual ~AbstractResponseHandler() { @@ -332,23 +399,6 @@ namespace epics { }; - class Context { - public: - virtual ~Context() { - } - /** - * Get timer. - * @return timer. - */ - virtual Timer* getTimer() =0; - - /** - * Get transport (virtual circuit) registry. - * @return transport (virtual circuit) registry. - */ - virtual TransportRegistry* getTransportRegistry() =0; - }; - /** * Interface defining reference counting transport IF. * @author Matej Sekoranja @@ -381,7 +431,7 @@ namespace epics { * Get channel SID. * @return channel SID. */ - virtual int getSID() =0; + virtual pvAccessID getSID() =0; /** * Destroy server channel. @@ -410,33 +460,34 @@ namespace epics { * Preallocate new channel SID. * @return new channel server id (SID). */ - virtual int preallocateChannelSID() =0; + virtual pvAccessID preallocateChannelSID() =0; /** * De-preallocate new channel SID. * @param sid preallocated channel SID. */ - virtual void depreallocateChannelSID(int sid) =0; + virtual void depreallocateChannelSID(pvAccessID sid) =0; /** * Register a new channel. * @param sid preallocated channel SID. * @param channel channel to register. */ - virtual void registerChannel(int sid, ServerChannel* channel) =0; + virtual void + registerChannel(pvAccessID sid, ServerChannel* channel) =0; /** * Unregister a new channel (and deallocates its handle). * @param sid SID */ - virtual void unregisterChannel(int sid) =0; + virtual void unregisterChannel(pvAccessID sid) =0; /** * Get channel by its SID. * @param sid channel SID * @return channel with given SID, null otherwise */ - virtual ServerChannel* getChannel(int sid) =0; + virtual ServerChannel* getChannel(pvAccessID sid) =0; /** * Get channel count. @@ -445,6 +496,44 @@ namespace epics { virtual int getChannelCount() =0; }; + /** + * A request that expects an response. + * Responses identified by its I/O ID. + * This interface needs to be extended (to provide method called on response). + * @author Matej Sekoranja + */ + class ResponseRequest { + public: + + /** + * Get I/O ID. + * @return ioid + */ + virtual pvAccessID getIOID() = 0; + + /** + * Timeout notification. + */ + virtual void timeout() = 0; + + /** + * Cancel response request (always to be called to complete/destroy). + */ + virtual void cancel() = 0; + + /** + * Report status to clients (e.g. disconnected). + * @param status to report. + */ + virtual void reportStatus(epics::pvData::Status* status) = 0; + + /** + * Get request requester. + * @return request requester. + */ + virtual epics::pvData::Requester* getRequester() = 0; + }; + } } diff --git a/pvAccessApp/remoteClient/clientContextImpl.h b/pvAccessApp/remoteClient/clientContextImpl.h new file mode 100644 index 0000000..378abcf --- /dev/null +++ b/pvAccessApp/remoteClient/clientContextImpl.h @@ -0,0 +1,53 @@ +/* + * clientContext.h + * + * Created on: Dec 21, 2010 + * Author: msekoran + */ + +#ifndef CLIENTCONTEXTIMPL_H_ +#define CLIENTCONTEXTIMPL_H_ + +#include +#include +#include + +namespace epics { + namespace pvAccess { + + class ChannelImpl : + public Channel , + public TransportClient, + public TransportSender, + public BaseSearchInstance + { + public: + virtual pvAccessID getChannelID() = 0; + virtual void destroyChannel(bool force) = 0; + virtual void connectionCompleted(pvAccessID sid/*, rights*/) = 0; + virtual void createChannelFailed() = 0; + + + }; + + class ClientContextImpl : public ClientContext, public Context + { + public: + virtual ChannelSearchManager* getChannelSearchManager() = 0; + virtual void checkChannelName(String& name) = 0; + + virtual void registerChannel(ChannelImpl* channel) = 0; + virtual void unregisterChannel(ChannelImpl* channel) = 0; + + virtual void destroyChannel(ChannelImpl* channel, bool force) = 0; + virtual ChannelImpl* createChannelInternal(String name, ChannelRequester* requester, short priority, InetAddrVector* addresses) = 0; + + virtual Transport* getTransport(TransportClient* client, osiSockAddr* serverAddress, int16 minorRevision, int16 priority) = 0; + + + }; + + } +} + +#endif /* CLIENTCONTEXTIMPL_H_ */ diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index e3bbad5..b96c659 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -24,23 +24,6 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { - void AbstractResponseHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, ByteBuffer* payloadBuffer) { - if(_debug) { - char ipAddrStr[48]; - ipAddrToA(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr)); - - ostringstream prologue; - prologue<<"Message [0x"<getArray(), - payloadBuffer->getPosition(), payloadSize); - } - } - void BadResponse::handleResponse(osiSockAddr* responseFrom, Transport* transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { @@ -48,7 +31,7 @@ namespace epics { transport, version, command, payloadSize, payloadBuffer); char ipAddrStr[48]; - ipAddrToA(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr)); + ipAddrToDottedIP(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr)); errlogSevPrintf(errlogInfo, "Undecipherable message (bad response type %d) from %s.", @@ -56,16 +39,15 @@ namespace epics { } - ServerResponseHandler::ServerResponseHandler(ServerContextImpl* context) : - _context(context) { + ServerResponseHandler::ServerResponseHandler(ServerContextImpl* context) { BadResponse* badResponse = new BadResponse(context); _handlerTable = new ResponseHandler*[HANDLER_TABLE_LENGTH]; // TODO add real handlers, as they are developed - _handlerTable[0] = new NoopResponse(_context, "Beacon"); - _handlerTable[1] = new ConnectionValidationHandler(_context); - _handlerTable[2] = new EchoHandler(_context); + _handlerTable[0] = new NoopResponse(context, "Beacon"); + _handlerTable[1] = new ConnectionValidationHandler(context); + _handlerTable[2] = new EchoHandler(context); _handlerTable[3] = badResponse; _handlerTable[4] = badResponse; _handlerTable[5] = badResponse; diff --git a/pvAccessApp/server/responseHandlers.h b/pvAccessApp/server/responseHandlers.h index afbcdba..ccc3849 100644 --- a/pvAccessApp/server/responseHandlers.h +++ b/pvAccessApp/server/responseHandlers.h @@ -8,6 +8,7 @@ #ifndef RESPONSEHANDLERS_H_ #define RESPONSEHANDLERS_H_ +#include "serverContext.h" #include "remote.h" namespace epics { @@ -18,20 +19,19 @@ namespace epics { * @version $Id: AbstractServerResponseHandler.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class AbstractServerResponseHandler : public AbstractResponseHandler { + protected: + ServerContextImpl* _context; public: /** * @param context * @param description */ - AbstractServerResponseHandler(ServerContextImpl* context, - String description) : - AbstractResponseHandler(description), _context(context) { + AbstractServerResponseHandler(ServerContextImpl* context, String description) : + AbstractResponseHandler(context, description), _context(context) { } virtual ~AbstractServerResponseHandler() { } - protected: - ServerContextImpl* _context; }; /** @@ -77,11 +77,6 @@ namespace epics { */ ResponseHandler** _handlerTable; - /** - * Context instance. - */ - ServerContextImpl* _context; - }; /** diff --git a/pvAccessApp/server/serverContext.h b/pvAccessApp/server/serverContext.h index d535616..c01d52e 100644 --- a/pvAccessApp/server/serverContext.h +++ b/pvAccessApp/server/serverContext.h @@ -8,11 +8,12 @@ #ifndef SERVERCONTEXT_H_ #define SERVERCONTEXT_H_ +#include "remote.h" + namespace epics { namespace pvAccess { - - class ServerContextImpl { + class ServerContextImpl : public Context { }; diff --git a/pvAccessApp/utils/arrayFIFO.h b/pvAccessApp/utils/arrayFIFO.h index d449c56..6de4bdb 100644 --- a/pvAccessApp/utils/arrayFIFO.h +++ b/pvAccessApp/utils/arrayFIFO.h @@ -243,7 +243,7 @@ namespace epics { T ArrayFIFO::pollFirst() { Lock lock(&_mutex); - if(isEmpty()) THROW_BASE_EXCEPTION("ArrayFIFO empty"); + if(isEmpty()) return 0; T result = _elements[_head]; // Element is null if deque empty _head = (_head+1)&(_size-1); @@ -254,7 +254,7 @@ namespace epics { T ArrayFIFO::pollLast() { Lock lock(&_mutex); - if(isEmpty()) THROW_BASE_EXCEPTION("ArrayFIFO empty"); + if(isEmpty()) return 0; _tail = (_tail-1)&(_size-1); return _elements[_tail]; @@ -264,7 +264,7 @@ namespace epics { T ArrayFIFO::peekFirst() { Lock lock(&_mutex); - if(isEmpty()) THROW_BASE_EXCEPTION("ArrayFIFO empty"); + if(isEmpty()) return 0; return _elements[_head]; } @@ -273,7 +273,7 @@ namespace epics { T ArrayFIFO::peekLast() { Lock lock(&_mutex); - if(isEmpty()) THROW_BASE_EXCEPTION("ArrayFIFO empty"); + if(isEmpty()) return 0; return _elements[(_tail-1)&(_size-1)]; } diff --git a/pvAccessApp/utils/growingCircularBuffer.h b/pvAccessApp/utils/growingCircularBuffer.h index 6a993a1..63bb242 100644 --- a/pvAccessApp/utils/growingCircularBuffer.h +++ b/pvAccessApp/utils/growingCircularBuffer.h @@ -28,8 +28,8 @@ namespace epics { * Create a GrowingCircularBuffer with the given capacity. **/ GrowingCircularBuffer(size_t capacity = 16) : - _elements(new T[capacity]), _takePointer(0), _putPointer(0), _count(0), _size(capacity) - { + _elements(new T[capacity]), _takePointer(0), _putPointer(0), + _count(0), _size(capacity) { } ~GrowingCircularBuffer() { @@ -94,13 +94,9 @@ namespace epics { size_t length); }; - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * g++ requires template definition inside a header file. - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - template - void GrowingCircularBuffer::arraycopy(T* src, size_t srcPos, T* dest, - size_t destPos, size_t length) { + void GrowingCircularBuffer::arraycopy(T* src, size_t srcPos, + T* dest, size_t destPos, size_t length) { if(srcPos=0; i--) dest[destPos+i] = src[srcPos+i]; @@ -111,17 +107,16 @@ namespace epics { template bool GrowingCircularBuffer::insert(const T x) { - if (_count == _size) - { + if(_count==_size) { // we are full, grow by factor 2 - T* newElements = new T[_size * 2]; + T* newElements = new T[_size*2]; // invariant: _takePointer < _size - size_t split = _size - _takePointer; - if (split > 0) - arraycopy(_elements, _takePointer, newElements, 0, split); - if (_takePointer != 0) - arraycopy(_elements, 0, newElements, split, _putPointer); + size_t split = _size-_takePointer; + if(split>0) arraycopy(_elements, _takePointer, newElements, 0, + split); + if(_takePointer!=0) arraycopy(_elements, 0, newElements, split, + _putPointer); _takePointer = 0; _putPointer = _size; @@ -132,8 +127,8 @@ namespace epics { _count++; _elements[_putPointer] = x; - if (++_putPointer >= _size) _putPointer = 0; - return _count == 1; + if(++_putPointer>=_size) _putPointer = 0; + return _count==1; } template @@ -146,6 +141,141 @@ namespace epics { return old; } + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * Template specialization for pointers. + * Implementation of circular FIFO unbouded buffer. + * Instance is not thread safe. + * @author Miha Vitorovic + */ + template + class GrowingCircularBuffer { + public: + + /** + * Create a GrowingCircularBuffer with the given capacity. + **/ + GrowingCircularBuffer(size_t capacity = 16) : + _elements(new T*[capacity]), _takePointer(0), _putPointer(0), + _count(0), _size(capacity) { + } + + ~GrowingCircularBuffer() { + delete[] _elements; + } + + /** + * Get number of elements in the buffer. + * @return number of elements in the buffer. + */ + inline size_t size() { + return _count; + } + + /** + * Get current buffer capacity. + * @return buffer current capacity. + */ + inline size_t capacity() { + return _size; + } + + /** + * Insert a new element in to the buffer. + * If buffer full the buffer is doubled. + * + * @param x element to insert. + * @return true if first element. + */ + bool insert(const T* x); + + /** + * Extract the oldest element from the buffer. + * @return the oldest element from the buffer. + */ + T* extract(); + + private: + /** + * Array (circular buffer) of elements. + */ + T** _elements; + + /** + * Take (read) pointer. + */ + size_t _takePointer; + + /** + * Put (write) pointer. + */ + size_t _putPointer; + + /** + * Number of elements in the buffer. + */ + size_t _count; + + size_t _size; + + void arraycopy(T** src, size_t srcPos, T** dest, size_t destPos, + size_t length); + }; + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * g++ requires template definition inside a header file. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + template + void GrowingCircularBuffer::arraycopy(T** src, size_t srcPos, + T** dest, size_t destPos, size_t length) { + if(srcPos=0; i--) + dest[destPos+i] = src[srcPos+i]; + else + for(size_t i = 0; i + bool GrowingCircularBuffer::insert(const T* x) { + if(_count==_size) { + // we are full, grow by factor 2 + T** newElements = new T*[_size*2]; + + // invariant: _takePointer < _size + size_t split = _size-_takePointer; + if(split>0) arraycopy(_elements, _takePointer, newElements, 0, + split); + if(_takePointer!=0) arraycopy(_elements, 0, newElements, split, + _putPointer); + + _takePointer = 0; + _putPointer = _size; + _size *= 2; + delete[] _elements; + _elements = newElements; + } + _count++; + + _elements[_putPointer] = const_cast(x); + if(++_putPointer>=_size) _putPointer = 0; + return _count==1; + } + + template + T* GrowingCircularBuffer::extract() { + if(_count==0) return NULL; + + _count--; + T* old = _elements[_takePointer]; + if(++_takePointer>=_size) _takePointer = 0; + return old; + } + } } #endif /* GROWINGCIRCULARBUFFER_H_ */ diff --git a/pvAccessApp/utils/inetAddressUtil.cpp b/pvAccessApp/utils/inetAddressUtil.cpp index 77eac47..18e1d18 100644 --- a/pvAccessApp/utils/inetAddressUtil.cpp +++ b/pvAccessApp/utils/inetAddressUtil.cpp @@ -32,14 +32,25 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { + void addDefaultBroadcastAddress(InetAddrVector* v, in_port_t p) { + osiSockAddr* pNewNode = new osiSockAddr; + pNewNode->ia.sin_family = AF_INET; + pNewNode->ia.sin_addr.s_addr = htonl(INADDR_BROADCAST); + pNewNode->ia.sin_port = htons(p); + v->push_back(pNewNode); + } + /* port of osiSockDiscoverBroadcastAddresses() in * epics/base/src/libCom/osi/os/default/osdNetIntf.c */ - InetAddrVector* getBroadcastAddresses(SOCKET sock) { + InetAddrVector* getBroadcastAddresses(SOCKET sock, + in_port_t defaultPort) { static const unsigned nelem = 100; int status; struct ifconf ifconf; struct ifreq* pIfreqList; + struct ifreq* pifreq; + struct ifreq ifrBuff; osiSockAddr* pNewNode; InetAddrVector* retVector = new InetAddrVector(); @@ -54,53 +65,72 @@ namespace epics { if(!pIfreqList) { errlogSevPrintf(errlogMajor, "getBroadcastAddresses(): no memory to complete request"); + addDefaultBroadcastAddress(retVector, defaultPort); return retVector; } // get number of interfaces ifconf.ifc_len = nelem*sizeof(ifreq); ifconf.ifc_req = pIfreqList; + memset(ifconf.ifc_req, 0, ifconf.ifc_len); status = ioctl(sock, SIOCGIFCONF, &ifconf); if(status<0||ifconf.ifc_len==0) { - errlogSevPrintf( - errlogMinor, + errlogSevPrintf(errlogMinor, "getBroadcastAddresses(): unable to fetch network interface configuration"); delete[] pIfreqList; + addDefaultBroadcastAddress(retVector, defaultPort); return retVector; } - errlogPrintf("Found %d interfaces\n", ifconf.ifc_len); + int maxNodes = ifconf.ifc_len/sizeof(ifreq); + //errlogPrintf("Found %d interfaces\n", maxNodes); + + pifreq = pIfreqList; + + for(int i = 0; iifr_name)) break; + + if(i>0) { + size_t n = pifreq->ifr_addr.sa_len+sizeof(pifreq->ifr_name); + if(nifr_addr.sa_family!=AF_INET) continue; - status = ioctl(sock, SIOCGIFFLAGS, &pIfreqList[i]); + strncpy(ifrBuff.ifr_name, pifreq->ifr_name, + sizeof(ifrBuff.ifr_name)); + status = ioctl(sock, SIOCGIFFLAGS, &ifrBuff); if(status) { errlogSevPrintf( errlogMinor, "getBroadcastAddresses(): net intf flags fetch for \"%s\" failed", - pIfreqList[i].ifr_name); + pifreq->ifr_name); continue; } /* * dont bother with interfaces that have been disabled */ - if(!(pIfreqList[i].ifr_flags&IFF_UP)) continue; + if(!(ifrBuff.ifr_flags&IFF_UP)) continue; /* * dont use the loop back interface */ - if(pIfreqList[i].ifr_flags&IFF_LOOPBACK) continue; + if(ifrBuff.ifr_flags&IFF_LOOPBACK) continue; pNewNode = new osiSockAddr; if(pNewNode==NULL) { errlogSevPrintf(errlogMajor, "getBroadcastAddresses(): no memory available for configuration"); delete[] pIfreqList; + if(retVector->size()==0) addDefaultBroadcastAddress( + retVector, defaultPort); return retVector; } @@ -114,40 +144,45 @@ namespace epics { * Otherwise CA will not query through the * interface. */ - if(pIfreqList[i].ifr_flags&IFF_BROADCAST) { - status = ioctl(sock, SIOCGIFBRDADDR, &pIfreqList[i]); + if(ifrBuff.ifr_flags&IFF_BROADCAST) { + strncpy(ifrBuff.ifr_name, pifreq->ifr_name, + sizeof(ifrBuff.ifr_name)); + status = ioctl(sock, SIOCGIFBRDADDR, &ifrBuff); if(status) { errlogSevPrintf( errlogMinor, "getBroadcastAddresses(): net intf \"%s\": bcast addr fetch fail", - pIfreqList->ifr_name); + pifreq->ifr_name); delete pNewNode; continue; } - pNewNode->sa = pIfreqList[i].ifr_broadaddr; + pNewNode->sa = ifrBuff.ifr_broadaddr; } #ifdef IFF_POINTOPOINT - else if(pIfreqList->ifr_flags&IFF_POINTOPOINT) { - status = ioctl(sock, SIOCGIFDSTADDR, &pIfreqList[i]); + else if(ifrBuff.ifr_flags&IFF_POINTOPOINT) { + strncpy(ifrBuff.ifr_name, pifreq->ifr_name, + sizeof(ifrBuff.ifr_name)); + status = ioctl(sock, SIOCGIFDSTADDR, &ifrBuff); if(status) { errlogSevPrintf( errlogMinor, "getBroadcastAddresses(): net intf \"%s\": pt to pt addr fetch fail", - pIfreqList[i].ifr_name); + pifreq->ifr_name); delete pNewNode; continue; } - pNewNode->sa = pIfreqList[i].ifr_dstaddr; + pNewNode->sa = ifrBuff.ifr_dstaddr; } #endif else { errlogSevPrintf( errlogMinor, "getBroadcastAddresses(): net intf \"%s\": not point to point or bcast?", - pIfreqList[i].ifr_name); + pifreq->ifr_name); delete pNewNode; continue; } + pNewNode->ia.sin_port = htons(defaultPort); retVector->push_back(pNewNode); } diff --git a/pvAccessApp/utils/inetAddressUtil.h b/pvAccessApp/utils/inetAddressUtil.h index ee7f381..e8ee082 100644 --- a/pvAccessApp/utils/inetAddressUtil.h +++ b/pvAccessApp/utils/inetAddressUtil.h @@ -33,8 +33,12 @@ namespace epics { /** * returns a vector containing all the IPv4 broadcast addresses * on this machine. IPv6 doesn't have a local broadcast address. - */ - InetAddrVector* getBroadcastAddresses(SOCKET sock); + * Conversion of the defaultPort to network byte order performed by + * the function. + * TODO: Windows implementation of the function. + */ + InetAddrVector* getBroadcastAddresses(SOCKET sock, + in_port_t defaultPort); /** * Encode IPv4 address as IPv6 address. diff --git a/testApp/remote/testBeaconEmitter.cpp b/testApp/remote/testBeaconEmitter.cpp index 0d3c904..9e98d85 100644 --- a/testApp/remote/testBeaconEmitter.cpp +++ b/testApp/remote/testBeaconEmitter.cpp @@ -18,6 +18,8 @@ using namespace epics::pvData; class DummyResponseHandler : public ResponseHandler { public: + DummyResponseHandler(Context* ctx) : ResponseHandler() {} + virtual void handleResponse(osiSockAddr* responseFrom, Transport* transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) @@ -27,9 +29,33 @@ public: }; +class ContextImpl : public Context { +public: + ContextImpl() : + _tr(new TransportRegistry()), _timer(new Timer("server thread", + lowPriority)), _conf(new SystemConfigurationImpl()) { + } + virtual ~ContextImpl() { + delete _tr; + delete _timer; + } + virtual Timer* getTimer() { return _timer; } + virtual TransportRegistry* getTransportRegistry() { return _tr; } + virtual Channel* getChannel(epics::pvAccess::pvAccessID) { return 0; } + virtual Transport* getSearchTransport() { return 0; } + virtual Configuration* getConfiguration() { return _conf; } + +private: + TransportRegistry* _tr; + Timer* _timer; + Configuration* _conf; +}; + + void testBeaconEmitter() { - DummyResponseHandler drh; + ContextImpl ctx; + DummyResponseHandler drh(&ctx); /* SOCKET mysocket; if ((mysocket = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { diff --git a/testApp/remote/testBeaconHandler.cpp b/testApp/remote/testBeaconHandler.cpp index 0ac231c..0e5ec28 100644 --- a/testApp/remote/testBeaconHandler.cpp +++ b/testApp/remote/testBeaconHandler.cpp @@ -37,7 +37,7 @@ void decodeFromIPv6Address(ByteBuffer* buffer, osiSockAddr* address) class BeaconResponseHandler : public ResponseHandler { public: - BeaconResponseHandler() + BeaconResponseHandler(Context* ctx) : ResponseHandler() { _pvDataCreate = getPVDataCreate(); } @@ -103,9 +103,33 @@ private: }; +class ContextImpl : public Context { +public: + ContextImpl() : + _tr(new TransportRegistry()), _timer(new Timer("server thread", + lowPriority)), _conf(new SystemConfigurationImpl()) { + } + virtual ~ContextImpl() { + delete _tr; + delete _timer; + } + virtual Timer* getTimer() { return _timer; } + virtual TransportRegistry* getTransportRegistry() { return _tr; } + virtual Channel* getChannel(epics::pvAccess::pvAccessID) { return 0; } + virtual Transport* getSearchTransport() { return 0; } + virtual Configuration* getConfiguration() { return _conf; } + +private: + TransportRegistry* _tr; + Timer* _timer; + Configuration* _conf; +}; + + void testBeaconHandler() { - BeaconResponseHandler brh; + ContextImpl ctx; + BeaconResponseHandler brh(&ctx); BlockingUDPConnector connector(false, NULL, true); osiSockAddr bindAddr; diff --git a/testApp/remote/testBlockingTCPClnt.cpp b/testApp/remote/testBlockingTCPClnt.cpp index 3f69392..4340caa 100644 --- a/testApp/remote/testBlockingTCPClnt.cpp +++ b/testApp/remote/testBlockingTCPClnt.cpp @@ -29,26 +29,30 @@ using std::sscanf; class ContextImpl : public Context { public: ContextImpl() : - _tr(new TransportRegistry()), _timer(new Timer("client thread", - lowPriority)) { + _tr(new TransportRegistry()), _timer(new Timer("server thread", + lowPriority)), _conf(new SystemConfigurationImpl()) { } virtual ~ContextImpl() { delete _tr; delete _timer; } - virtual Timer* getTimer() { - return _timer; - } - virtual TransportRegistry* getTransportRegistry() { - return _tr; - } + virtual Timer* getTimer() { return _timer; } + virtual TransportRegistry* getTransportRegistry() { return _tr; } + virtual Channel* getChannel(epics::pvAccess::pvAccessID) { return 0; } + virtual Transport* getSearchTransport() { return 0; } + virtual Configuration* getConfiguration() { return _conf; } + private: TransportRegistry* _tr; Timer* _timer; + Configuration* _conf; }; class DummyResponseHandler : public ResponseHandler { public: + DummyResponseHandler(Context* ctx) : ResponseHandler() { + } + virtual void handleResponse(osiSockAddr* responseFrom, Transport* transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { @@ -108,7 +112,7 @@ void testBlockingTCPSender() { DummyTransportClient dtc; DummyTransportSender dts; - DummyResponseHandler drh; + DummyResponseHandler drh(&ctx); osiSockAddr srvAddr; diff --git a/testApp/remote/testBlockingTCPSrv.cpp b/testApp/remote/testBlockingTCPSrv.cpp index 704093a..c7ced35 100644 --- a/testApp/remote/testBlockingTCPSrv.cpp +++ b/testApp/remote/testBlockingTCPSrv.cpp @@ -8,6 +8,7 @@ #include "blockingTCP.h" #include "remote.h" #include "logger.h" +#include "configuration.h" #include @@ -21,16 +22,22 @@ class ContextImpl : public Context { public: ContextImpl() : _tr(new TransportRegistry()), - _timer(new Timer("server thread", lowPriority)) {} + _timer(new Timer("server thread", lowPriority)), + _conf(new SystemConfigurationImpl()) {} virtual ~ContextImpl() { delete _tr; delete _timer; } virtual Timer* getTimer() { return _timer; } virtual TransportRegistry* getTransportRegistry() { return _tr; } + virtual Channel* getChannel(epics::pvAccess::pvAccessID) { return 0; } + virtual Transport* getSearchTransport() { return 0; } + virtual Configuration* getConfiguration() { return _conf; } + private: TransportRegistry* _tr; Timer* _timer; + Configuration* _conf; }; void testServerConnections() { @@ -40,7 +47,7 @@ void testServerConnections() { 1024); cout<<"Press any key to stop the server..."; - char c = cin.peek(); + cin.peek(); delete srv; } diff --git a/testApp/remote/testBlockingUDPClnt.cpp b/testApp/remote/testBlockingUDPClnt.cpp index 06443aa..7fb490c 100644 --- a/testApp/remote/testBlockingUDPClnt.cpp +++ b/testApp/remote/testBlockingUDPClnt.cpp @@ -26,8 +26,43 @@ using std::sscanf; static osiSockAddr sendTo; +class ContextImpl : public Context { +public: + ContextImpl() : + _tr(new TransportRegistry()), _timer(new Timer("server thread", + lowPriority)), _conf(new SystemConfigurationImpl()) { + } + virtual ~ContextImpl() { + delete _tr; + delete _timer; + } + virtual Timer* getTimer() { + return _timer; + } + virtual TransportRegistry* getTransportRegistry() { + return _tr; + } + virtual Channel* getChannel(epics::pvAccess::pvAccessID) { + return 0; + } + virtual Transport* getSearchTransport() { + return 0; + } + virtual Configuration* getConfiguration() { + return _conf; + } + +private: + TransportRegistry* _tr; + Timer* _timer; + Configuration* _conf; +}; + class DummyResponseHandler : public ResponseHandler { public: + DummyResponseHandler(Context* ctx) + { } + virtual void handleResponse(osiSockAddr* responseFrom, Transport* transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { @@ -69,9 +104,10 @@ private: void testBlockingUDPSender() { BlockingUDPConnector connector(false, NULL, true); + ContextImpl ctx; DummyTransportSender dts; - DummyResponseHandler drh; + DummyResponseHandler drh(&ctx); osiSockAddr bindAddr; diff --git a/testApp/remote/testBlockingUDPSrv.cpp b/testApp/remote/testBlockingUDPSrv.cpp index 6b713bb..5308428 100644 --- a/testApp/remote/testBlockingUDPSrv.cpp +++ b/testApp/remote/testBlockingUDPSrv.cpp @@ -21,10 +21,42 @@ using std::endl; using std::hex; using std::dec; +class ContextImpl : public Context { +public: + ContextImpl() : + _tr(new TransportRegistry()), _timer(new Timer("server thread", + lowPriority)), _conf(new SystemConfigurationImpl()) { + } + virtual ~ContextImpl() { + delete _tr; + delete _timer; + } + virtual Timer* getTimer() { + return _timer; + } + virtual TransportRegistry* getTransportRegistry() { + return _tr; + } + virtual Channel* getChannel(epics::pvAccess::pvAccessID) { + return 0; + } + virtual Transport* getSearchTransport() { + return 0; + } + virtual Configuration* getConfiguration() { + return _conf; + } + +private: + TransportRegistry* _tr; + Timer* _timer; + Configuration* _conf; +}; + class DummyResponseHandler : public ResponseHandler { public: - DummyResponseHandler() : - packets(0) { + DummyResponseHandler(Context* context) + : packets(0) { } int getPackets() { @@ -71,8 +103,9 @@ void DummyResponseHandler::handleResponse(osiSockAddr* responseFrom, void testBlockingUDPConnector() { BlockingUDPConnector connector(false, NULL, true); + ContextImpl ctx; - DummyResponseHandler drh; + DummyResponseHandler drh(&ctx); osiSockAddr bindAddr; diff --git a/testApp/remote/testRemoteClientImpl.cpp b/testApp/remote/testRemoteClientImpl.cpp index f917251..e9ca92b 100644 --- a/testApp/remote/testRemoteClientImpl.cpp +++ b/testApp/remote/testRemoteClientImpl.cpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include using namespace epics::pvData; using namespace epics::pvAccess; @@ -33,7 +36,7 @@ class ChannelImplProcess : public ChannelProcess ChannelProcessRequester* m_channelProcessRequester; PVStructure* m_pvStructure; PVScalar* m_valueField; - + private: ~ChannelImplProcess() { @@ -52,29 +55,29 @@ class ChannelImplProcess : public ChannelProcess Status* noValueFieldStatus = getStatusCreate()->createStatus(STATUSTYPE_ERROR, "no 'value' field"); m_channelProcessRequester->channelProcessConnect(noValueFieldStatus, this); delete noValueFieldStatus; - + // NOTE client must destroy this instance... // do not access any fields and return ASAP return; } - + if (field->getField()->getType() != scalar) { Status* notAScalarStatus = getStatusCreate()->createStatus(STATUSTYPE_ERROR, "'value' field not scalar type"); m_channelProcessRequester->channelProcessConnect(notAScalarStatus, this); delete notAScalarStatus; - + // NOTE client must destroy this instance…. // do not access any fields and return ASAP return; } - + m_valueField = static_cast(field); - - // TODO pvRequest + + // TODO pvRequest m_channelProcessRequester->channelProcessConnect(getStatusCreate()->getStatusOK(), this); } - + virtual void process(bool lastRequest) { switch (m_valueField->getScalar()->getScalarType()) @@ -146,19 +149,19 @@ class ChannelImplProcess : public ChannelProcess default: // noop break; - - } + + } m_channelProcessRequester->processDone(getStatusCreate()->getStatusOK()); - + if (lastRequest) destroy(); } - + virtual void destroy() { delete this; } - + }; @@ -175,7 +178,7 @@ class ChannelImplGet : public ChannelGet PVStructure* m_pvStructure; BitSet* m_bitSet; volatile bool m_first; - + private: ~ChannelImplGet() { @@ -189,10 +192,10 @@ class ChannelImplGet : public ChannelGet { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelGet); - // TODO pvRequest + // TODO pvRequest m_channelGetRequester->channelGetConnect(getStatusCreate()->getStatusOK(), this, m_pvStructure, m_bitSet); } - + virtual void get(bool lastRequest) { m_channelGetRequester->getDone(getStatusCreate()->getStatusOK()); @@ -201,17 +204,17 @@ class ChannelImplGet : public ChannelGet m_first = false; m_bitSet->set(0); // TODO } - + if (lastRequest) destroy(); } - + virtual void destroy() { delete m_bitSet; delete this; } - + }; @@ -230,7 +233,7 @@ class ChannelImplPut : public ChannelPut PVStructure* m_pvStructure; BitSet* m_bitSet; volatile bool m_first; - + private: ~ChannelImplPut() { @@ -244,17 +247,17 @@ class ChannelImplPut : public ChannelPut { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelPut); - // TODO pvRequest + // TODO pvRequest m_channelPutRequester->channelPutConnect(getStatusCreate()->getStatusOK(), this, m_pvStructure, m_bitSet); } - + virtual void put(bool lastRequest) { m_channelPutRequester->putDone(getStatusCreate()->getStatusOK()); if (lastRequest) destroy(); } - + virtual void get() { m_channelPutRequester->getDone(getStatusCreate()->getStatusOK()); @@ -265,7 +268,7 @@ class ChannelImplPut : public ChannelPut delete m_bitSet; delete this; } - + }; @@ -286,7 +289,7 @@ class MockMonitor : public Monitor, public MonitorElement volatile bool m_first; Mutex* m_lock; volatile int m_count; - + private: ~MockMonitor() { @@ -305,16 +308,16 @@ class MockMonitor : public Monitor, public MonitorElement PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockMonitor); m_changedBitSet->set(0); - - // TODO pvRequest + + // TODO pvRequest m_monitorRequester->monitorConnect(getStatusCreate()->getStatusOK(), this, const_cast(m_pvStructure->getStructure())); } - + virtual Status* start() { // fist monitor m_monitorRequester->monitorEvent(this); - + // client needs to delete status, so passing shared OK instance is not right thing to do return getStatusCreate()->createStatus(STATUSTYPE_OK, "Monitor started."); } @@ -345,24 +348,24 @@ class MockMonitor : public Monitor, public MonitorElement if (m_count) m_count--; } - + virtual void destroy() { delete stop(); - + delete m_lock; delete m_overrunBitSet; delete m_changedBitSet; delete this; } - + // ============ MonitorElement ============ - + virtual PVStructure* getPVStructure() { return m_pvStructure; } - + virtual BitSet* getChangedBitSet() { return m_changedBitSet; @@ -372,54 +375,12 @@ class MockMonitor : public Monitor, public MonitorElement { return m_overrunBitSet; } - - + + }; -typedef int pvAccessID; - - -/** - * A request that expects an response. - * Responses identified by its I/O ID. - * This interface needs to be extended (to provide method called on response). - * @author Matej Sekoranja - */ -class ResponseRequest { - public: - - /** - * Get I/O ID. - * @return ioid - */ - virtual pvAccessID getIOID() = 0; - - /** - * Timeout notification. - */ - virtual void timeout() = 0; - - /** - * Cancel response request (always to be called to complete/destroy). - */ - virtual void cancel() = 0; - - /** - * Report status to clients (e.g. disconnected). - * @param status to report. - */ - virtual void reportStatus(Status* status) = 0; - - /** - * Get request requester. - * @return request requester. - */ - virtual Requester* getRequester() = 0; -}; - - // TODO consider std::unordered_map typedef std::map IOIDResponseRequestMap; @@ -429,14 +390,34 @@ typedef std::map IOIDResponseRequestMap; #define CALLBACK_GUARD(code) try { code } catch(...) { } -class ClientContextImpl; - class DebugResponse : public ResponseHandler, private epics::pvData::NoDefaultMethods { + /** + * @author Matej Sekoranja + * @version $Id: AbstractServerResponseHandler.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ + */ + class AbstractClientResponseHandler : public AbstractResponseHandler { + protected: + ClientContextImpl* _context; + public: + /** + * @param context + * @param description + */ + AbstractClientResponseHandler(ClientContextImpl* context, String description) : + AbstractResponseHandler(context, description), _context(context) { + } + + virtual ~AbstractClientResponseHandler() { + } + }; + + class DebugResponse : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { public: /** * @param context */ - DebugResponse() + DebugResponse(ClientContextImpl* context) : + AbstractClientResponseHandler(context, "not implemented") { } @@ -447,23 +428,151 @@ class ClientContextImpl; 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; - + ipAddrToDottedIP(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr)); ostringstream prologue; prologue<<"Message [0x"<getArray(), payloadBuffer->getPosition(), payloadSize); - + } }; + class SearchResponseHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + public: + SearchResponseHandler(ClientContextImpl* context) : + AbstractClientResponseHandler(context, "Search response") + { + } + + virtual ~SearchResponseHandler() { + } + + virtual void handleResponse(osiSockAddr* responseFrom, + Transport* transport, int8 version, int8 command, + int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) + { + AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); + + transport->ensureData(5); + int32 searchSequenceId = payloadBuffer->getInt(); + bool found = payloadBuffer->getByte() != 0; + if (!found) + return; + + transport->ensureData((128+2*16)/8); + + osiSockAddr serverAddress; + serverAddress.ia.sin_family = AF_INET; + + // 128-bit IPv6 address + /* + int8* byteAddress = new int8[16]; + for (int i = 0; i < 16; i++) + byteAddress[i] = payloadBuffer->getByte(); }; + */ + + // IPv4 compatible IPv6 address expected + // first 80-bit are 0 + if (payloadBuffer->getLong() != 0) return; + if (payloadBuffer->getShort() != 0) return; + if (payloadBuffer->getShort() != (int16)0xFFFF) return; + + // accept given address if explicitly specified by sender + serverAddress.ia.sin_addr.s_addr = htonl(payloadBuffer->getInt()); + if (serverAddress.ia.sin_addr.s_addr == INADDR_ANY) + serverAddress.ia.sin_addr = responseFrom->ia.sin_addr; + + serverAddress.ia.sin_port = htons(payloadBuffer->getShort()); + + // reads CIDs + ChannelSearchManager* csm = _context->getChannelSearchManager(); + int16 count = payloadBuffer->getShort(); + for (int i = 0; i < count; i++) + { + transport->ensureData(4); + pvAccessID cid = payloadBuffer->getInt(); + csm->searchResponse(cid, searchSequenceId, version & 0x0F, &serverAddress); + } + + + } + }; + + + class ConnectionValidationHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + public: + ConnectionValidationHandler(ClientContextImpl* context) : + AbstractClientResponseHandler(context, "Connection validation") + { + } + + virtual ~ConnectionValidationHandler() { + } + + virtual void handleResponse(osiSockAddr* responseFrom, + Transport* transport, int8 version, int8 command, + int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) + { + AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); + + transport->ensureData(8); + transport->setRemoteTransportReceiveBufferSize(payloadBuffer->getInt()); + transport->setRemoteTransportSocketReceiveBufferSize(payloadBuffer->getInt()); + + transport->setRemoteMinorRevision(version); + + transport->enqueueSendRequest((TransportSender*)transport); + transport->verified(); + + } + }; + + class CreateChannelHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + public: + CreateChannelHandler(ClientContextImpl* context) : + AbstractClientResponseHandler(context, "Create channel") + { + } + + virtual ~CreateChannelHandler() { + } + + virtual void handleResponse(osiSockAddr* responseFrom, + Transport* transport, int8 version, int8 command, + int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) + { + AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); + + transport->ensureData(8); + pvAccessID cid = payloadBuffer->getInt(); + pvAccessID sid = payloadBuffer->getInt(); + // TODO... do not destroy OK + Status* status = transport->getIntrospectionRegistry()->deserializeStatus(payloadBuffer, transport); + + ChannelImpl* channel = static_cast(_context->getChannel(cid)); + if (channel) + { + // failed check + if (!status->isSuccess()) { + channel->createChannelFailed(); + return; + } + + //int16 acl = payloadBuffer->getShort(); + + channel->connectionCompleted(sid); + } + + } + }; + + + /** * CA response handler - main handler which dispatches responses to appripriate handlers. * @author Matej Sekoranja @@ -471,40 +580,40 @@ class ClientContextImpl; */ class ClientResponseHandler : public ResponseHandler, private epics::pvData::NoDefaultMethods { private: - + /** * Table of response handlers for each command ID. */ ResponseHandler** m_handlerTable; - /** - * Context instance. + /* + * Context instance is part of the response handler now */ - ClientContextImpl* m_context; - + //ClientContextImpl* m_context; + public: - + ~ClientResponseHandler() { delete[] m_handlerTable; } - + /** * @param context */ - ClientResponseHandler(ClientContextImpl* context) : m_context(context) { - static ResponseHandler* badResponse = new DebugResponse(); + ClientResponseHandler(ClientContextImpl* context) { + static ResponseHandler* badResponse = new DebugResponse(context); static ResponseHandler* dataResponse = 0; //new DataResponseHandler(context); - + #define HANDLER_COUNT 28 m_handlerTable = new ResponseHandler*[HANDLER_COUNT]; m_handlerTable[ 0] = badResponse; // TODO new BeaconHandler(context), /* 0 */ - m_handlerTable[ 1] = badResponse; // TODO new ConnectionValidationHandler(context), /* 1 */ + m_handlerTable[ 1] = new ConnectionValidationHandler(context), /* 1 */ m_handlerTable[ 2] = badResponse; // TODO new NoopResponse(context, "Echo"), /* 2 */ m_handlerTable[ 3] = badResponse; // TODO new NoopResponse(context, "Search"), /* 3 */ - m_handlerTable[ 4] = badResponse; // TODO new SearchResponseHandler(context), /* 4 */ + m_handlerTable[ 4] = new SearchResponseHandler(context), /* 4 */ m_handlerTable[ 5] = badResponse; // TODO new NoopResponse(context, "Introspection search"), /* 5 */ m_handlerTable[ 6] = dataResponse; /* 6 - introspection search */ - m_handlerTable[ 7] = badResponse; // TODO new CreateChannelHandler(context), /* 7 */ + m_handlerTable[ 7] = new CreateChannelHandler(context), /* 7 */ m_handlerTable[ 8] = badResponse; // TODO new NoopResponse(context, "Destroy channel"), /* 8 */ // TODO it might be useful to implement this... m_handlerTable[ 9] = badResponse; /* 9 */ m_handlerTable[10] = dataResponse; /* 10 - get response */ @@ -543,7 +652,7 @@ class ClientResponseHandler : public ResponseHandler, private epics::pvData::NoD hexDump(buf, (const int8*)(payloadBuffer->getArray()), payloadBuffer->getPosition(), payloadSize); return; } - + // delegate m_handlerTable[c]->handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); } @@ -566,72 +675,9 @@ class ClientResponseHandler : public ResponseHandler, private epics::pvData::NoD }; - -#include -class SearchInstance { - public: - - virtual pvAccessID getChannelID() = 0; - virtual String getChannelName() = 0; - virtual void unsetListOwnership() = 0; - virtual void addAndSetListOwnership(ArrayFIFO* newOwner, int index) = 0; - virtual void removeAndUnsetListOwnership() = 0; - virtual int getOwnerIndex() = 0; - virtual bool generateSearchRequestMessage(ByteBuffer* buffer, TransportSendControl* control) = 0; - /** - * Search response from server (channel found). - * @param minorRevision server minor CA revision. - * @param serverAddress server address. - */ - virtual void searchResponse(int8 minorRevision, osiSockAddr* serverAddress) = 0; -}; - -// TODO (only to make to make it compile) -class BaseSearchInstance : public SearchInstance -{ - public: - virtual pvAccessID getChannelID() { return 0; } - virtual String getChannelName() { return ""; } - virtual void unsetListOwnership() {} - virtual void addAndSetListOwnership(ArrayFIFO* newOwner, int index) {} - virtual void removeAndUnsetListOwnership() {} - virtual int getOwnerIndex() { return 0; } - - 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 BeaconHandlerImpl; @@ -659,10 +705,9 @@ enum ContextState { */ CONTEXT_DESTROYED }; - -class ClientContextImpl : public ClientContext, -public Context /* TODO */ + +class TestClientContextImpl : public ClientContextImpl { @@ -670,54 +715,13 @@ 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 */ -class ChannelImpl : - public Channel , - public TransportClient, - public TransportSender, - public BaseSearchInstance { +class TestChannelImpl : public ChannelImpl { private: - + /** * Context. */ @@ -727,12 +731,12 @@ class ChannelImpl : * Client channel ID. */ pvAccessID m_channelID; - + /** * Channel name. */ String m_name; - + /** * Channel requester. */ @@ -742,48 +746,48 @@ class ChannelImpl : * Process priority. */ short m_priority; - + /** * List of fixed addresses, if name resolution will be used. */ InetAddrVector* m_addresses; - + /** * Connection status. */ ConnectionState m_connectionState; - + /** - * List of all channel's pending requests (keys are subscription IDs). + * List of all channel's pending requests (keys are subscription IDs). */ IOIDResponseRequestMap m_responseRequests; - + /** - * Allow reconnection flag. + * Allow reconnection flag. */ bool m_allowCreation; - + /** * Reference counting. - * NOTE: synced on m_channelMutex. + * NOTE: synced on m_channelMutex. */ int m_references; - + /* ****************** */ - /* CA protocol fields */ + /* CA protocol fields */ /* ****************** */ - + /** * Server transport. */ Transport* m_transport; - + /** * Server channel ID. */ pvAccessID m_serverChannelID; - + /** * Context sync. mutex. */ @@ -791,20 +795,20 @@ class ChannelImpl : /** * Flag indicting what message to send. - */ + */ bool m_issueCreateMessage; - + // TODO mock PVStructure* m_pvStructure; - + private: - ~ChannelImpl() + ~TestChannelImpl() { PVDATA_REFCOUNT_MONITOR_DESTRUCT(channel); } - + public: - + /** * Constructor. * @param context @@ -812,7 +816,7 @@ class ChannelImpl : * @param listener * @throws CAException */ - ChannelImpl( + TestChannelImpl( ClientContextImpl* context, pvAccessID channelID, String name, @@ -833,34 +837,14 @@ class ChannelImpl : m_issueCreateMessage(true) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channel); - + // register before issuing search request m_context->registerChannel(this); - + // connect connect(); - - - - // - // mock - // - ScalarType stype = pvDouble; - String allProperties("alarm,timeStamp,display,control,valueAlarm"); - - m_pvStructure = getStandardPVField()->scalar( - 0,name,stype,allProperties); - PVDouble *pvField = m_pvStructure->getDoubleField(String("value")); - pvField->put(1.123); - - - // already connected, report state - m_requester->channelStateChange(this, CONNECTED); - - - } - + virtual void destroy() { if (m_addresses) delete m_addresses; @@ -872,13 +856,13 @@ class ChannelImpl : { return getChannelName(); }; - - virtual void message(String message,MessageType messageType) + + virtual void message(String message,MessageType messageType) { - std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual ChannelProvider* getProvider() + virtual ChannelProvider* getProvider() { return m_context->getProvider(); } @@ -927,10 +911,18 @@ class ChannelImpl : * Get client channel ID. * @return client channel ID. */ - pvAccessID getChannelID() const { + pvAccessID getChannelID() { return m_channelID; } + virtual pvAccessID getSearchInstanceID() { + return m_channelID; + } + + virtual String getSearchInstanceName() { + return m_name; + } + void connect() { Lock guard(&m_channelMutex); // if not destroyed... @@ -947,14 +939,14 @@ class ChannelImpl : throw std::runtime_error("Channel destroyed."); else if (m_connectionState == CONNECTED) disconnect(false, true); - } - + } + /** * Create a channel, i.e. submit create channel request to the server. * This method is called after search is complete. * @param transport */ - void createChannel(Transport* transport) + void createChannel(Transport* transport) { Lock guard(&m_channelMutex); @@ -962,12 +954,12 @@ class ChannelImpl : if (!m_allowCreation) return; m_allowCreation = false; - + // check existing transport if (m_transport && m_transport != transport) { disconnectPendingIO(false); - + ReferenceCountingTransport* rct = dynamic_cast(m_transport); if (rct) rct->release(this); } @@ -977,11 +969,11 @@ class ChannelImpl : // this happens when server is slower (processing search requests) than client generating it return; } - + m_transport = transport; m_transport->enqueueSendRequest(this); } - + virtual void cancel() { // noop } @@ -1007,7 +999,7 @@ class ChannelImpl : * sid might not be valid, this depends on protocol revision. * @param sid */ - void connectionCompleted(pvAccessID sid/*, rights*/) + virtual void connectionCompleted(pvAccessID sid/*, rights*/) { Lock guard(&m_channelMutex); @@ -1024,16 +1016,16 @@ class ChannelImpl : // user might create monitors in listeners, so this has to be done before this can happen // however, it would not be nice if events would come before connection event is fired - // but this cannot happen since transport (TCP) is serving in this thread + // but this cannot happen since transport (TCP) is serving in this thread resubscribeSubscriptions(); setConnectionState(CONNECTED); allOK = true; } catch (...) { // noop - // TODO at least log something?? + // TODO at least log something?? } - + if (!allOK) { // end connection request @@ -1048,10 +1040,10 @@ class ChannelImpl : Lock guard(&m_channelMutex); if (m_connectionState == DESTROYED) throw std::runtime_error("Channel already destroyed."); - + // do destruction via context m_context->destroyChannel(this, force); - + } /** @@ -1078,7 +1070,7 @@ class ChannelImpl : m_references--; if (m_references > 0 && !force) return; - + // stop searching... m_context->getChannelSearchManager()->unregisterChannel(this); cancel(); @@ -1098,7 +1090,7 @@ class ChannelImpl : } setConnectionState(DESTROYED); - + // unregister m_context->unregisterChannel(this); } @@ -1110,10 +1102,10 @@ class ChannelImpl : */ void disconnect(bool initiateSearch, bool remoteDestroy) { Lock guard(&m_channelMutex); - + if (m_connectionState != CONNECTED && !m_transport) return; - + if (!initiateSearch) { // stop searching... m_context->getChannelSearchManager()->unregisterChannel(this); @@ -1130,12 +1122,12 @@ class ChannelImpl : m_issueCreateMessage = false; m_transport->enqueueSendRequest(this); } - + ReferenceCountingTransport* rct = dynamic_cast(m_transport); if (rct) rct->release(this); m_transport = 0; } - + if (initiateSearch) this->initiateSearch(); @@ -1149,7 +1141,7 @@ class ChannelImpl : Lock guard(&m_channelMutex); m_allowCreation = true; - + if (!m_addresses) m_context->getChannelSearchManager()->registerChannel(this); /* TODO @@ -1167,15 +1159,14 @@ class ChannelImpl : if (transport) { // multiple defined PV or reconnect request (same server address) - // TOD !!!! if (!(*(transport->getRemoteAddress()) == *serverAddress)) - if (false) + if (sockAddrAreIdentical(transport->getRemoteAddress(), serverAddress)) { m_requester->message("More than one channel with name '" + m_name + "' detected, additional response from: " + inetAddressToString(serverAddress), warningMessage); return; } } - + transport = m_context->getTransport(this, serverAddress, minorRevision, m_priority); if (!transport) { @@ -1200,7 +1191,7 @@ class ChannelImpl : if (m_connectionState == DISCONNECTED) { updateSubscriptions(); - + // reconnect using existing IDs, data connectionCompleted(m_serverChannelID/*, accessRights*/); } @@ -1213,7 +1204,7 @@ class ChannelImpl : // NOTE: 2 types of disconnected state - distinguish them setConnectionState(DISCONNECTED); - // ... CA notifies also w/ no access rights callback, although access right are not changed + // ... CA notifies also w/ no access rights callback, although access right are not changed } } @@ -1227,7 +1218,7 @@ class ChannelImpl : if (m_connectionState != connectionState) { m_connectionState = connectionState; - + //bool connectionStatusToReport = (connectionState == CONNECTED); //if (connectionStatusToReport != lastReportedConnectionState) { @@ -1242,16 +1233,16 @@ class ChannelImpl : // noop } - + virtual void send(ByteBuffer* buffer, TransportSendControl* control) { m_channelMutex.lock(); bool issueCreateMessage = m_issueCreateMessage; m_channelMutex.unlock(); - + if (issueCreateMessage) { control->startMessage((int8)7, 2+4); - + // count buffer->putShort((int16)1); // array of CIDs and names @@ -1290,9 +1281,9 @@ class ChannelImpl : { // TODO } - + /** - * Resubscribe subscriptions. + * Resubscribe subscriptions. */ // TODO to be called from non-transport thread !!!!!! void resubscribeSubscriptions() @@ -1301,7 +1292,7 @@ class ChannelImpl : } /** - * Update subscriptions. + * Update subscriptions. */ // TODO to be called from non-transport thread !!!!!! void updateSubscriptions() @@ -1342,7 +1333,7 @@ class ChannelImpl : // TODO return 0; } - + virtual ChannelRPC* createChannelRPC(ChannelRPCRequester *channelRPCRequester, epics::pvData::PVStructure *pvRequest) { @@ -1364,20 +1355,20 @@ class ChannelImpl : // TODO return 0; } - - - + + + virtual void printInfo() { String info; printInfo(&info); std::cout << info.c_str() << std::endl; } - + virtual void printInfo(epics::pvData::StringBuilder out) { //Lock lock(&m_channelMutex); //std::ostringstream ostr; //static String emptyString; - + out->append( "CHANNEL : "); out->append(m_name); out->append("\nSTATE : "); out->append(ConnectionStateNames[m_connectionState]); if (m_connectionState == CONNECTED) @@ -1388,72 +1379,72 @@ class ChannelImpl : out->append("\n"); } }; - + class ChannelProviderImpl; - + class ChannelImplFind : public ChannelFind { public: ChannelImplFind(ChannelProvider* provider) : m_provider(provider) { } - + virtual void destroy() { // one instance for all, do not delete at all } - + virtual ChannelProvider* getChannelProvider() { return m_provider; }; - + virtual void cancelChannelFind() { throw std::runtime_error("not supported"); } - + private: - + // only to be destroyed by it friend class ChannelProviderImpl; virtual ~ChannelImplFind() {} - - ChannelProvider* m_provider; + + ChannelProvider* m_provider; }; - + class ChannelProviderImpl : public ChannelProvider { public: - + ChannelProviderImpl(ClientContextImpl* context) : m_context(context) { } - + virtual epics::pvData::String getProviderName() { return "ChannelProviderImpl"; } - + virtual void destroy() { delete this; } - + virtual ChannelFind* channelFind( epics::pvData::String channelName, ChannelFindRequester *channelFindRequester) { m_context->checkChannelName(channelName); - + if (!channelFindRequester) throw std::runtime_error("null requester"); - + std::auto_ptr errorStatus(getStatusCreate()->createStatus(STATUSTYPE_ERROR, "not implemented", 0)); channelFindRequester->channelFindResult(errorStatus.get(), 0, false); return 0; } - + virtual Channel* createChannel( epics::pvData::String channelName, ChannelRequester *channelRequester, @@ -1461,7 +1452,7 @@ class ChannelImpl : { return createChannel(channelName, channelRequester, priority, emptyString); } - + virtual Channel* createChannel( epics::pvData::String channelName, ChannelRequester *channelRequester, @@ -1473,31 +1464,34 @@ class ChannelImpl : if (channel) channelRequester->channelCreated(getStatusCreate()->getStatusOK(), channel); return channel; - + // NOTE it's up to internal code to respond w/ error to requester and return 0 in case of errors } - + private: ~ChannelProviderImpl() {}; - + /* TODO static*/ String emptyString; ClientContextImpl* m_context; }; public: - - ClientContextImpl() : + TestClientContextImpl() : m_addressList(""), m_autoAddressList(true), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), m_broadcastPort(CA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), m_timer(0), m_broadcastTransport(0), m_searchTransport(0), m_connector(0), m_transportRegistry(0), m_namedLocker(0), m_lastCID(0), m_lastIOID(0), m_channelSearchManager(0), m_version(new Version("CA Client", "cpp", 0, 0, 0, 1)), m_provider(new ChannelProviderImpl(this)), - m_contextState(CONTEXT_NOT_INITIALIZED) + m_contextState(CONTEXT_NOT_INITIALIZED), m_configuration(new SystemConfigurationImpl()) { loadConfiguration(); } - + + virtual Configuration* getConfiguration() { + return m_configuration; + } + virtual Version* getVersion() { return m_version; } @@ -1527,28 +1521,28 @@ class ChannelImpl : virtual void initialize() { Lock lock(&m_contextMutex); - + if (m_contextState == CONTEXT_DESTROYED) throw std::runtime_error("Context destroyed."); else if (m_contextState == CONTEXT_INITIALIZED) throw std::runtime_error("Context already initialized."); - + internalInitialize(); m_contextState = CONTEXT_INITIALIZED; } - + virtual void printInfo() { String info; printInfo(&info); std::cout << info.c_str() << std::endl; } - + virtual void printInfo(epics::pvData::StringBuilder out) { Lock lock(&m_contextMutex); std::ostringstream ostr; static String emptyString; - + out->append( "CLASS : ::epics::pvAccess::ClientContextImpl"); out->append("\nVERSION : "); out->append(m_version->getVersionString()); out->append("\nADDR_LIST : "); ostr << m_addressList; out->append(ostr.str()); ostr.str(emptyString); @@ -1574,7 +1568,7 @@ class ChannelImpl : } out->append("\n"); } - + virtual void destroy() { m_contextMutex.lock(); @@ -1584,21 +1578,21 @@ class ChannelImpl : m_contextMutex.unlock(); throw std::runtime_error("Context already destroyed."); } - - // go into destroyed state ASAP + + // go into destroyed state ASAP m_contextState = CONTEXT_DESTROYED; internalDestroy(); } - + virtual void dispose() { destroy(); - } - + } + private: - ~ClientContextImpl() {}; - + ~TestClientContextImpl() {}; + void loadConfiguration() { // TODO /* @@ -1612,19 +1606,19 @@ class ChannelImpl : } void internalInitialize() { - + m_timer = new Timer("pvAccess-client timer", lowPriority); m_connector = new BlockingTCPConnector(this, m_receiveBufferSize, m_beaconPeriod); m_transportRegistry = new TransportRegistry(); m_namedLocker = new NamedLockPattern(); - + // setup UDP transport initializeUDPTransport(); // setup search manager m_channelSearchManager = new ChannelSearchManager(this); } - + /** * Initialized UDP transport (broadcast socket and repeater connection). */ @@ -1637,28 +1631,34 @@ class ChannelImpl : 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) + SOCKET socket = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); + InetAddrVector* broadcastAddresses = getBroadcastAddresses(socket, m_broadcastPort); + cout<<"Broadcast addresses: "<size()<size(); i++) { + cout<<"Broadcast address: "; + cout<at(i))<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, @@ -1671,7 +1671,7 @@ class ChannelImpl : InetAddrVector* appendList = 0; if (m_autoAddressList) appendList = m_broadcastTransport->getSendAddresses(); - + InetAddrVector* list = getSocketAddressList(m_addressList, m_broadcastPort, appendList); // TODO delete !!!! if (list && list->size()) { @@ -1689,40 +1689,41 @@ class ChannelImpl : // TODO } } - + void internalDestroy() { - + // stop searching if (m_channelSearchManager) delete m_channelSearchManager; //->destroy(); - + // stop timer - if (m_timer) + if (m_timer) delete m_timer; // // cleanup // - + // this will also close all CA transports destroyAllChannels(); - + // TODO destroy !!! if (m_broadcastTransport) 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; + if (m_configuration) delete m_configuration; m_provider->destroy(); delete m_version; m_contextMutex.unlock(); delete this; } - + void destroyAllChannels() { // TODO } @@ -1777,18 +1778,18 @@ class ChannelImpl : ChannelImpl* getChannel(pvAccessID channelID) { Lock guard(&m_cidMapMutex); - CIDChannelMap::iterator it = m_channelsByCID.find(channelID); + CIDChannelMap::iterator it = m_channelsByCID.find(channelID); return (it == m_channelsByCID.end() ? 0 : it->second); } /** * Generate Client channel ID (CID). - * @return Client channel ID (CID). + * @return Client channel ID (CID). */ pvAccessID generateCID() { Lock guard(&m_cidMapMutex); - + // search first free (theoretically possible loop of death) while (m_channelsByCID.find(++m_lastCID) != m_channelsByCID.end()); // reserve CID @@ -1805,7 +1806,7 @@ class ChannelImpl : m_channelsByCID.erase(cid); } - + /** * Get, or create if necessary, transport of given server address. * @param serverAddress required transport address @@ -1814,54 +1815,51 @@ class ChannelImpl : */ Transport* getTransport(TransportClient* client, osiSockAddr* serverAddress, int16 minorRevision, int16 priority) { - // TODO !!! - /* try { - return connector->connect(client, new ClientResponseHandler(this), serverAddress, minorRevision, priority); + return m_connector->connect(client, new ClientResponseHandler(this), *serverAddress, minorRevision, priority); } - catch (ConnectionException cex) + catch (...) { - logger.log(Level.SEVERE, "Failed to create transport for: " + serverAddress, cex); + // TODO log + printf("failed to get transport\n"); + return 0; } - */ - return 0; - } - + /** * Internal create channel. */ // TODO no minor version with the addresses // TODO what if there is an channel with the same name, but on different host! - Channel* createChannelInternal(String name, ChannelRequester* requester, short priority, + ChannelImpl* createChannelInternal(String name, ChannelRequester* requester, short priority, InetAddrVector* addresses) { // TODO addresses checkState(); checkChannelName(name); - + if (requester == 0) throw std::runtime_error("null requester"); - + if (priority < ChannelProvider::PRIORITY_MIN || priority > ChannelProvider::PRIORITY_MAX) throw std::range_error("priority out of bounds"); bool lockAcquired = true; // TODO namedLocker->acquireSynchronizationObject(name, LOCK_TIMEOUT); if (lockAcquired) - { + { try { pvAccessID cid = generateCID(); - return new ChannelImpl(this, cid, name, requester, priority, addresses); + return new TestChannelImpl(this, cid, name, requester, priority, addresses); } catch(...) { // TODO return 0; } - // TODO namedLocker.releaseSynchronizationObject(name); + // TODO namedLocker.releaseSynchronizationObject(name); } else - { + { // TODO is this OK? throw std::runtime_error("Failed to obtain synchronization lock for '" + name + "', possible deadlock."); } @@ -1875,23 +1873,23 @@ class ChannelImpl : * @throws IllegalStateException */ void destroyChannel(ChannelImpl* channel, bool force) { - + String name = channel->getChannelName(); bool lockAcquired = true; //namedLocker->acquireSynchronizationObject(name, LOCK_TIMEOUT); if (lockAcquired) - { + { try - { + { channel->destroyChannel(force); } catch(...) { // TODO } - // TODO namedLocker->releaseSynchronizationObject(channel.getChannelName()); + // TODO namedLocker->releaseSynchronizationObject(channel.getChannelName()); } else - { - // TODO is this OK? + { + // TODO is this OK? throw std::runtime_error("Failed to obtain synchronization lock for '" + name + "', possible deadlock."); } } @@ -1903,15 +1901,15 @@ class ChannelImpl : ChannelSearchManager* getChannelSearchManager() { return m_channelSearchManager; } - + /** * A space-separated list of broadcast address for process variable name resolution. * Each address must be of the form: ip.number:port or host.name:port */ String m_addressList; - + /** - * Define whether or not the network interfaces should be discovered at runtime. + * Define whether or not the network interfaces should be discovered at runtime. */ bool m_autoAddressList; @@ -1922,22 +1920,22 @@ class ChannelImpl : * the server is no longer present on the network and disconnect. */ float m_connectionTimeout; - + /** * Period in second between two beacon signals. */ float m_beaconPeriod; - + /** * Broadcast (beacon, search) port number to listen to. */ int m_broadcastPort; - + /** * Receive buffer size (max size of payload). */ int m_receiveBufferSize; - + /** * Timer. */ @@ -1947,7 +1945,7 @@ class ChannelImpl : * Broadcast transport needed to listen for broadcasts. */ BlockingUDPTransport* m_broadcastTransport; - + /** * UDP transport needed for channel searches. */ @@ -1960,7 +1958,7 @@ class ChannelImpl : /** * CA transport (virtual circuit) registry. - * This registry contains all active transports - connections to CA servers. + * This registry contains all active transports - connections to CA servers. */ TransportRegistry* m_transportRegistry; @@ -1987,7 +1985,7 @@ class ChannelImpl : Mutex m_cidMapMutex; /** - * Last CID cache. + * Last CID cache. */ pvAccessID m_lastCID; @@ -1999,7 +1997,7 @@ class ChannelImpl : IOIDResponseRequestMap m_pendingResponseRequests; /** - * Last IOID cache. + * Last IOID cache. */ pvAccessID m_lastIOID; @@ -2013,9 +2011,9 @@ class ChannelImpl : * Beacon handler map. */ // TODO consider std::unordered_map - typedef std::map AddressBeaconHandlerMap; - AddressBeaconHandlerMap m_beaconHandlers; - +// typedef std::map AddressBeaconHandlerMap; +// AddressBeaconHandlerMap m_beaconHandlers; + /** * Version. */ @@ -2025,18 +2023,20 @@ class ChannelImpl : * Provider implementation. */ ChannelProviderImpl* m_provider; - + /** * Context state. */ ContextState m_contextState; - + /** * Context sync. mutex. */ Mutex m_contextMutex; friend class ChannelProviderImpl; + + Configuration* m_configuration; }; @@ -2045,7 +2045,7 @@ class ChannelFindRequesterImpl : public ChannelFindRequester virtual void channelFindResult(epics::pvData::Status *status,ChannelFind *channelFind,bool wasFound) { std::cout << "[ChannelFindRequesterImpl] channelFindResult(" - << status->toString() << ", ..., " << wasFound << ")" << std::endl; + << status->toString() << ", ..., " << wasFound << ")" << std::endl; } }; @@ -2055,10 +2055,10 @@ class ChannelRequesterImpl : public ChannelRequester { return "ChannelRequesterImpl"; }; - - virtual void message(String message,MessageType messageType) + + virtual void message(String message,MessageType messageType) { - std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } virtual void channelCreated(epics::pvData::Status* status, Channel *channel) @@ -2066,7 +2066,7 @@ class ChannelRequesterImpl : public ChannelRequester std::cout << "channelCreated(" << status->toString() << ", " << (channel ? channel->getChannelName() : "(null)") << ")" << std::endl; } - + virtual void channelStateChange(Channel *c, ConnectionState connectionState) { std::cout << "channelStateChange(" << c->getChannelName() << ", " << ConnectionStateNames[connectionState] << ")" << std::endl; @@ -2079,10 +2079,10 @@ class GetFieldRequesterImpl : public GetFieldRequester { return "GetFieldRequesterImpl"; }; - - virtual void message(String message,MessageType messageType) + + virtual void message(String message,MessageType messageType) { - std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } virtual void getDone(epics::pvData::Status *status,epics::pvData::FieldConstPtr field) @@ -2105,22 +2105,22 @@ class ChannelGetRequesterImpl : public ChannelGetRequester ChannelGet *m_channelGet; epics::pvData::PVStructure *m_pvStructure; epics::pvData::BitSet *m_bitSet; - + virtual String getRequesterName() { return "ChannelGetRequesterImpl"; }; - - virtual void message(String message,MessageType messageType) + + virtual void message(String message,MessageType messageType) { - std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } virtual void channelGetConnect(epics::pvData::Status *status,ChannelGet *channelGet, epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) { std::cout << "channelGetConnect(" << status->toString() << ")" << std::endl; - + // TODO sync m_channelGet = channelGet; m_pvStructure = pvStructure; @@ -2142,22 +2142,22 @@ class ChannelPutRequesterImpl : public ChannelPutRequester ChannelPut *m_channelPut; epics::pvData::PVStructure *m_pvStructure; epics::pvData::BitSet *m_bitSet; - + virtual String getRequesterName() { return "ChannelPutRequesterImpl"; }; - - virtual void message(String message,MessageType messageType) + + virtual void message(String message,MessageType messageType) { - std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } virtual void channelPutConnect(epics::pvData::Status *status,ChannelPut *channelPut, epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) { std::cout << "channelPutConnect(" << status->toString() << ")" << std::endl; - + // TODO sync m_channelPut = channelPut; m_pvStructure = pvStructure; @@ -2183,20 +2183,20 @@ class ChannelPutRequesterImpl : public ChannelPutRequester } }; - - + + class MonitorRequesterImpl : public MonitorRequester { virtual String getRequesterName() { return "MonitorRequesterImpl"; }; - - virtual void message(String message,MessageType messageType) + + virtual void message(String message,MessageType messageType) { - std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - + virtual void monitorConnect(Status* status, Monitor* monitor, Structure* structure) { std::cout << "monitorConnect(" << status->toString() << ")" << std::endl; @@ -2207,13 +2207,13 @@ class MonitorRequesterImpl : public MonitorRequester std::cout << str << std::endl; } } - + virtual void monitorEvent(Monitor* monitor) { std::cout << "monitorEvent" << std::endl; MonitorElement* element = monitor->poll(); - + String str("changed/overrun "); element->getChangedBitSet()->toString(&str); str += '/'; @@ -2221,35 +2221,35 @@ class MonitorRequesterImpl : public MonitorRequester str += '\n'; element->getPVStructure()->toString(&str); std::cout << str << std::endl; - + monitor->release(element); } - + virtual void unlisten(Monitor* monitor) { std::cout << "unlisten" << std::endl; } -}; +}; class ChannelProcessRequesterImpl : public ChannelProcessRequester { ChannelProcess *m_channelProcess; - + virtual String getRequesterName() { return "ProcessRequesterImpl"; }; - - virtual void message(String message,MessageType messageType) + + virtual void message(String message,MessageType messageType) { - std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } virtual void channelProcessConnect(epics::pvData::Status *status,ChannelProcess *channelProcess) { std::cout << "channelProcessConnect(" << status->toString() << ")" << std::endl; - + // TODO sync m_channelProcess = channelProcess; } @@ -2263,36 +2263,36 @@ class ChannelProcessRequesterImpl : public ChannelProcessRequester int main(int argc,char *argv[]) { - ClientContextImpl* context = new ClientContextImpl(); + TestClientContextImpl* context = new TestClientContextImpl(); context->printInfo(); - context->initialize(); + context->initialize(); context->printInfo(); - + epicsThreadSleep ( 1.0 ); - + //ChannelFindRequesterImpl findRequester; //context->getProvider()->channelFind("something", &findRequester); - + ChannelRequesterImpl channelRequester; Channel* channel = context->getProvider()->createChannel("structureArrayTest", &channelRequester); channel->printInfo(); /* GetFieldRequesterImpl getFieldRequesterImpl; channel->getField(&getFieldRequesterImpl, "timeStamp.secondsPastEpoch"); - + ChannelGetRequesterImpl channelGetRequesterImpl; ChannelGet* channelGet = channel->createChannelGet(&channelGetRequesterImpl, 0); channelGet->get(false); channelGet->destroy(); - + ChannelPutRequesterImpl channelPutRequesterImpl; ChannelPut* channelPut = channel->createChannelPut(&channelPutRequesterImpl, 0); channelPut->get(); channelPut->put(false); channelPut->destroy(); - - + + MonitorRequesterImpl monitorRequesterImpl; Monitor* monitor = channel->createMonitor(&monitorRequesterImpl, 0); @@ -2305,20 +2305,20 @@ int main(int argc,char *argv[]) ChannelProcess* channelProcess = channel->createChannelProcess(&channelProcessRequester, 0); channelProcess->process(false); channelProcess->destroy(); - + status = monitor->stop(); std::cout << "monitor->stop() = " << status->toString() << std::endl; delete status; - - + + monitor->destroy(); */ - epicsThreadSleep ( 10.0 ); + epicsThreadSleep ( 100.0 ); channel->destroy(); - + context->destroy(); - + std::cout << "-----------------------------------------------------------------------" << std::endl; getShowConstructDestruct()->constuctDestructTotals(stdout); return(0); diff --git a/testApp/utils/arrayFIFOTest.cpp b/testApp/utils/arrayFIFOTest.cpp index 61cbfc7..966d2c1 100644 --- a/testApp/utils/arrayFIFOTest.cpp +++ b/testApp/utils/arrayFIFOTest.cpp @@ -15,7 +15,9 @@ using namespace epics::pvAccess; using std::cout; using std::endl; -int main(int argc, char *argv[]) { +void testSimpleType() { + cout<<"\nTests for simple type template."< fifoInt; assert(fifoInt.size()==0); @@ -133,5 +135,137 @@ int main(int argc, char *argv[]) { assert(fifoInt.isEmpty()); cout<<"\nPASSED!\n"; +} + +void testPointerType() { + cout<<"\nTests for pointer type template."< fifoInt; + + assert(fifoInt.size()==0); + assert(fifoInt.isEmpty()); + + cout<<"Testing clear."< cb(CAPACITY); - cout<<"Testing circular buffer."< cb(CAPACITY); + int testVals[] = {0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20}; + + cout<<"Testing circular buffer pointer type."< #include @@ -23,6 +24,7 @@ using std::stringstream; using std::hex; int main(int argc, char *argv[]) { + createFileLogger("inetAddresUtils.log"); InetAddrVector *vec; InetAddrVector *vec1; @@ -127,11 +129,11 @@ int main(int argc, char *argv[]) { cout<<"\nPASSED!\n"; SOCKET socket = epicsSocketCreate(AF_INET, SOCK_STREAM, IPPROTO_TCP); - InetAddrVector* broadcasts = getBroadcastAddresses(socket); + InetAddrVector* broadcasts = getBroadcastAddresses(socket,6678); cout<<"Broadcast addresses: "<size()<size(); i++) { cout<<"Broadcast address: "; - cout<at(i), false)<at(i))<