From 2f5f6328db51cd3c3a1b091b5b624245df0823b0 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Wed, 26 Mar 2014 21:20:26 +0100 Subject: [PATCH 01/32] flow: Created branch 'feature/changesAfter3_0_2'. From 44053463843431aaafa33828fd05549fb0277bd7 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Tue, 1 Apr 2014 09:58:38 -0400 Subject: [PATCH 02/32] moved CreateRequest to pvDataCPP --- pvAccessApp/Makefile | 1 - pvAccessApp/client/pvAccess.h | 31 +------ testApp/client/Makefile | 4 - testApp/client/testCreateRequest.cpp | 132 --------------------------- 4 files changed, 1 insertion(+), 167 deletions(-) delete mode 100644 testApp/client/testCreateRequest.cpp diff --git a/pvAccessApp/Makefile b/pvAccessApp/Makefile index 405c85a..87564d5 100644 --- a/pvAccessApp/Makefile +++ b/pvAccessApp/Makefile @@ -34,7 +34,6 @@ LIBSRCS += pvAccess.cpp SRC_DIRS += $(PVACCESS)/factory LIBSRCS += ChannelAccessFactory.cpp -LIBSRCS += CreateRequestFactory.cpp SRC_DIRS += $(PVACCESS)/remote INC += remote.h diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index 64b6370..cabd16e 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -15,6 +15,7 @@ #endif #include +#include #include #include #include @@ -802,36 +803,6 @@ namespace pvAccess { epicsShareExtern void registerChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory); epicsShareExtern void unregisterChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory); - /** - * Interface for creating request structure. - */ - class epicsShareClass CreateRequest { - public: - POINTER_DEFINITIONS(CreateRequest); - static CreateRequest::shared_pointer create(); - virtual ~CreateRequest() {}; - - /** - * Create a request structure for the create calls in Channel. - * See the package overview documentation for details. - * @param request The field request. See the package overview documentation for details. - * @param requester The requester; - * @return The request PVStructure if a valid request was given. - * If a NULL PVStructure is returned then getMessage will return - * the reason. - */ - virtual epics::pvData::PVStructure::shared_pointer createRequest( - epics::pvData::String const & request) = 0; - /** - * Get the error message of createRequest returns NULL; - * @return the error message - */ - epics::pvData::String getMessage() {return message;} - protected: - CreateRequest() {} - epics::pvData::String message; - - }; }} diff --git a/testApp/client/Makefile b/testApp/client/Makefile index cefa61e..c43d419 100644 --- a/testApp/client/Makefile +++ b/testApp/client/Makefile @@ -6,10 +6,6 @@ include $(TOP)/configure/CONFIG testChannelAccessFactory_SRCS = testChannelAccessFactory.cpp testChannelAccessFactory_LIBS = pvAccess pvData Com -PROD_HOST += testCreateRequest -testCreateRequest_SRCS = testCreateRequest.cpp -testCreateRequest_LIBS = pvAccess pvData pvMB Com - #PROD_HOST += testMockClient testMockClient_SRCS = testMockClient.cpp MockClientImpl.cpp testMockClient_LIBS = pvAccess pvData Com diff --git a/testApp/client/testCreateRequest.cpp b/testApp/client/testCreateRequest.cpp deleted file mode 100644 index f3b2a6e..0000000 --- a/testApp/client/testCreateRequest.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* testCreateRequest.cpp */ -/* Author: Matej Sekoranja Date: 2010.12.27 */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace epics::pvData; -using namespace epics::pvAccess; - - -void testCreateRequest() { - printf("testCreateRequest... \n"); - CreateRequest::shared_pointer createRequest = CreateRequest::create(); - - String out; - String request = ""; - std::cout << std::endl << String("request") <createRequest(request); - assert(pvRequest.get()); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - -request = "record[process=true] field(alarm , timeStamp) putField( synput:a,synput:b,stnput:c)"; - std::cout << std::endl << String("request") <createRequest(request); -assert(pvRequest.get()); -out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - - - request = "alarm,timeStamp,power.value"; - std::cout << std::endl << String("request") <createRequest(request); - assert(pvRequest.get()); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - - request = "record[process=true]field(alarm,timeStamp,power.value)"; - std::cout << std::endl << String("request") <createRequest(request); - assert(pvRequest.get()); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - - request = "record[process=true]field(alarm,timeStamp[algorithm=onChange,causeMonitor=false],power{value,alarm})"; - std::cout << String("request") <createRequest(request); - assert(pvRequest.get()); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - - request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value)"; - std::cout << String("request") <createRequest(request); - assert(pvRequest.get()); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - - request = String("record[process=true,xxx=yyy]") - + "putField(power.value)" - + "getField(alarm,timeStamp,power{value,alarm}," - + "current{value,alarm},voltage{value,alarm})"; - std::cout << String("request") <createRequest(request); - assert(pvRequest.get()); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - - request = String("field(alarm,timeStamp,supply{") - + "0{voltage.value,current.value,power.value}," - + "1{voltage.value,current.value,power.value}" - + "})"; - std::cout << String("request") <createRequest(request); - assert(pvRequest.get()); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - - request = String("record[process=true,xxx=yyy]") - + "putField(power.value)" - + "getField(alarm,timeStamp,power{value,alarm}," - + "current{value,alarm},voltage{value,alarm}," - + "ps0{alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm}}," - + "ps1{alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm}}" - + ")"; - std::cout << String("request") <createRequest(request); - assert(pvRequest.get()); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - - request = "a{b{c{d}}}"; - std::cout << String("request") <createRequest(request); - assert(pvRequest.get()); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - - request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value"; - std::cout << String("request") <createRequest(request); - assert(pvRequest.get()==NULL); - std::cout << "reason " << createRequest->getMessage() << std::endl; - request = String("record[process=true,xxx=yyy]") - + "putField(power.value)" - + "getField(alarm,timeStamp,power{value,alarm}," - + "current{value,alarm},voltage{value,alarm}," - + "ps0{alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm}}," - + "ps1{alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm}" - + ")"; - std::cout << String("request") <createRequest(request); - assert(pvRequest.get()==NULL); - std::cout << "reason " << createRequest->getMessage() << std::endl; - request = "record[process=true,power.value"; - std::cout << String("request") <createRequest(request); - assert(pvRequest.get()==NULL); - std::cout << "reason " << createRequest->getMessage() << std::endl; -} - -int main() -{ - testCreateRequest(); - - //std::cout << "-----------------------------------------------------------------------" << std::endl; - //epicsExitCallAtExits(); - return 0; -} - - From d2fb05ddd8eaa7a99f2289b6087406e8362d9466 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Fri, 4 Apr 2014 12:36:11 +0200 Subject: [PATCH 03/32] ChannelArray int to size_t --- pvAccessApp/client/pvAccess.h | 14 ++++++------ .../remoteClient/clientContextImpl.cpp | 19 ++++++++-------- pvAccessApp/server/responseHandlers.cpp | 10 ++++----- pvAccessCPP.files | 3 +++ testApp/remote/channelAccessIFTest.cpp | 15 +++++++------ testApp/remote/syncTestRequesters.h | 6 ++--- testApp/remote/testRemoteClientImpl.cpp | 4 ++-- testApp/remote/testServer.cpp | 22 +++++++++---------- 8 files changed, 47 insertions(+), 46 deletions(-) diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index cabd16e..7f59f9b 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -128,25 +128,25 @@ namespace pvAccess { * put to the remote array. * @param lastRequest Is this the last request. * @param offset The offset in the remote array, i.e. the PVArray returned by ChannelArrayRequester.channelArrayConnect. - * @param count The number of elements to put. + * @param count The number of elements to put, 0 means "enture array". */ - virtual void putArray(bool lastRequest, int offset, int count) = 0; + virtual void putArray(bool lastRequest, size_t offset = 0, size_t count = 0) = 0; /** * get from the remote array. * @param lastRequest Is this the last request. * @param offset The offset in the remote array, i.e. the PVArray returned by ChannelArrayRequester.channelArrayConnect. - * @param count The number of elements to get. + * @param count The number of elements to get, 0 means "till the end of an array". */ - virtual void getArray(bool lastRequest, int offset, int count) = 0; + virtual void getArray(bool lastRequest, size_t offset = 0, size_t count = 0) = 0; /** * Set the length and/or the capacity. * @param lastRequest Is this the last request. - * @param length The new length. -1 means do not change. - * @param capacity The new capacity. -1 means do not change. + * @param length The new length. + * @param capacity The new capacity, 0 means do "do not change the capacity". */ - virtual void setLength(bool lastRequest, int length, int capacity) = 0; + virtual void setLength(bool lastRequest, size_t length, size_t capacity = 0) = 0; }; /** diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index 9a162cb..c9cf0ee 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -1388,12 +1388,11 @@ namespace epics { PVArray::shared_pointer m_structure; - // TODO revise int32 !!! - int32 m_offset; - int32 m_count; + size_t m_offset; + size_t m_count; - int32 m_length; - int32 m_capacity; + size_t m_length; + size_t m_capacity; Mutex m_structureMutex; @@ -1402,7 +1401,7 @@ namespace epics { m_channelArrayRequester(channelArrayRequester), m_pvRequest(pvRequest), m_offset(0), m_count(0), - m_length(-1), m_capacity(-1) + m_length(0), m_capacity(0) { PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelArray); } @@ -1478,7 +1477,7 @@ namespace epics { // no need to lock here, since it is already locked via TransportSender IF //Lock lock(m_structureMutex); SerializeHelper::writeSize(m_offset, buffer, control); - m_structure->serialize(buffer, control, 0, m_count); // put from 0 offset; TODO count out-of-bounds check?! + m_structure->serialize(buffer, control, 0, m_count ? m_count : m_structure->getLength()); // put from 0 offset (see API doc), m_count == 0 means entire array } } @@ -1543,7 +1542,7 @@ namespace epics { } - virtual void getArray(bool lastRequest, int offset, int count) { + virtual void getArray(bool lastRequest, size_t offset, size_t count) { { Lock guard(m_mutex); @@ -1575,7 +1574,7 @@ namespace epics { } } - virtual void putArray(bool lastRequest, int offset, int count) { + virtual void putArray(bool lastRequest, size_t offset, size_t count) { { Lock guard(m_mutex); @@ -1607,7 +1606,7 @@ namespace epics { } } - virtual void setLength(bool lastRequest, int length, int capacity) { + virtual void setLength(bool lastRequest, size_t length, size_t capacity) { { Lock guard(m_mutex); diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index 9e20e9e..a1699e0 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -1481,20 +1481,20 @@ void ServerArrayHandler::handleResponse(osiSockAddr* responseFrom, if (get) { - const int32 offset = SerializeHelper::readSize(payloadBuffer, transport.get()); - const int32 count = SerializeHelper::readSize(payloadBuffer, transport.get()); + size_t offset = SerializeHelper::readSize(payloadBuffer, transport.get()); + size_t count = SerializeHelper::readSize(payloadBuffer, transport.get()); request->getChannelArray()->getArray(lastRequest, offset, count); } else if (setLength) { - const int32 length = SerializeHelper::readSize(payloadBuffer, transport.get()); - const int32 capacity = SerializeHelper::readSize(payloadBuffer, transport.get()); + size_t length = SerializeHelper::readSize(payloadBuffer, transport.get()); + size_t capacity = SerializeHelper::readSize(payloadBuffer, transport.get()); request->getChannelArray()->setLength(lastRequest, length, capacity); } else { // deserialize data to put - int32 offset; + size_t offset; ChannelArray::shared_pointer channelArray = request->getChannelArray(); PVArray::shared_pointer array = request->getPVArray(); { diff --git a/pvAccessCPP.files b/pvAccessCPP.files index a0e4c1e..7a38550 100644 --- a/pvAccessCPP.files +++ b/pvAccessCPP.files @@ -121,3 +121,6 @@ pvAccessApp/ca/caProvider.cpp pvAccessApp/ca/caChannel.h pvAccessApp/ca/caChannel.cpp testApp/utils/Makefile +testApp/remote/channelAccessIFTest.h +testApp/remote/channelAccessIFTest.cpp +testApp/remote/syncTestRequesters.h diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index cdd1307..492bbb9 100755 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -1754,13 +1754,13 @@ void ChannelAccessIFTest::test_channelArray() { array->replace(freeze(newdata)); - succStatus = arrayReq->syncPut(false, 0, -1, getTimeoutSec()); + succStatus = arrayReq->syncPut(false, 0, 0, getTimeoutSec()); if (!succStatus) { testFail("%s: an array syncPut failed (2) ", CURRENT_FUNCTION); return; } - succStatus = arrayReq->syncGet(false, 0, -1, getTimeoutSec()); + succStatus = arrayReq->syncGet(false, 0, 0, getTimeoutSec()); if (!succStatus) { testFail("%s: an array syncGet failed (3) ", CURRENT_FUNCTION); return; @@ -1800,13 +1800,13 @@ void ChannelAccessIFTest::test_channelArray() { //testOk(data1[2] == 2.2 , "%s: check 2: %f", CURRENT_FUNCTION, data1[2]); - succStatus = arrayReq->syncSetLength(false, 3, -1, getTimeoutSec()); + succStatus = arrayReq->syncSetLength(false, 3, 0, getTimeoutSec()); if (!succStatus) { testFail("%s: an array setLength failed ", CURRENT_FUNCTION); return; } - succStatus = arrayReq->syncGet(false, 0, -1, getTimeoutSec()); + succStatus = arrayReq->syncGet(false, 0, 0, getTimeoutSec()); if (!succStatus) { testFail("%s: an array syncGet failed (7) ", CURRENT_FUNCTION); return; @@ -1821,14 +1821,15 @@ void ChannelAccessIFTest::test_channelArray() { testOk(data2[1] == 2.2 , "%s: 2.check 1: %f", CURRENT_FUNCTION, data2[1]); testOk(data2[2] == 3.3, "%s: 2.check 2: %f", CURRENT_FUNCTION, data2[2]); + size_t currentLength = 3; size_t newCap = 2; - succStatus = arrayReq->syncSetLength(false, -1, newCap, getTimeoutSec()); + succStatus = arrayReq->syncSetLength(false, currentLength, newCap, getTimeoutSec()); if (!succStatus) { testFail("%s: an array setLength failed (2) ", CURRENT_FUNCTION); return; } - succStatus = arrayReq->syncGet(false, 0, -1, getTimeoutSec()); + succStatus = arrayReq->syncGet(false, 0, 0, getTimeoutSec()); if (!succStatus) { testFail("%s: an array syncGet failed (8) ", CURRENT_FUNCTION); return; @@ -1850,7 +1851,7 @@ void ChannelAccessIFTest::test_channelArray() { return; } - succStatus = arrayReq->syncGet(false, 0, -1, getTimeoutSec()); + succStatus = arrayReq->syncGet(false, 0, 0, getTimeoutSec()); if (!succStatus) { testFail("%s: an array syncGet failed (9) ", CURRENT_FUNCTION); return; diff --git a/testApp/remote/syncTestRequesters.h b/testApp/remote/syncTestRequesters.h index 705d01d..d100e03 100755 --- a/testApp/remote/syncTestRequesters.h +++ b/testApp/remote/syncTestRequesters.h @@ -1134,7 +1134,7 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB m_lengthArrayStatus(false) {} - bool syncPut(bool lastRequest, int offset, int count, long timeOut) + bool syncPut(bool lastRequest, size_t offset, size_t count, long timeOut) { if (!getConnectedStatus()) { @@ -1146,7 +1146,7 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB } - bool syncGet(bool lastRequest, int offset, int count, long timeOut) + bool syncGet(bool lastRequest, size_t offset, size_t count, long timeOut) { if (!getConnectedStatus()) { @@ -1158,7 +1158,7 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB } - bool syncSetLength(bool lastRequest, int length, int capacity, long timeOut) + bool syncSetLength(bool lastRequest, size_t length, size_t capacity, long timeOut) { if (!getConnectedStatus()) { diff --git a/testApp/remote/testRemoteClientImpl.cpp b/testApp/remote/testRemoteClientImpl.cpp index 6161fd9..0d0c8ab 100644 --- a/testApp/remote/testRemoteClientImpl.cpp +++ b/testApp/remote/testRemoteClientImpl.cpp @@ -539,9 +539,9 @@ int main() ChannelArray::shared_pointer channelArray = channel->createChannelArray(channelArrayRequesterImpl, pvRequest); epicsThreadSleep ( 1.0 ); - channelArray->getArray(false,0,-1); + channelArray->getArray(false,0,0); epicsThreadSleep ( 1.0 ); - channelArray->putArray(false,0,-1); + channelArray->putArray(false,0,0); epicsThreadSleep ( 1.0 ); channelArray->setLength(false,3,4); epicsThreadSleep ( 1.0 ); diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index 75ab021..a70f593 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -1693,11 +1693,11 @@ public: to->replace(freeze(temp)); } - virtual void putArray(bool lastRequest, int offset, int count) + virtual void putArray(bool lastRequest, size_t offset, size_t count) { - size_t o = static_cast(offset); - if (count == -1) count = static_cast(m_pvArray->getLength()); - size_t c = static_cast(count); + size_t o = offset; + if (count == 0) count = m_pvArray->getLength(); + size_t c = count; Field::const_shared_pointer field = m_pvArray->getField(); Type type = field->getType(); @@ -1745,11 +1745,11 @@ public: } - virtual void getArray(bool lastRequest, int offset, int count) + virtual void getArray(bool lastRequest, size_t offset, size_t count) { - size_t o = static_cast(offset); - if (count == -1) count = static_cast(m_pvStructureArray->getLength()); - size_t c = static_cast(count); + size_t o = offset; + if (count == 0) count = m_pvStructureArray->getLength(); + size_t c = count; Field::const_shared_pointer field = m_pvArray->getField(); Type type = field->getType(); @@ -1781,15 +1781,13 @@ public: destroy(); } - virtual void setLength(bool lastRequest, int length, int capacity) + virtual void setLength(bool lastRequest, size_t length, size_t capacity) { if (capacity > 0) { m_pvStructureArray->setCapacity(capacity); } - if (length > 0) { - m_pvStructureArray->setLength(length); - } + m_pvStructureArray->setLength(length); m_channelArrayRequester->setLengthDone(Status::Ok); if (lastRequest) From 4bbab422fe29c79de569e12ea0b24b9ba47a54c5 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 7 Apr 2014 12:22:30 +0200 Subject: [PATCH 04/32] ChannelRequest::cancel() impl. --- pvAccessApp/ca/caChannel.cpp | 23 ++++++ pvAccessApp/ca/caChannel.h | 12 ++++ pvAccessApp/client/pvAccess.h | 6 ++ pvAccessApp/remote/remote.h | 5 +- .../remoteClient/clientContextImpl.cpp | 70 ++++++++++++++++--- pvAccessApp/rpcService/rpcServer.cpp | 5 ++ pvAccessApp/server/baseChannelRequester.cpp | 1 + pvAccessApp/server/baseChannelRequester.h | 1 + pvAccessApp/server/responseHandlers.cpp | 54 ++++++++++++-- pvAccessApp/server/responseHandlers.h | 31 ++++++-- testApp/remote/testServer.cpp | 28 ++++++++ 11 files changed, 216 insertions(+), 20 deletions(-) diff --git a/pvAccessApp/ca/caChannel.cpp b/pvAccessApp/ca/caChannel.cpp index 99b682a..bba7c38 100644 --- a/pvAccessApp/ca/caChannel.cpp +++ b/pvAccessApp/ca/caChannel.cpp @@ -881,6 +881,13 @@ void CAChannelGet::get(bool lastRequest) } +/* --------------- epics::pvData::ChannelRequest --------------- */ + +void CAChannelGet::cancel() +{ + // noop +} + /* --------------- epics::pvData::Destroyable --------------- */ @@ -1176,6 +1183,14 @@ void CAChannelPut::get() } + +/* --------------- epics::pvData::ChannelRequest --------------- */ + +void CAChannelPut::cancel() +{ + // noop +} + /* --------------- epics::pvData::Destroyable --------------- */ @@ -1350,6 +1365,14 @@ void CAChannelMonitor::release(epics::pvData::MonitorElementPtr const & /*monito } + +/* --------------- epics::pvData::ChannelRequest --------------- */ + +void CAChannelMonitor::cancel() +{ + // noop +} + /* --------------- epics::pvData::Destroyable --------------- */ diff --git a/pvAccessApp/ca/caChannel.h b/pvAccessApp/ca/caChannel.h index 74a4d2f..ee8b845 100644 --- a/pvAccessApp/ca/caChannel.h +++ b/pvAccessApp/ca/caChannel.h @@ -144,6 +144,10 @@ public: virtual void get(bool lastRequest); + /* --------------- epics::pvData::ChannelRequest --------------- */ + + virtual void cancel(); + /* --------------- epics::pvData::Destroyable --------------- */ virtual void destroy(); @@ -192,6 +196,10 @@ public: virtual void put(bool lastRequest); virtual void get(); + /* --------------- epics::pvData::ChannelRequest --------------- */ + + virtual void cancel(); + /* --------------- epics::pvData::Destroyable --------------- */ virtual void destroy(); @@ -240,6 +248,10 @@ public: virtual epics::pvData::MonitorElementPtr poll(); virtual void release(epics::pvData::MonitorElementPtr const & monitorElement); + /* --------------- epics::pvData::ChannelRequest --------------- */ + + virtual void cancel(); + /* --------------- epics::pvData::Destroyable --------------- */ virtual void destroy(); diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index 7f59f9b..5cc0982 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -114,6 +114,12 @@ namespace pvAccess { class epicsShareClass ChannelRequest : public epics::pvData::Destroyable, public Lockable, private epics::pvData::NoDefaultMethods { public: POINTER_DEFINITIONS(ChannelRequest); + + /** + * Cancel any currently pending request. + * No response callback should be called after the request has been canceled. + */ + virtual void cancel() = 0; }; /** diff --git a/pvAccessApp/remote/remote.h b/pvAccessApp/remote/remote.h index 311c328..7999293 100644 --- a/pvAccessApp/remote/remote.h +++ b/pvAccessApp/remote/remote.h @@ -99,12 +99,13 @@ namespace epics { CMD_PUT_GET = 12, CMD_MONITOR = 13, CMD_ARRAY = 14, - CMD_CANCEL_REQUEST = 15, + CMD_DESTROY_REQUEST = 15, CMD_PROCESS = 16, CMD_GET_FIELD = 17, CMD_MESSAGE = 18, CMD_MULTIPLE_DATA = 19, - CMD_RPC = 20 + CMD_RPC = 20, + CMD_CANCEL_REQUEST = 21 }; enum ControlCommands { diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index c9cf0ee..e14ee2c 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -120,6 +120,7 @@ namespace epics { /* negative... */ static const int NULL_REQUEST = -1; static const int PURE_DESTROY_REQUEST = -2; + static const int PURE_CANCEL_REQUEST = -3; pvAccessID m_ioid; @@ -160,7 +161,7 @@ namespace epics { Lock guard(m_mutex); // we allow pure destroy... - if (m_pendingRequest != NULL_REQUEST && qos != PURE_DESTROY_REQUEST) + if (m_pendingRequest != NULL_REQUEST && qos != PURE_DESTROY_REQUEST && qos != PURE_CANCEL_REQUEST) return false; m_pendingRequest = qos; @@ -224,7 +225,7 @@ namespace epics { m_mutex.unlock(); if (!destroyResponse(transport, version, payloadBuffer, qos, m_status)) - cancel(); + destroy(); } else { @@ -239,7 +240,21 @@ namespace epics { } virtual void cancel() { - destroy(); + + { + Lock guard(m_mutex); + if (m_destroyed) + return; + } + + try + { + startRequest(PURE_CANCEL_REQUEST); + m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + } catch (...) { + // noop (do not complain if fails) + } + } virtual void destroy() { @@ -311,6 +326,12 @@ namespace epics { if (qos == -1) return; else if (qos == PURE_DESTROY_REQUEST) + { + control->startMessage((int8)CMD_DESTROY_REQUEST, 8); + buffer->putInt(m_channel->getServerChannelID()); + buffer->putInt(m_ioid); + } + else if (qos == PURE_CANCEL_REQUEST) { control->startMessage((int8)CMD_CANCEL_REQUEST, 8); buffer->putInt(m_channel->getServerChannelID()); @@ -467,6 +488,11 @@ namespace epics { } } + virtual void cancel() + { + BaseRequestImpl::cancel(); + } + virtual void destroy() { BaseRequestImpl::destroy(); @@ -669,6 +695,11 @@ namespace epics { } } + virtual void cancel() + { + BaseRequestImpl::cancel(); + } + virtual void destroy() { BaseRequestImpl::destroy(); @@ -893,6 +924,11 @@ namespace epics { } } + virtual void cancel() + { + BaseRequestImpl::cancel(); + } + virtual void destroy() { BaseRequestImpl::destroy(); @@ -1169,6 +1205,11 @@ namespace epics { } } + virtual void cancel() + { + BaseRequestImpl::cancel(); + } + virtual void destroy() { BaseRequestImpl::destroy(); @@ -1351,6 +1392,11 @@ namespace epics { } } + virtual void cancel() + { + BaseRequestImpl::cancel(); + } + virtual void destroy() { BaseRequestImpl::destroy(); @@ -1638,6 +1684,11 @@ namespace epics { } } + virtual void cancel() + { + BaseRequestImpl::cancel(); + } + virtual void destroy() { BaseRequestImpl::destroy(); @@ -1746,8 +1797,8 @@ namespace epics { virtual void cancel() { - destroy(); - // TODO notify? + // TODO + // noop } virtual void timeout() { @@ -1796,7 +1847,7 @@ namespace epics { EXCEPTION_GUARD(m_callback->getDone(status, FieldConstPtr())); } - cancel(); + destroy(); } @@ -2144,7 +2195,7 @@ namespace epics { m_mutex.unlock(); if (!destroyResponse(transport, version, payloadBuffer, qos, status)) - cancel(); + destroy(); } else { @@ -2580,7 +2631,7 @@ namespace epics { ResponseHandler::shared_pointer badResponse(new BadResponse(context)); ResponseHandler::shared_pointer dataResponse(new DataResponseHandler(context)); - m_handlerTable.resize(CMD_RPC+1); + m_handlerTable.resize(CMD_CANCEL_REQUEST+1); m_handlerTable[CMD_BEACON].reset(new BeaconResponseHandler(context)); /* 0 */ m_handlerTable[CMD_CONNECTION_VALIDATION].reset(new ClientConnectionValidationHandler(context)); /* 1 */ @@ -2597,12 +2648,13 @@ namespace epics { m_handlerTable[CMD_PUT_GET] = dataResponse; /* 12 - put-get response */ m_handlerTable[CMD_MONITOR] = dataResponse; /* 13 - monitor response */ m_handlerTable[CMD_ARRAY] = dataResponse; /* 14 - array response */ - m_handlerTable[CMD_CANCEL_REQUEST] = badResponse; /* 15 - cancel request */ + m_handlerTable[CMD_DESTROY_REQUEST] = badResponse; /* 15 - destroy request */ m_handlerTable[CMD_PROCESS] = dataResponse; /* 16 - process response */ m_handlerTable[CMD_GET_FIELD] = dataResponse; /* 17 - get field response */ m_handlerTable[CMD_MESSAGE].reset(new MessageHandler(context)); /* 18 - message to Requester */ m_handlerTable[CMD_MULTIPLE_DATA] = badResponse; // TODO new MultipleDataResponseHandler(context), /* 19 - grouped monitors */ m_handlerTable[CMD_RPC] = dataResponse; /* 20 - RPC response */ + m_handlerTable[CMD_CANCEL_REQUEST] = badResponse; /* 21 - cancel request */ } virtual void handleResponse(osiSockAddr* responseFrom, diff --git a/pvAccessApp/rpcService/rpcServer.cpp b/pvAccessApp/rpcService/rpcServer.cpp index 7f2299b..8b50efa 100644 --- a/pvAccessApp/rpcService/rpcServer.cpp +++ b/pvAccessApp/rpcService/rpcServer.cpp @@ -78,6 +78,11 @@ class ChannelRPCServiceImpl : public ChannelRPC processRequest(pvArgument, lastRequest); } + virtual void cancel() + { + // noop + } + virtual void destroy() { // noop diff --git a/pvAccessApp/server/baseChannelRequester.cpp b/pvAccessApp/server/baseChannelRequester.cpp index 928fdb2..73416fc 100644 --- a/pvAccessApp/server/baseChannelRequester.cpp +++ b/pvAccessApp/server/baseChannelRequester.cpp @@ -18,6 +18,7 @@ const Status BaseChannelRequester::noReadACLStatus = Status(Status::STATUSTYPE_E const Status BaseChannelRequester::noWriteACLStatus = Status(Status::STATUSTYPE_ERROR, "no write access"); const Status BaseChannelRequester::noProcessACLStatus = Status(Status::STATUSTYPE_ERROR, "no process access"); const Status BaseChannelRequester::otherRequestPendingStatus = Status(Status::STATUSTYPE_ERROR, "other request pending"); +const Status BaseChannelRequester::notAChannelRequestStatus = Status(Status::STATUSTYPE_ERROR, "not a channel request"); const int32 BaseChannelRequester::NULL_REQUEST = -1; diff --git a/pvAccessApp/server/baseChannelRequester.h b/pvAccessApp/server/baseChannelRequester.h index c17af5c..ffb85f5 100644 --- a/pvAccessApp/server/baseChannelRequester.h +++ b/pvAccessApp/server/baseChannelRequester.h @@ -48,6 +48,7 @@ public: static const epics::pvData::Status noWriteACLStatus; static const epics::pvData::Status noProcessACLStatus; static const epics::pvData::Status otherRequestPendingStatus; + static const epics::pvData::Status notAChannelRequestStatus; protected: const pvAccessID _ioid; Transport::shared_pointer _transport; diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index a1699e0..4d8fb56 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -50,7 +50,7 @@ ServerResponseHandler::ServerResponseHandler(ServerContextImpl::shared_pointer c MB_INIT; ResponseHandler::shared_pointer badResponse(new ServerBadResponse(context)); - m_handlerTable.resize(CMD_RPC+1); + m_handlerTable.resize(CMD_CANCEL_REQUEST+1); m_handlerTable[CMD_BEACON].reset(new ServerNoopResponse(context, "Beacon")); /* 0 */ m_handlerTable[CMD_CONNECTION_VALIDATION].reset(new ServerConnectionValidationHandler(context)); /* 1 */ @@ -68,12 +68,13 @@ ServerResponseHandler::ServerResponseHandler(ServerContextImpl::shared_pointer c m_handlerTable[CMD_PUT_GET].reset(new ServerPutGetHandler(context)); /* 12 - put-get response */ m_handlerTable[CMD_MONITOR].reset(new ServerMonitorHandler(context)); /* 13 - monitor response */ m_handlerTable[CMD_ARRAY].reset(new ServerArrayHandler(context)); /* 14 - array response */ - m_handlerTable[CMD_CANCEL_REQUEST].reset(new ServerCancelRequestHandler(context)); /* 15 - cancel request */ + m_handlerTable[CMD_DESTROY_REQUEST].reset(new ServerDestroyRequestHandler(context)); /* 15 - destroy request */ m_handlerTable[CMD_PROCESS].reset(new ServerProcessHandler(context)); /* 16 - process response */ m_handlerTable[CMD_GET_FIELD].reset(new ServerGetFieldHandler(context)); /* 17 - get field response */ m_handlerTable[CMD_MESSAGE] = badResponse; /* 18 - message to Requester */ m_handlerTable[CMD_MULTIPLE_DATA] = badResponse; /* 19 - grouped monitors */ m_handlerTable[CMD_RPC].reset(new ServerRPCHandler(context)); /* 20 - RPC response */ + m_handlerTable[CMD_CANCEL_REQUEST].reset(new ServerCancelRequestHandler(context)); /* 21 - cancel request */ } void ServerResponseHandler::handleResponse(osiSockAddr* responseFrom, @@ -1659,7 +1660,7 @@ void ServerChannelArrayRequesterImpl::send(ByteBuffer* buffer, TransportSendCont } /****************************************************************************************/ -void ServerCancelRequestHandler::handleResponse(osiSockAddr* responseFrom, +void ServerDestroyRequestHandler::handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer const & transport, int8 version, int8 command, size_t payloadSize, ByteBuffer* payloadBuffer) { AbstractServerResponseHandler::handleResponse(responseFrom, @@ -1693,11 +1694,56 @@ void ServerCancelRequestHandler::handleResponse(osiSockAddr* responseFrom, channel->unregisterRequest(ioid); } -void ServerCancelRequestHandler::failureResponse(Transport::shared_pointer const & transport, pvAccessID ioid, const Status& errorStatus) +void ServerDestroyRequestHandler::failureResponse(Transport::shared_pointer const & transport, pvAccessID ioid, const Status& errorStatus) { BaseChannelRequester::message(transport, ioid, errorStatus.getMessage(), warningMessage); } +/****************************************************************************************/ +void ServerCancelRequestHandler::handleResponse(osiSockAddr* responseFrom, + Transport::shared_pointer const & transport, int8 version, int8 command, + size_t payloadSize, ByteBuffer* payloadBuffer) { + AbstractServerResponseHandler::handleResponse(responseFrom, + transport, version, command, payloadSize, payloadBuffer); + + // NOTE: we do not explicitly check if transport is OK + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); + + transport->ensureData(2*sizeof(int32)/sizeof(int8)); + const pvAccessID sid = payloadBuffer->getInt(); + const pvAccessID ioid = payloadBuffer->getInt(); + + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); + if (channel == NULL) + { + failureResponse(transport, ioid, BaseChannelRequester::badCIDStatus); + return; + } + + Destroyable::shared_pointer request = channel->getRequest(ioid); + if (request == NULL) + { + failureResponse(transport, ioid, BaseChannelRequester::badIOIDStatus); + return; + } + + ChannelRequest::shared_pointer cr = dynamic_pointer_cast(request); + if (cr == NULL) + { + failureResponse(transport, ioid, BaseChannelRequester::notAChannelRequestStatus); + return; + } + + // cancel + cr->cancel(); + +} + +void ServerCancelRequestHandler::failureResponse(Transport::shared_pointer const & transport, pvAccessID ioid, const Status& errorStatus) +{ + BaseChannelRequester::message(transport, ioid, errorStatus.getMessage(), warningMessage); +} + /****************************************************************************************/ void ServerProcessHandler::handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer const & transport, int8 version, int8 command, diff --git a/pvAccessApp/server/responseHandlers.h b/pvAccessApp/server/responseHandlers.h index 89db7ce..49a2912 100644 --- a/pvAccessApp/server/responseHandlers.h +++ b/pvAccessApp/server/responseHandlers.h @@ -573,15 +573,15 @@ namespace pvAccess { /****************************************************************************************/ /** - * Cancel request handler. + * Destroy request handler. */ - class ServerCancelRequestHandler : public AbstractServerResponseHandler + class ServerDestroyRequestHandler : public AbstractServerResponseHandler { public: - ServerCancelRequestHandler(ServerContextImpl::shared_pointer const & context) : - AbstractServerResponseHandler(context, "Cancel request") { + ServerDestroyRequestHandler(ServerContextImpl::shared_pointer const & context) : + AbstractServerResponseHandler(context, "Destroy request") { } - virtual ~ServerCancelRequestHandler() {} + virtual ~ServerDestroyRequestHandler() {} virtual void handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer const & transport, epics::pvData::int8 version, epics::pvData::int8 command, @@ -592,6 +592,27 @@ namespace pvAccess { }; + /****************************************************************************************/ + /** + * Cancel request handler. + */ + class ServerCancelRequestHandler : public AbstractServerResponseHandler + { + public: + ServerCancelRequestHandler(ServerContextImpl::shared_pointer const & context) : + AbstractServerResponseHandler(context, "Cancel request") { + } + virtual ~ServerCancelRequestHandler() {} + + virtual void handleResponse(osiSockAddr* responseFrom, + Transport::shared_pointer const & transport, epics::pvData::int8 version, epics::pvData::int8 command, + std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer); + private: + + void failureResponse(Transport::shared_pointer const & transport, pvAccessID ioid, const epics::pvData::Status& errorStatus); + }; + + /****************************************************************************************/ /** * Process request handler. diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index a70f593..230e636 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -885,6 +885,10 @@ public: destroy(); } + virtual void cancel() + { + } + virtual void destroy() { } @@ -998,6 +1002,10 @@ public: m_changed.set(); } + virtual void cancel() + { + } + virtual void destroy() { if (m_channelProcess) @@ -1097,6 +1105,10 @@ public: m_channelPutRequester->getDone(Status::Ok); } + virtual void cancel() + { + } + virtual void destroy() { if (m_channelProcess) @@ -1187,6 +1199,10 @@ public: m_channelPutGetRequester->getPutDone(Status::Ok); } + virtual void cancel() + { + } + virtual void destroy() { if (m_channelProcess) @@ -1602,6 +1618,10 @@ public: destroy(); } + virtual void cancel() + { + } + virtual void destroy() { } @@ -1794,6 +1814,10 @@ public: destroy(); } + virtual void cancel() + { + } + virtual void destroy() { } @@ -1931,6 +1955,10 @@ public: } } + virtual void cancel() + { + } + virtual void destroy() { stop(); From 4f63aba281037588718b348316f24a2de757c5a0 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Wed, 14 May 2014 11:07:54 +0200 Subject: [PATCH 05/32] new API, code not yet ported --- pvAccessApp/client/pvAccess.h | 236 ++++++++++++++++++++++++---------- 1 file changed, 169 insertions(+), 67 deletions(-) diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index 5cc0982..ee3d628 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -116,10 +116,20 @@ namespace pvAccess { POINTER_DEFINITIONS(ChannelRequest); /** - * Cancel any currently pending request. - * No response callback should be called after the request has been canceled. + * Cancel any pending request. + * Completion will be reported via request's response callback: + *
    + *
  • if cancel() request is issued after the request was already complete, request success/failure completion will be reported and cancel() request ignored.
  • + *
  • if the request was actually canceled, cancellation completion is reported.
  • + *
*/ virtual void cancel() = 0; + + /** + * Announce next request as last request. + * When last request will be completed (regardless of completion status) the remote and local instance will be destroyed. + */ + virtual void lastRequest() = 0; }; /** @@ -132,27 +142,34 @@ namespace pvAccess { /** * put to the remote array. - * @param lastRequest Is this the last request. + * @param putArray array to put. * @param offset The offset in the remote array, i.e. the PVArray returned by ChannelArrayRequester.channelArrayConnect. - * @param count The number of elements to put, 0 means "enture array". + * @param count The number of elements to put, 0 means "entire array". + * @param stride 1 means all the elements from offset to count, 2 means every other, 3 means every third, etc. */ - virtual void putArray(bool lastRequest, size_t offset = 0, size_t count = 0) = 0; + virtual void putArray( + epics::pvData::PVArray::shared_pointer const & putArray, + size_t offset = 0, size_t count = 0, size_t stride = 1) = 0; /** * get from the remote array. - * @param lastRequest Is this the last request. * @param offset The offset in the remote array, i.e. the PVArray returned by ChannelArrayRequester.channelArrayConnect. * @param count The number of elements to get, 0 means "till the end of an array". + * @param stride 1 means all the elements from offset to count, 2 means every other, 3 means every third, etc. */ - virtual void getArray(bool lastRequest, size_t offset = 0, size_t count = 0) = 0; + virtual void getArray(size_t offset = 0, size_t count = 0, size_t stride = 1) = 0; + + /** + * Get the length and the capacity. + */ + virtual void getLength() = 0; /** * Set the length and/or the capacity. - * @param lastRequest Is this the last request. * @param length The new length. * @param capacity The new capacity, 0 means do "do not change the capacity". */ - virtual void setLength(bool lastRequest, size_t length, size_t capacity = 0) = 0; + virtual void setLength(size_t length, size_t capacity = 0) = 0; }; /** @@ -165,10 +182,30 @@ namespace pvAccess { /** * The client and server have both completed the createChannelArray request. * @param status Completion status. - * @param channelArray The channelArray interface or null if the request failed. - * @param pvArray The PVArray that holds the data. + * @param channelArray The channelArray interface or null if the request failed. + * @param pvArray The PVArray that holds the data or null if the request failed. */ virtual void channelArrayConnect( + const epics::pvData::Status& status, + ChannelArray::shared_pointer const & channelArray, + epics::pvData::Array::shared_pointer const & array) = 0; + + /** + * The request is done. This is always called with no locks held. + * @param status Completion status. + * @param channelArray The channelArray interface. + */ + virtual void putArrayDone( + const epics::pvData::Status& status, + ChannelArray::shared_pointer const & channelArray) = 0; + + /** + * The request is done. This is always called with no locks held. + * @param status Completion status. + * @param channelArray The channelArray interface. + * @param pvArray The PVArray that holds the data or null if the request failed. + */ + virtual void getArrayDone( const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray, epics::pvData::PVArray::shared_pointer const & pvArray) = 0; @@ -176,20 +213,23 @@ namespace pvAccess { /** * The request is done. This is always called with no locks held. * @param status Completion status. + * @param channelArray The channelArray interface. + * @param length The length of the array, 0 if the request failed. + * @param capacity The capacity of the array, 0 if the request failed. */ - virtual void putArrayDone(const epics::pvData::Status& status) = 0; + virtual void getLengthDone( + const epics::pvData::Status& status, + ChannelArray::shared_pointer const & channelArray, + size_t length, size_t capacity) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. + * @param channelArray The channelArray interface. */ - virtual void getArrayDone(const epics::pvData::Status& status) = 0; - - /** - * The request is done. This is always called with no locks held. - * @param status Completion status. - */ - virtual void setLengthDone(const epics::pvData::Status& status) = 0; + virtual void setLengthDone( + const epics::pvData::Status& status, + ChannelArray::shared_pointer const & channelArray) = 0; }; @@ -212,10 +252,14 @@ namespace pvAccess { POINTER_DEFINITIONS(ChannelFindRequester); virtual ~ChannelFindRequester() {}; + /** * @param status Completion status. */ - virtual void channelFindResult(const epics::pvData::Status& status,ChannelFind::shared_pointer const & channelFind,bool wasFound) = 0; + virtual void channelFindResult( + const epics::pvData::Status& status, + ChannelFind::shared_pointer const & channelFind, + bool wasFound) = 0; }; @@ -228,11 +272,9 @@ namespace pvAccess { /** * Get data from the channel. - * This fails if the request can not be satisfied. - * If it fails ChannelGetRequester.getDone is called before get returns. - * @param lastRequest Is this the last request? + * Completion status is reported by calling ChannelGetRequester.getDone() callback. */ - virtual void get(bool lastRequest) = 0; + virtual void get() = 0; }; @@ -246,18 +288,26 @@ namespace pvAccess { /** * The client and server have both completed the createChannelGet request. * @param status Completion status. - * @param channelGet The channelGet interface or null if the request failed. - * @param pvStructure The PVStructure that holds the data. - * @param bitSet The bitSet for that shows what data has changed. + * @param channelGet The channelGet interface or null if the request failed. + * @param structure The introspection interface of requested get structure or null if the request failed. */ - virtual void channelGetConnect(const epics::pvData::Status& status,ChannelGet::shared_pointer const & channelGet, - epics::pvData::PVStructure::shared_pointer const & pvStructure,epics::pvData::BitSet::shared_pointer const & bitSet) = 0; + virtual void channelGetConnect( + const epics::pvData::Status& status, + ChannelGet::shared_pointer const & channelGet, + epics::pvData::Structure::shared_pointer const & structure) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. + * @param channelGet The channelGet interface. + * @param pvStructure The PVStructure that holds the data or null if the request failed. + * @param bitSet The bitSet for that shows what data has changed or null if the request failed. */ - virtual void getDone(const epics::pvData::Status& status) = 0; + virtual void getDone( + const epics::pvData::Status& status, + ChannelGet::shared_pointer const & channelGet, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet) = 0; }; @@ -270,11 +320,9 @@ namespace pvAccess { /** * Issue a process request. - * This fails if the request can not be satisfied. - * If it fails the channelProcessRequester.processDone is called before process returns. - * @param lastRequest Is this the last request? + * Completion status is reported by calling ChannelProcessRequester.processDone() callback. */ - virtual void process(bool lastRequest) = 0; + virtual void process() = 0; }; @@ -288,16 +336,21 @@ namespace pvAccess { /** * The client and server have both completed the createChannelProcess request. * @param status Completion status. - * @param channelProcess The channelProcess interface or null if the client could not become + * @param channelProcess The channelProcess interface or null if the client could not become * the record processor. */ - virtual void channelProcessConnect(const epics::pvData::Status& status,ChannelProcess::shared_pointer const & channelProcess) = 0; + virtual void channelProcessConnect( + const epics::pvData::Status& status, + ChannelProcess::shared_pointer const & channelProcess) = 0; /** * The process request is done. This is always called with no locks held. * @param status Completion status. + * @param channelProcess The channelProcess interface. */ - virtual void processDone(const epics::pvData::Status& status) = 0; + virtual void processDone( + const epics::pvData::Status& status, + ChannelProcess::shared_pointer const & channelProcess) = 0; }; @@ -310,11 +363,13 @@ namespace pvAccess { /** * Put data to a channel. - * This fails if the request can not be satisfied. - * If it fails ChannelPutRequester.putDone is called before put returns. - * @param lastRequest Is this the last request? + * Completion status is reported by calling ChannelPutRequester.putDone() callback. + * @param pvPutStructure The PVStructure that holds the putData. + * @param putBitSet putPVStructure bit-set (selects what fields to put). */ - virtual void put(bool lastRequest) = 0; + virtual void put( + epics::pvData::PVStructure::shared_pointer const & pvPutStructure, + epics::pvData::BitSet::shared_pointer const & putBitSet) = 0; /** * Get the current data. @@ -334,23 +389,34 @@ namespace pvAccess { * The client and server have both processed the createChannelPut request. * @param status Completion status. * @param channelPut The channelPut interface or null if the request failed. - * @param pvStructure The PVStructure that holds the data. - * @param bitSet The bitSet for that shows what data has changed. + * @param structure The introspection interface of requested put/get structure or null if the request failed. */ - virtual void channelPutConnect(const epics::pvData::Status& status,ChannelPut::shared_pointer const & channelPut, - epics::pvData::PVStructure::shared_pointer const & pvStructure,epics::pvData::BitSet::shared_pointer const & bitSet) = 0; + virtual void channelPutConnect( + const epics::pvData::Status& status, + ChannelPut::shared_pointer const & channelPut, + epics::pvData::Structure::shared_pointer const & structure) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. + * @param channelPut The channelPut interface. */ - virtual void putDone(const epics::pvData::Status& status) = 0; + virtual void putDone( + const epics::pvData::Status& status, + ChannelPut::shared_pointer const & channelPut) = 0; /** * The get request is done. This is always called with no locks held. * @param status Completion status. + * @param channelPut The channelPut interface. + * @param pvStructure The PVStructure that holds the data or null if the request failed. + * @param bitSet The bitSet for that shows what data has changed or null if the request failed. */ - virtual void getDone(const epics::pvData::Status& status) = 0; + virtual void getDone( + const epics::pvData::Status& status, + ChannelPut::shared_pointer const & channelPut, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet) = 0; }; @@ -364,19 +430,23 @@ namespace pvAccess { /** * Issue a put/get request. If process was requested when the ChannelPutGet was created this is a put, process, get. - * This fails if the request can not be satisfied. - * If it fails ChannelPutGetRequester.putDone is called before putGet returns. - * @param lastRequest Is this the last request? + * Completion status is reported by calling ChannelPutGetRequester.putGetDone() callback. + * @param pvPutStructure The PVStructure that holds the putData. + * @param putBitSet putPVStructure bit-set (selects what fields to put). */ - virtual void putGet(bool lastRequest) = 0; + virtual void putGet( + epics::pvData::PVStructure::shared_pointer const & pvPutStructure, + epics::pvData::BitSet::shared_pointer const & putBitSet) = 0; /** * Get the put PVStructure. The record will not be processed. + * Completion status is reported by calling ChannelPutGetRequester.getPutDone() callback. */ virtual void getPut() = 0; /** * Get the get PVStructure. The record will not be processed. + * Completion status is reported by calling ChannelPutGetRequester.getGetDone() callback. */ virtual void getGet() = 0; }; @@ -394,28 +464,53 @@ namespace pvAccess { * The client and server have both completed the createChannelPutGet request. * @param status Completion status. * @param channelPutGet The channelPutGet interface or null if the request failed. - * @param pvPutStructure The PVStructure that holds the putData. - * @param pvGetStructure The PVStructure that holds the getData. + * @param putStructure The put structure introspection data or null if the request failed. + * @param getStructure The get structure introspection data or null if the request failed. */ - virtual void channelPutGetConnect(const epics::pvData::Status& status,ChannelPutGet::shared_pointer const & channelPutGet, - epics::pvData::PVStructure::shared_pointer const & pvPutStructure,epics::pvData::PVStructure::shared_pointer const & pvGetStructure) = 0; + virtual void channelPutGetConnect( + const epics::pvData::Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::Structure::shared_pointer const & putStructure, + epics::pvData::Structure::shared_pointer const & getStructure) = 0; + /** * The putGet request is done. This is always called with no locks held. * @param status Completion status. + * @param channelPutGet The channelPutGet interface. + * @param pvGetStructure The PVStructure that holds the getData or null if the request failed. + * @param getBitSet getPVStructure changed bit-set or null if the request failed. */ - virtual void putGetDone(const epics::pvData::Status& status) = 0; + virtual void putGetDone( + const epics::pvData::Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructure::shared_pointer const & pvGetStructure, + epics::pvData::BitSet::shared_pointer const & getBitSet) = 0; /** * The getPut request is done. This is always called with no locks held. * @param status Completion status. + * @param channelPutGet The channelPutGet interface. + * @param pvPutStructure The PVStructure that holds the putData or null if the request failed. + * @param putBitSet putPVStructure changed bit-set or null if the request failed. */ - virtual void getPutDone(const epics::pvData::Status& status) = 0; + virtual void getPutDone( + const epics::pvData::Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructure::shared_pointer const & pvPutStructure, + epics::pvData::BitSet::shared_pointer const & putBitSet) = 0; /** * The getGet request is done. This is always called with no locks held. * @param status Completion status. + * @param channelPutGet The channelPutGet interface. + * @param pvGetStructure The PVStructure that holds the getData or null if the request failed. + * @param getBitSet getPVStructure changed bit-set or null if the request failed. */ - virtual void getGetDone(const epics::pvData::Status& status) = 0; + virtual void getGetDone( + const epics::pvData::Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructure::shared_pointer const & pvGetStructure, + epics::pvData::BitSet::shared_pointer const & getBitSet) = 0; }; @@ -428,11 +523,10 @@ namespace pvAccess { /** * Issue an RPC request to the channel. - * This fails if the request can not be satisfied. + * Completion status is reported by calling ChannelRPCRequester.requestDone() callback. * @param pvArgument The argument structure for an RPC request. - * @param lastRequest Is this the last request? */ - virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument, bool lastRequest) = 0; + virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument) = 0; }; @@ -446,16 +540,22 @@ namespace pvAccess { /** * The client and server have both completed the createChannelGet request. * @param status Completion status. - * @param channelRPC The channelRPC interface or null if the request failed. + * @param channelRPC The channelRPC interface or null if the request failed. */ - virtual void channelRPCConnect(const epics::pvData::Status& status,ChannelRPC::shared_pointer const & channelRPC) = 0; + virtual void channelRPCConnect( + const epics::pvData::Status& status, + ChannelRPC::shared_pointer const & channelRPC) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. - * @param pvResponse The response data for the RPC request. + * @param channelRPC The channelRPC interface. + * @param pvResponse The response data for the RPC request or null if the request failed. */ - virtual void requestDone(const epics::pvData::Status& status,epics::pvData::PVStructure::shared_pointer const & pvResponse) = 0; + virtual void requestDone( + const epics::pvData::Status& status, + ChannelRPC::shared_pointer const & channelRPC, + epics::pvData::PVStructure::shared_pointer const & pvResponse) = 0; }; @@ -471,8 +571,10 @@ namespace pvAccess { * @param status Completion status. * @param field The Structure for the request. */ - // TODO naming convention - virtual void getDone(const epics::pvData::Status& status,epics::pvData::FieldConstPtr const & field) = 0; + virtual void getDone( + const epics::pvData::Status& status, + epics::pvData::FieldConstPtr const & field) = 0; // TODO naming convention + }; From 2ef0abc67b5b15fdbc2fb2f00a630782f84629b7 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 19 May 2014 22:33:40 +0200 Subject: [PATCH 06/32] work on porting --- pvAccessApp/client/pvAccess.h | 8 +- pvAccessApp/factory/ChannelAccessFactory.cpp | 12 +- .../remoteClient/clientContextImpl.cpp | 576 +++++++++++------- pvAccessApp/rpcService/rpcServer.cpp | 31 + pvAccessApp/rpcService/rpcServer.h | 8 +- 5 files changed, 394 insertions(+), 241 deletions(-) diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index ee3d628..5514610 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -878,13 +878,13 @@ namespace pvAccess { /** * Interface for locating channel providers. */ - class epicsShareClass ChannelAccess : private epics::pvData::NoDefaultMethods { + class epicsShareClass ChannelProviderRegistry : private epics::pvData::NoDefaultMethods { public: - POINTER_DEFINITIONS(ChannelAccess); + POINTER_DEFINITIONS(ChannelProviderRegistry); typedef std::vector stringVector_t; - virtual ~ChannelAccess() {}; + virtual ~ChannelProviderRegistry() {}; /** * Get a shared instance of the provider with the specified name. @@ -907,7 +907,7 @@ namespace pvAccess { virtual std::auto_ptr getProviderNames() = 0; }; - epicsShareExtern ChannelAccess::shared_pointer getChannelAccess(); + epicsShareExtern ChannelProviderRegistry::shared_pointer getChannelProviderRegistry(); epicsShareExtern void registerChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory); epicsShareExtern void unregisterChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory); diff --git a/pvAccessApp/factory/ChannelAccessFactory.cpp b/pvAccessApp/factory/ChannelAccessFactory.cpp index 5e11b71..9b74123 100644 --- a/pvAccessApp/factory/ChannelAccessFactory.cpp +++ b/pvAccessApp/factory/ChannelAccessFactory.cpp @@ -20,7 +20,7 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { -static ChannelAccess::shared_pointer channelAccess; +static ChannelProviderRegistry::shared_pointer ChannelProviderRegistry; static Mutex channelProviderMutex; @@ -28,7 +28,7 @@ typedef std::map ChannelProvider static ChannelProviderFactoryMap channelProviders; -class ChannelAccessImpl : public ChannelAccess { +class ChannelProviderRegistryImpl : public ChannelProviderRegistry { public: ChannelProvider::shared_pointer getProvider(String const & _providerName) { @@ -68,14 +68,14 @@ class ChannelAccessImpl : public ChannelAccess { } }; -ChannelAccess::shared_pointer getChannelAccess() { +ChannelProviderRegistry::shared_pointer getChannelProviderRegistry() { static Mutex mutex; Lock guard(mutex); - if(channelAccess.get()==0){ - channelAccess.reset(new ChannelAccessImpl()); + if(ChannelProviderRegistry.get()==0){ + ChannelProviderRegistry.reset(new ChannelProviderRegistryImpl()); } - return channelAccess; + return ChannelProviderRegistry; } void registerChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory) { diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index e14ee2c..a1d7a3b 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -106,11 +106,41 @@ namespace epics { static Status channelNotConnected; static Status channelDestroyed; static Status otherRequestPendingStatus; + static Status invalidPutStructureStatus; + static Status invalidPutArrayStatus; + static Status invalidBitSetLengthStatus; static Status pvRequestNull; static PVStructure::shared_pointer nullPVStructure; + static Structure::shared_pointer nullStructure; static BitSet::shared_pointer nullBitSet; + static BitSet::shared_pointer createBitSetFor( + PVStructure::shared_pointer const & pvStructure, + BitSet::shared_pointer const & existingBitSet) + { + int pvStructureSize = pvStructure->getNumberFields(); + if (existingBitSet.get() && static_cast(existingBitSet->size()) >= pvStructureSize) + { + // clear existing BitSet + // also necessary if larger BitSet is reused + existingBitSet->clear(); + return existingBitSet; + } + else + return BitSet::shared_pointer(new BitSet(pvStructureSize)); + } + + static PVField::shared_pointer reuseOrCreatePVField( + Field::const_shared_pointer const & field, + PVField::shared_pointer const & existingPVField) + { + if (existingPVField.get() && *field == *existingPVField->getField()) + return existingPVField; + else + return pvDataCreate->createPVField(field); + } + protected: ChannelImpl::shared_pointer m_channel; @@ -134,6 +164,8 @@ namespace epics { bool m_destroyed; bool m_initialized; + AtomicBoolean m_lastRequest; + AtomicBoolean m_subscribed; virtual ~BaseRequestImpl() {}; @@ -189,9 +221,8 @@ namespace epics { return m_ioid; } - virtual bool initResponse(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; - virtual bool destroyResponse(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; - virtual bool normalResponse(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; + virtual void initResponse(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; + virtual void normalResponse(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; virtual void response(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer) { transport->ensureData(1); @@ -218,18 +249,22 @@ namespace epics { initResponse(transport, version, payloadBuffer, qos, m_status); } - else if (qos & QOS_DESTROY) - { - m_mutex.lock(); - m_initialized = false; - m_mutex.unlock(); - - if (!destroyResponse(transport, version, payloadBuffer, qos, m_status)) - destroy(); - } else { + bool destroyReq = false; + + if (qos & QOS_DESTROY) + { + m_mutex.lock(); + m_initialized = false; + destroyReq = true; + m_mutex.unlock(); + } + normalResponse(transport, version, payloadBuffer, qos, m_status); + + if (destroyReq) + destroy(); } } catch (std::exception &e) { @@ -260,6 +295,10 @@ namespace epics { virtual void destroy() { destroy(false); } + + virtual void lastRequest() { + m_lastRequest.set(); + } virtual void destroy(bool createRequestFailed) { @@ -351,27 +390,14 @@ namespace epics { Status BaseRequestImpl::channelNotConnected = Status(Status::STATUSTYPE_ERROR, "channel not connected"); Status BaseRequestImpl::channelDestroyed = Status(Status::STATUSTYPE_ERROR, "channel destroyed"); Status BaseRequestImpl::otherRequestPendingStatus = Status(Status::STATUSTYPE_ERROR, "other request pending"); + Status BaseRequestImpl::invalidPutStructureStatus = Status(Status::STATUSTYPE_ERROR, "incompatible put structure"); + Status BaseRequestImpl::invalidPutArrayStatus = Status(Status::STATUSTYPE_ERROR, "incompatible put array"); + Status BaseRequestImpl::invalidBitSetLengthStatus = Status(Status::STATUSTYPE_ERROR, "invalid bit-set length"); Status BaseRequestImpl::pvRequestNull = Status(Status::STATUSTYPE_ERROR, "pvRequest == 0"); PVStructure::shared_pointer BaseRequestImpl::nullPVStructure; BitSet::shared_pointer BaseRequestImpl::nullBitSet; - - static BitSet::shared_pointer createBitSetFor(PVStructure::shared_pointer const & pvStructure, BitSet::shared_pointer const & existingBitSet) - { - int pvStructureSize = pvStructure->getNumberFields(); - if (existingBitSet.get() && static_cast(existingBitSet->size()) >= pvStructureSize) - { - // clear existing BitSet - // also necessary if larger BitSet is reused - existingBitSet->clear(); - return existingBitSet; - } - else - return BitSet::shared_pointer(new BitSet(pvStructureSize)); - } - - PVACCESS_REFCOUNT_MONITOR_DEFINE(channelProcess); class ChannelProcessRequestImpl : @@ -445,38 +471,31 @@ namespace epics { stopRequest(); } - virtual bool destroyResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { - EXCEPTION_GUARD(m_callback->processDone(status)); - return true; - } - - virtual bool initResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { + virtual void initResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { ChannelProcess::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); EXCEPTION_GUARD(m_callback->channelProcessConnect(status, thisPtr)); - return true; } - virtual bool normalResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { - EXCEPTION_GUARD(m_callback->processDone(status)); - return true; + virtual void normalResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { + EXCEPTION_GUARD(m_callback->processDone(status, shared_from_this())); } - virtual void process(bool lastRequest) + virtual void process() { { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_callback->processDone(destroyedStatus)); + EXCEPTION_GUARD(m_callback->processDone(destroyedStatus, shared_from_this())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_callback->processDone(notInitializedStatus)); + EXCEPTION_GUARD(m_callback->processDone(notInitializedStatus, shared_from_this())); return; } } - if (!startRequest(lastRequest ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_callback->processDone(otherRequestPendingStatus)); + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { + EXCEPTION_GUARD(m_callback->processDone(otherRequestPendingStatus, shared_from_this())); return; } @@ -484,7 +503,7 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_callback->processDone(channelNotConnected)); + EXCEPTION_GUARD(m_callback->processDone(channelNotConnected, shared_from_this())); } } @@ -498,6 +517,11 @@ namespace epics { BaseRequestImpl::destroy(); } + virtual void lastRequest() + { + BaseRequestImpl::lastRequest(); + } + virtual void lock() { // noop } @@ -542,7 +566,7 @@ namespace epics { if (m_pvRequest == 0) { ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(pvRequestNull, thisPointer, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(pvRequestNull, thisPointer, nullStructure)); return; } @@ -555,7 +579,7 @@ namespace epics { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(channelDestroyed, thisPointer, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(channelDestroyed, thisPointer, nullStructure)); BaseRequestImpl::destroy(true); } } @@ -601,19 +625,12 @@ namespace epics { stopRequest(); } - virtual bool destroyResponse(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { - // data available - if (qos & QOS_GET) - return normalResponse(transport, version, payloadBuffer, qos, status); - return true; - } - - virtual bool initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { + virtual void initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisPointer, nullPVStructure, nullBitSet)); - return true; + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisPointer, nullStructure)); + return; } // create data and its bitSet @@ -625,18 +642,17 @@ namespace epics { // notify ChannelGet::shared_pointer thisChannelGet = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisChannelGet, m_structure, m_bitSet)); - return true; + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisChannelGet, m_structure->getStructure())); } - virtual bool normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { + virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { MB_POINT(channelGet, 8, "client channelGet->deserialize (start)"); if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(status)); - return true; + EXCEPTION_GUARD(m_channelGetRequester->getDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + return; } // deserialize bitSet and data @@ -648,11 +664,10 @@ namespace epics { MB_POINT(channelGet, 9, "client channelGet->deserialize (end), just before channelGet->getDone() is called"); - EXCEPTION_GUARD(m_channelGetRequester->getDone(status)); - return true; + EXCEPTION_GUARD(m_channelGetRequester->getDone(status, shared_from_this(), m_structure, m_bitSet)); } - virtual void get(bool lastRequest) { + virtual void get() { { MB_INC_AUTO_ID(channelGet); @@ -660,11 +675,11 @@ namespace epics { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(destroyedStatus)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(notInitializedStatus)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } } @@ -681,8 +696,8 @@ namespace epics { return; } */ - if (!startRequest(lastRequest ? QOS_DESTROY | QOS_GET : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(otherRequestPendingStatus)); + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET : QOS_DEFAULT)) { + EXCEPTION_GUARD(m_channelGetRequester->getDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } @@ -691,7 +706,7 @@ namespace epics { //TODO bulk hack m_channel->checkAndGetTransport()->enqueueOnlySendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelGetRequester->getDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); } } @@ -705,6 +720,11 @@ namespace epics { BaseRequestImpl::destroy(); } + virtual void lastRequest() + { + BaseRequestImpl::lastRequest(); + } + virtual void lock() { m_structureMutex.lock(); @@ -737,8 +757,13 @@ namespace epics { PVStructure::shared_pointer m_pvRequest; + // get structure container PVStructure::shared_pointer m_structure; BitSet::shared_pointer m_bitSet; + + // put reference store + PVStructure::shared_pointer m_pvPutStructure; + BitSet::shared_pointer m_pvPutBitSet; Mutex m_structureMutex; @@ -755,7 +780,7 @@ namespace epics { if (m_pvRequest == 0) { ChannelPut::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(pvRequestNull, thisPointer, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(pvRequestNull, thisPointer, nullStructure)); return; } @@ -768,7 +793,7 @@ namespace epics { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { ChannelPut::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(channelDestroyed, thisPointer, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(channelDestroyed, thisPointer, nullStructure)); BaseRequestImpl::destroy(true); } } @@ -811,25 +836,24 @@ namespace epics { { // no need to lock here, since it is already locked via TransportSender IF //Lock lock(m_structureMutex); - m_bitSet->serialize(buffer, control); - m_structure->serialize(buffer, control, m_bitSet.get()); + m_pvPutBitSet->serialize(buffer, control); + m_pvPutStructure->serialize(buffer, control, m_pvPutBitSet.get()); + + // release references + m_pvPutBitSet.reset(); + m_pvPutStructure.reset(); } } stopRequest(); } - virtual bool destroyResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { - EXCEPTION_GUARD(m_channelPutRequester->putDone(status)); - return true; - } - - virtual bool initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { + virtual void initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { ChannelPut::shared_pointer thisChannelPut = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, thisChannelPut, nullPVStructure, nullBitSet)); - return true; + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, thisChannelPut, nullStructure)); + return; } // create data and its bitSet @@ -841,31 +865,29 @@ namespace epics { // notify ChannelPut::shared_pointer thisChannelPut = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, thisChannelPut, m_structure, m_bitSet)); - return true; + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, thisChannelPut, m_structure->getStructure())); } - virtual bool normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (qos & QOS_GET) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(status)); - return true; + EXCEPTION_GUARD(m_channelPutRequester->getDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + return; } { Lock lock(m_structureMutex); - m_structure->deserialize(payloadBuffer, transport.get()); + m_bitSet->deserialize(payloadBuffer, transport.get()); + m_structure->deserialize(payloadBuffer, transport.get(), m_bitSet.get()); } - EXCEPTION_GUARD(m_channelPutRequester->getDone(status)); - return true; + EXCEPTION_GUARD(m_channelPutRequester->getDone(status, shared_from_this(), m_structure, m_bitSet)); } else { - EXCEPTION_GUARD(m_channelPutRequester->putDone(status)); - return true; + EXCEPTION_GUARD(m_channelPutRequester->putDone(status, shared_from_this())); } } @@ -874,17 +896,17 @@ namespace epics { { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(destroyedStatus)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(notInitializedStatus)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } } - if (!startRequest(QOS_GET)) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(otherRequestPendingStatus)); + if (!startRequest(m_lastRequest.get() ? QOS_GET | QOS_DESTROY : QOS_GET)) { + EXCEPTION_GUARD(m_channelPutRequester->getDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } @@ -893,34 +915,50 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutRequester->getDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); } } - virtual void put(bool lastRequest) { + virtual void put(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & pvPutBitSet) { { Lock guard(m_mutex); if (m_destroyed) { - m_channelPutRequester->putDone(destroyedStatus); + m_channelPutRequester->putDone(destroyedStatus, shared_from_this()); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutRequester->putDone(notInitializedStatus)); + EXCEPTION_GUARD(m_channelPutRequester->putDone(notInitializedStatus, shared_from_this())); return; } } - if (!startRequest(lastRequest ? QOS_DESTROY : QOS_DEFAULT)) { - m_channelPutRequester->putDone(otherRequestPendingStatus); + if (!(*m_structure->getStructure() == *pvPutStructure->getStructure())) + { + EXCEPTION_GUARD(m_channelPutRequester->putDone(invalidPutStructureStatus, shared_from_this())); + return; + } + + if (pvPutBitSet->size() < m_bitSet->size()) + { + EXCEPTION_GUARD(m_channelPutRequester->putDone(invalidBitSetLengthStatus, shared_from_this())); + return; + } + + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { + m_channelPutRequester->putDone(otherRequestPendingStatus, shared_from_this()); return; } try { + lock(); + m_pvPutStructure = pvPutStructure; + m_pvPutBitSet = pvPutBitSet; + unlock(); m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutRequester->putDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelPutRequester->putDone(channelNotConnected, shared_from_this())); } } @@ -934,6 +972,11 @@ namespace epics { BaseRequestImpl::destroy(); } + virtual void lastRequest() + { + BaseRequestImpl::lastRequest(); + } + virtual void lock() { m_structureMutex.lock(); @@ -963,9 +1006,18 @@ namespace epics { PVStructure::shared_pointer m_pvRequest; + // put data container PVStructure::shared_pointer m_putData; + BitSet::shared_pointer m_putDataBitSet; + + // get data container PVStructure::shared_pointer m_getData; + BitSet::shared_pointer m_getDataBitSet; + // putGet reference store + PVStructure::shared_pointer m_putPutData; + BitSet::shared_pointer m_putPutDataBitSet; + Mutex m_structureMutex; ChannelPutGetImpl(ChannelImpl::shared_pointer const & channel, ChannelPutGetRequester::shared_pointer const & channelPutGetRequester, PVStructure::shared_pointer const & pvRequest) : @@ -981,7 +1033,7 @@ namespace epics { if (m_pvRequest == 0) { ChannelPutGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(pvRequestNull, thisPointer, nullPVStructure, nullPVStructure)); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(pvRequestNull, thisPointer, nullStructure, nullStructure)); return; } @@ -991,7 +1043,7 @@ namespace epics { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { ChannelPutGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(channelDestroyed, thisPointer, nullPVStructure, nullPVStructure)); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(channelDestroyed, thisPointer, nullStructure, nullStructure)); BaseRequestImpl::destroy(true); } } @@ -1038,118 +1090,134 @@ namespace epics { { // no need to lock here, since it is already locked via TransportSender IF //Lock lock(m_structureMutex); - m_putData->serialize(buffer, control); + m_putPutDataBitSet->serialize(buffer, control); + m_putPutData->serialize(buffer, control, m_putPutDataBitSet.get()); + + // release references + m_putPutDataBitSet.reset(); + m_putPutData.reset(); } } stopRequest(); } - virtual bool destroyResponse(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { - // data available - // TODO we need a flag here... - return normalResponse(transport, version, payloadBuffer, qos, status); - } - - virtual bool initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { + virtual void initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { ChannelPutGet::shared_pointer thisChannelPutGet = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, thisChannelPutGet, nullPVStructure, nullPVStructure)); - return true; + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, thisChannelPutGet, nullStructure, nullStructure)); + return; } { Lock lock(m_structureMutex); m_putData = SerializationHelper::deserializeStructureAndCreatePVStructure(payloadBuffer, transport.get()); + m_putDataBitSet = createBitSetFor(m_putData, m_putDataBitSet); m_getData = SerializationHelper::deserializeStructureAndCreatePVStructure(payloadBuffer, transport.get()); + m_getDataBitSet = createBitSetFor(m_getData, m_getDataBitSet); } // notify ChannelPutGet::shared_pointer thisChannelPutGet = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, thisChannelPutGet, m_putData, m_getData)); - return true; + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, thisChannelPutGet, m_putData->getStructure(), m_getData->getStructure())); } - virtual bool normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (qos & QOS_GET) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status)); - return true; + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + return; } { Lock lock(m_structureMutex); // deserialize get data - m_getData->deserialize(payloadBuffer, transport.get()); + m_getDataBitSet->deserialize(payloadBuffer, transport.get()); + m_getData->deserialize(payloadBuffer, transport.get(), m_getDataBitSet.get()); } - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status)); - return true; + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status, shared_from_this(), m_getData, m_getDataBitSet)); } else if (qos & QOS_GET_PUT) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status)); - return true; + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + return; } { Lock lock(m_structureMutex); // deserialize put data - m_putData->deserialize(payloadBuffer, transport.get()); + m_putDataBitSet->deserialize(payloadBuffer, transport.get()); + m_putData->deserialize(payloadBuffer, transport.get(), m_putDataBitSet.get()); } - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status)); - return true; + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status, shared_from_this(), m_putData, m_putDataBitSet)); } else { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status)); - return true; + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + return; } { Lock lock(m_structureMutex); // deserialize data - m_getData->deserialize(payloadBuffer, transport.get()); + m_getDataBitSet->deserialize(payloadBuffer, transport.get()); + m_getData->deserialize(payloadBuffer, transport.get(), m_getDataBitSet.get()); } - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status)); - return true; + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status, shared_from_this(), m_getData, m_getDataBitSet)); } } - virtual void putGet(bool lastRequest) { + virtual void putGet(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & bitSet) { { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(destroyedStatus)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(notInitializedStatus)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } } - if (!startRequest(lastRequest ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(otherRequestPendingStatus)); + if (!(*m_putData->getStructure() == *pvPutStructure->getStructure())) + { + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidPutStructureStatus, shared_from_this(), nullPVStructure, nullBitSet)); + return; + } + + if (bitSet->size() < m_putDataBitSet->size()) + { + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidBitSetLengthStatus, shared_from_this(), nullPVStructure, nullBitSet)); + return; + } + + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } try { + lock(); + m_putPutData = pvPutStructure; + m_putPutDataBitSet = bitSet; + unlock(); m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); } } @@ -1157,17 +1225,17 @@ namespace epics { { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(destroyedStatus)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(notInitializedStatus)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } } - if (!startRequest(QOS_GET)) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(otherRequestPendingStatus)); + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET : QOS_GET)) { + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } @@ -1175,7 +1243,7 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); } } @@ -1183,17 +1251,17 @@ namespace epics { { Lock guard(m_mutex); if (m_destroyed) { - m_channelPutGetRequester->getPutDone(destroyedStatus); + m_channelPutGetRequester->getPutDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(notInitializedStatus)); + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); return; } } - if (!startRequest(QOS_GET_PUT)) { - m_channelPutGetRequester->getPutDone(otherRequestPendingStatus); + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET_PUT : QOS_GET_PUT)) { + m_channelPutGetRequester->getPutDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet); return; } @@ -1201,7 +1269,7 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); } } @@ -1215,6 +1283,11 @@ namespace epics { BaseRequestImpl::destroy(); } + virtual void lastRequest() + { + BaseRequestImpl::lastRequest(); + } + virtual void lock() { m_structureMutex.lock(); @@ -1328,55 +1401,47 @@ namespace epics { stopRequest(); } - virtual bool destroyResponse(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { - // data available - // TODO we need a flag here... - return normalResponse(transport, version, payloadBuffer, qos, status); - } - - virtual bool initResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { + virtual void initResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { ChannelRPC::shared_pointer thisChannelRPC = dynamic_pointer_cast(shared_from_this()); EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, thisChannelRPC)); - return true; + return; } // notify ChannelRPC::shared_pointer thisChannelRPC = dynamic_pointer_cast(shared_from_this()); EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, thisChannelRPC)); - return true; } - virtual bool normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { + virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, nullPVStructure)); - return true; + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, shared_from_this(), nullPVStructure)); + return; } PVStructure::shared_pointer response(SerializationHelper::deserializeStructureFull(payloadBuffer, transport.get())); - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, response)); - return true; + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, shared_from_this(), response)); } - virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument, bool lastRequest) { + virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument) { { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(destroyedStatus, nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(destroyedStatus, shared_from_this(), nullPVStructure)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(notInitializedStatus, nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(notInitializedStatus, shared_from_this(), nullPVStructure)); return; } } - if (!startRequest(lastRequest ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(otherRequestPendingStatus, nullPVStructure)); + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure)); return; } @@ -1388,7 +1453,7 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(channelNotConnected, nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(channelNotConnected, shared_from_this(), nullPVStructure)); } } @@ -1402,6 +1467,11 @@ namespace epics { BaseRequestImpl::destroy(); } + virtual void lastRequest() + { + BaseRequestImpl::lastRequest(); + } + virtual void lock() { m_structureMutex.lock(); @@ -1432,10 +1502,15 @@ namespace epics { PVStructure::shared_pointer m_pvRequest; - PVArray::shared_pointer m_structure; + // data container (for get) + PVArray::shared_pointer m_data; + // reference store (for put + PVArray::shared_pointer m_putData; + size_t m_offset; size_t m_count; + size_t m_stride; size_t m_length; size_t m_capacity; @@ -1457,7 +1532,7 @@ namespace epics { if (m_pvRequest == 0) { ChannelArray::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(pvRequestNull, thisPointer, PVArray::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(pvRequestNull, thisPointer, Array::shared_pointer())); return; } @@ -1468,7 +1543,7 @@ namespace epics { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { ChannelArray::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(channelDestroyed, thisPointer, PVArray::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(channelDestroyed, thisPointer, Array::shared_pointer())); BaseRequestImpl::destroy(true); } } @@ -1509,6 +1584,7 @@ namespace epics { // lock... see comment below SerializeHelper::writeSize(m_offset, buffer, control); SerializeHelper::writeSize(m_count, buffer, control); + SerializeHelper::writeSize(m_stride, buffer, control); } else if (pendingRequest & QOS_GET_PUT) // i.e. setLength { @@ -1516,6 +1592,10 @@ namespace epics { SerializeHelper::writeSize(m_length, buffer, control); SerializeHelper::writeSize(m_capacity, buffer, control); } + else if (pendingRequest & QOS_PROCESS) // i.e. getLength + { + // noop + } // put else { @@ -1523,87 +1603,93 @@ namespace epics { // no need to lock here, since it is already locked via TransportSender IF //Lock lock(m_structureMutex); SerializeHelper::writeSize(m_offset, buffer, control); - m_structure->serialize(buffer, control, 0, m_count ? m_count : m_structure->getLength()); // put from 0 offset (see API doc), m_count == 0 means entire array + SerializeHelper::writeSize(m_stride, buffer, control); + // TODO what about count sanity check? + m_putData->serialize(buffer, control, 0, m_count ? m_count : m_putData->getLength()); // put from 0 offset (see API doc), m_count == 0 means entire array + // release reference + m_putData.reset(); } } stopRequest(); } - virtual bool destroyResponse(Transport::shared_pointer const & transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { - // data available (get with destroy) - if (qos & QOS_GET) - return normalResponse(transport, version, payloadBuffer, qos, status); - return true; - } - - virtual bool initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { + virtual void initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, thisChannelArray, PVArray::shared_pointer())); - return true; + return; } // create data and its bitSet FieldConstPtr field = transport->cachedDeserialize(payloadBuffer); { Lock lock(m_structureMutex); - m_structure = dynamic_pointer_cast(getPVDataCreate()->createPVField(field)); + m_data = dynamic_pointer_cast(getPVDataCreate()->createPVField(field)); } // notify ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, thisChannelArray, m_structure)); - return true; + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, thisChannelArray, m_data->getArray())); } - virtual bool normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + + ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + if (qos & QOS_GET) { if (!status.isSuccess()) { - m_channelArrayRequester->getArrayDone(status); - return true; + m_channelArrayRequester->getArrayDone(status, thisChannelArray, PVArray::shared_pointer()); + return; } { Lock lock(m_structureMutex); - m_structure->deserialize(payloadBuffer, transport.get()); + m_data->deserialize(payloadBuffer, transport.get()); } - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(status)); - return true; + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(status, thisChannelArray, m_data)); } else if (qos & QOS_GET_PUT) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(status)); - return true; + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(status, thisChannelArray)); + } + else if (qos & QOS_PROCESS) + { + size_t length = SerializeHelper::readSize(payloadBuffer, transport.get()); + size_t capacity = SerializeHelper::readSize(payloadBuffer, transport.get()); + + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(status, thisChannelArray, length, capacity)); } else { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(status)); - return true; + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(status, thisChannelArray)); } } - virtual void getArray(bool lastRequest, size_t offset, size_t count) { + virtual void getArray(size_t offset, size_t count, size_t stride) { + // TODO stride == 0 check + ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(destroyedStatus)); + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(destroyedStatus, thisChannelArray, PVArray::shared_pointer())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(notInitializedStatus)); + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(notInitializedStatus, thisChannelArray, PVArray::shared_pointer())); return; } } - if (!startRequest(lastRequest ? QOS_DESTROY | QOS_GET : QOS_GET)) { - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(otherRequestPendingStatus)); + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET : QOS_GET)) { + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(otherRequestPendingStatus, thisChannelArray, PVArray::shared_pointer())); return; } @@ -1612,62 +1698,73 @@ namespace epics { Lock lock(m_structureMutex); m_offset = offset; m_count = count; + m_stride = stride; } m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(channelNotConnected, thisChannelArray, PVArray::shared_pointer())); } } - virtual void putArray(bool lastRequest, size_t offset, size_t count) { + virtual void putArray(PVArray::shared_pointer const & putArray, size_t offset, size_t count, size_t stride) { + + // TODO stride == 0 check { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(destroyedStatus)); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(destroyedStatus, shared_from_this())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(notInitializedStatus)); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(notInitializedStatus, shared_from_this())); return; } } - if (!startRequest(lastRequest ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(otherRequestPendingStatus)); + if (!(*m_data->getArray() == *putArray->getArray())) + { + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(invalidPutArrayStatus, shared_from_this())); + return; + } + + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(otherRequestPendingStatus, shared_from_this())); return; } try { { Lock lock(m_structureMutex); + m_putData = putArray; m_offset = offset; m_count = count; + m_stride = stride; } m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(channelNotConnected, shared_from_this())); } } - virtual void setLength(bool lastRequest, size_t length, size_t capacity) { + virtual void setLength(size_t length, size_t capacity) { { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(destroyedStatus)); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(destroyedStatus, shared_from_this())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(notInitializedStatus)); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(notInitializedStatus, shared_from_this())); return; } } - if (!startRequest(lastRequest ? QOS_DESTROY | QOS_GET_PUT : QOS_GET_PUT)) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(otherRequestPendingStatus)); + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET_PUT : QOS_GET_PUT)) { + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(otherRequestPendingStatus, shared_from_this())); return; } @@ -1680,7 +1777,35 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(channelNotConnected, shared_from_this())); + } + } + + + virtual void getLength() { + + { + Lock guard(m_mutex); + if (m_destroyed) { + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(destroyedStatus, shared_from_this(), 0, 0)); + return; + } + if (!m_initialized) { + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(notInitializedStatus, shared_from_this(), 0, 0)); + return; + } + } + + if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_PROCESS : QOS_PROCESS)) { + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(otherRequestPendingStatus, shared_from_this(), 0, 0)); + return; + } + + try { + m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + } catch (std::runtime_error &rte) { + stopRequest(); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(channelNotConnected, shared_from_this(), 0, 0)); } } @@ -1694,6 +1819,11 @@ namespace epics { BaseRequestImpl::destroy(); } + virtual void lastRequest() + { + BaseRequestImpl::lastRequest(); + } + virtual void lock() { m_structureMutex.lock(); @@ -2107,17 +2237,7 @@ namespace epics { stopRequest(); } - virtual bool destroyResponse( - Transport::shared_pointer const & transport, - int8 version, ByteBuffer* payloadBuffer, - int8 qos, const Status& status) - { - // data available - // TODO if (qos & QOS_GET) - return normalResponse(transport, version, payloadBuffer, qos, status); - } - - virtual bool initResponse( + virtual void initResponse( Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, @@ -2128,7 +2248,7 @@ namespace epics { { Monitor::shared_pointer thisChannelMonitor = dynamic_pointer_cast(shared_from_this()); EXCEPTION_GUARD(m_monitorRequester->monitorConnect(status, thisChannelMonitor, StructureConstPtr())); - return true; + return; } StructureConstPtr structure = @@ -2143,11 +2263,9 @@ namespace epics { if (m_started) start(); - - return true; } - virtual bool normalResponse( + virtual void normalResponse( Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, @@ -2162,7 +2280,6 @@ namespace epics { { m_ElementQueue->response(transport, payloadBuffer); } - return true; } // override, since we optimize status @@ -2194,8 +2311,7 @@ namespace epics { m_initialized = false; m_mutex.unlock(); - if (!destroyResponse(transport, version, payloadBuffer, qos, status)) - destroy(); + normalResponse(transport, version, payloadBuffer, qos, status); } else { diff --git a/pvAccessApp/rpcService/rpcServer.cpp b/pvAccessApp/rpcService/rpcServer.cpp index 8b50efa..022b961 100644 --- a/pvAccessApp/rpcService/rpcServer.cpp +++ b/pvAccessApp/rpcService/rpcServer.cpp @@ -463,6 +463,37 @@ void RPCServer::run(int seconds) m_serverContext->run(seconds); } +struct ThreadRunnerParam { + RPCServer::shared_pointer server; + int timeToRun; +}; + +static void threadRunner(void* usr) +{ + ThreadRunnerParam* pusr = static_cast(usr); + ThreadRunnerParam param = *pusr; + delete pusr; + + param.server->run(param.timeToRun); +} + +/// Method requires usage of std::tr1::shared_ptr. This instance must be +/// owned by a shared_ptr instance. +void RPCServer::runInNewThread(int seconds) +{ + std::auto_ptr param(new ThreadRunnerParam()); + param->server = rpcServer; + param->timeToRun = seconds; + + epicsThreadCreate("RPCServer thread", + epicsThreadPriorityMedium, + epicsThreadGetStackSize(epicsThreadStackSmall), + threadRunner, param.get()); + + // let the thread delete 'param' + param.release(); +} + void RPCServer::destroy() { m_serverContext->destroy(); diff --git a/pvAccessApp/rpcService/rpcServer.h b/pvAccessApp/rpcService/rpcServer.h index 53f97b2..fc102e2 100644 --- a/pvAccessApp/rpcService/rpcServer.h +++ b/pvAccessApp/rpcService/rpcServer.h @@ -27,7 +27,9 @@ namespace epics { namespace pvAccess { -class epicsShareClass RPCServer { +class epicsShareClass RPCServer : + public std::tr1::enable_shared_from_this +{ private: ServerContextImpl::shared_pointer m_serverContext; @@ -49,6 +51,10 @@ class epicsShareClass RPCServer { void run(int seconds = 0); + /// Method requires usage of std::tr1::shared_ptr. This instance must be + /// owned by a shared_ptr instance. + void runInNewThread(int seconds = 0); + void destroy(); /** From 2c4bffd8d98ac2ea9e74c5c7f4391cc237c29dcd Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Tue, 20 May 2014 09:52:57 +0200 Subject: [PATCH 07/32] client side API changes --- pvAccessApp/client/pvAccess.h | 12 +- .../remoteClient/clientContextImpl.cpp | 174 +++++++++++------- 2 files changed, 112 insertions(+), 74 deletions(-) diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index 5514610..178f08f 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -188,7 +188,7 @@ namespace pvAccess { virtual void channelArrayConnect( const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray, - epics::pvData::Array::shared_pointer const & array) = 0; + epics::pvData::Array::const_shared_pointer const & array) = 0; /** * The request is done. This is always called with no locks held. @@ -294,7 +294,7 @@ namespace pvAccess { virtual void channelGetConnect( const epics::pvData::Status& status, ChannelGet::shared_pointer const & channelGet, - epics::pvData::Structure::shared_pointer const & structure) = 0; + epics::pvData::Structure::const_shared_pointer const & structure) = 0; /** * The request is done. This is always called with no locks held. @@ -357,7 +357,7 @@ namespace pvAccess { /** * Interface for a channel access put request. */ - class epicsShareClass ChannelPut : public ChannelRequest { + class epicsShareClass ChannelPut : public ChannelRequest { public: POINTER_DEFINITIONS(ChannelPut); @@ -394,7 +394,7 @@ namespace pvAccess { virtual void channelPutConnect( const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut, - epics::pvData::Structure::shared_pointer const & structure) = 0; + epics::pvData::Structure::const_shared_pointer const & structure) = 0; /** * The request is done. This is always called with no locks held. @@ -470,8 +470,8 @@ namespace pvAccess { virtual void channelPutGetConnect( const epics::pvData::Status& status, ChannelPutGet::shared_pointer const & channelPutGet, - epics::pvData::Structure::shared_pointer const & putStructure, - epics::pvData::Structure::shared_pointer const & getStructure) = 0; + epics::pvData::Structure::const_shared_pointer const & putStructure, + epics::pvData::Structure::const_shared_pointer const & getStructure) = 0; /** * The putGet request is done. This is always called with no locks held. diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index a1d7a3b..f9f6f11 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -477,25 +477,28 @@ namespace epics { } virtual void normalResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { - EXCEPTION_GUARD(m_callback->processDone(status, shared_from_this())); + ChannelProcess::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + EXCEPTION_GUARD(m_callback->processDone(status, thisPtr)); } virtual void process() { + ChannelProcess::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_callback->processDone(destroyedStatus, shared_from_this())); + EXCEPTION_GUARD(m_callback->processDone(destroyedStatus, thisPtr)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_callback->processDone(notInitializedStatus, shared_from_this())); + EXCEPTION_GUARD(m_callback->processDone(notInitializedStatus, thisPtr)); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_callback->processDone(otherRequestPendingStatus, shared_from_this())); + EXCEPTION_GUARD(m_callback->processDone(otherRequestPendingStatus, thisPtr)); return; } @@ -503,7 +506,7 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_callback->processDone(channelNotConnected, shared_from_this())); + EXCEPTION_GUARD(m_callback->processDone(channelNotConnected, thisPtr)); } } @@ -649,9 +652,11 @@ namespace epics { MB_POINT(channelGet, 8, "client channelGet->deserialize (start)"); + ChannelGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(status, thisPtr, nullPVStructure, nullBitSet)); return; } @@ -664,22 +669,24 @@ namespace epics { MB_POINT(channelGet, 9, "client channelGet->deserialize (end), just before channelGet->getDone() is called"); - EXCEPTION_GUARD(m_channelGetRequester->getDone(status, shared_from_this(), m_structure, m_bitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(status, thisPtr, m_structure, m_bitSet)); } virtual void get() { - { - MB_INC_AUTO_ID(channelGet); - MB_POINT(channelGet, 0, "client channelGet->get()"); + MB_INC_AUTO_ID(channelGet); + MB_POINT(channelGet, 0, "client channelGet->get()"); + ChannelGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); return; } } @@ -691,13 +698,13 @@ namespace epics { m_channel->checkAndGetTransport()->flushSendQueue(); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelGetRequester->getDone(channelNotConnected)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(channelNotConnected, thisPtr)); } return; } */ if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet)); return; } @@ -706,7 +713,7 @@ namespace epics { //TODO bulk hack m_channel->checkAndGetTransport()->enqueueOnlySendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelGetRequester->getDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); } } @@ -869,11 +876,14 @@ namespace epics { } virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + + ChannelPut::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + if (qos & QOS_GET) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(status, thisPtr, nullPVStructure, nullBitSet)); return; } @@ -883,30 +893,32 @@ namespace epics { m_structure->deserialize(payloadBuffer, transport.get(), m_bitSet.get()); } - EXCEPTION_GUARD(m_channelPutRequester->getDone(status, shared_from_this(), m_structure, m_bitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(status, thisPtr, m_structure, m_bitSet)); } else { - EXCEPTION_GUARD(m_channelPutRequester->putDone(status, shared_from_this())); + EXCEPTION_GUARD(m_channelPutRequester->putDone(status, thisPtr)); } } virtual void get() { + ChannelPut::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); return; } } if (!startRequest(m_lastRequest.get() ? QOS_GET | QOS_DESTROY : QOS_GET)) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet)); return; } @@ -915,38 +927,40 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutRequester->getDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); } } virtual void put(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & pvPutBitSet) { + ChannelPut::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - m_channelPutRequester->putDone(destroyedStatus, shared_from_this()); + m_channelPutRequester->putDone(destroyedStatus, thisPtr); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutRequester->putDone(notInitializedStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelPutRequester->putDone(notInitializedStatus, thisPtr)); return; } } if (!(*m_structure->getStructure() == *pvPutStructure->getStructure())) { - EXCEPTION_GUARD(m_channelPutRequester->putDone(invalidPutStructureStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelPutRequester->putDone(invalidPutStructureStatus, thisPtr)); return; } if (pvPutBitSet->size() < m_bitSet->size()) { - EXCEPTION_GUARD(m_channelPutRequester->putDone(invalidBitSetLengthStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelPutRequester->putDone(invalidBitSetLengthStatus, thisPtr)); return; } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { - m_channelPutRequester->putDone(otherRequestPendingStatus, shared_from_this()); + m_channelPutRequester->putDone(otherRequestPendingStatus, thisPtr); return; } @@ -958,7 +972,7 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutRequester->putDone(channelNotConnected, shared_from_this())); + EXCEPTION_GUARD(m_channelPutRequester->putDone(channelNotConnected, thisPtr)); } } @@ -1125,11 +1139,14 @@ namespace epics { virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + + ChannelPutGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + if (qos & QOS_GET) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status, thisPtr, nullPVStructure, nullBitSet)); return; } @@ -1140,13 +1157,13 @@ namespace epics { m_getData->deserialize(payloadBuffer, transport.get(), m_getDataBitSet.get()); } - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status, shared_from_this(), m_getData, m_getDataBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status, thisPtr, m_getData, m_getDataBitSet)); } else if (qos & QOS_GET_PUT) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status, thisPtr, nullPVStructure, nullBitSet)); return; } @@ -1157,13 +1174,13 @@ namespace epics { m_putData->deserialize(payloadBuffer, transport.get(), m_putDataBitSet.get()); } - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status, shared_from_this(), m_putData, m_putDataBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status, thisPtr, m_putData, m_putDataBitSet)); } else { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status, thisPtr, nullPVStructure, nullBitSet)); return; } @@ -1174,38 +1191,41 @@ namespace epics { m_getData->deserialize(payloadBuffer, transport.get(), m_getDataBitSet.get()); } - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status, shared_from_this(), m_getData, m_getDataBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status, thisPtr, m_getData, m_getDataBitSet)); } } virtual void putGet(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & bitSet) { + + ChannelPutGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); return; } } if (!(*m_putData->getStructure() == *pvPutStructure->getStructure())) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidPutStructureStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidPutStructureStatus, thisPtr, nullPVStructure, nullBitSet)); return; } if (bitSet->size() < m_putDataBitSet->size()) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidBitSetLengthStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidBitSetLengthStatus, thisPtr, nullPVStructure, nullBitSet)); return; } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet)); return; } @@ -1217,25 +1237,28 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); } } virtual void getGet() { + + ChannelPutGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET : QOS_GET)) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet)); return; } @@ -1243,25 +1266,28 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); } } virtual void getPut() { + + ChannelPutGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - m_channelPutGetRequester->getPutDone(destroyedStatus, shared_from_this(), nullPVStructure, nullBitSet); + m_channelPutGetRequester->getPutDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(notInitializedStatus, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET_PUT : QOS_GET_PUT)) { - m_channelPutGetRequester->getPutDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure, nullBitSet); + m_channelPutGetRequester->getPutDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet); return; } @@ -1269,7 +1295,7 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(channelNotConnected, shared_from_this(), nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); } } @@ -1415,33 +1441,38 @@ namespace epics { } virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { + + ChannelRPC::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, shared_from_this(), nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, thisPtr, nullPVStructure)); return; } PVStructure::shared_pointer response(SerializationHelper::deserializeStructureFull(payloadBuffer, transport.get())); - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, shared_from_this(), response)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, thisPtr, response)); } virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument) { + ChannelRPC::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(destroyedStatus, shared_from_this(), nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(destroyedStatus, thisPtr, nullPVStructure)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(notInitializedStatus, shared_from_this(), nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(notInitializedStatus, thisPtr, nullPVStructure)); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(otherRequestPendingStatus, shared_from_this(), nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(otherRequestPendingStatus, thisPtr, nullPVStructure)); return; } @@ -1453,7 +1484,7 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(channelNotConnected, shared_from_this(), nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(channelNotConnected, thisPtr, nullPVStructure)); } } @@ -1618,7 +1649,7 @@ namespace epics { if (!status.isSuccess()) { ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, thisChannelArray, PVArray::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, thisChannelArray, Array::shared_pointer())); return; } @@ -1674,6 +1705,7 @@ namespace epics { virtual void getArray(size_t offset, size_t count, size_t stride) { // TODO stride == 0 check + ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); { @@ -1711,26 +1743,28 @@ namespace epics { // TODO stride == 0 check + ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(destroyedStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(destroyedStatus, thisChannelArray)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(notInitializedStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(notInitializedStatus, thisChannelArray)); return; } } if (!(*m_data->getArray() == *putArray->getArray())) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(invalidPutArrayStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(invalidPutArrayStatus, thisChannelArray)); return; } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(otherRequestPendingStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(otherRequestPendingStatus, thisChannelArray)); return; } @@ -1745,26 +1779,28 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(channelNotConnected, shared_from_this())); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(channelNotConnected, thisChannelArray)); } } virtual void setLength(size_t length, size_t capacity) { + ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(destroyedStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(destroyedStatus, thisChannelArray)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(notInitializedStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(notInitializedStatus, thisChannelArray)); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET_PUT : QOS_GET_PUT)) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(otherRequestPendingStatus, shared_from_this())); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(otherRequestPendingStatus, thisChannelArray)); return; } @@ -1777,27 +1813,29 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(channelNotConnected, shared_from_this())); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(channelNotConnected, thisChannelArray)); } } virtual void getLength() { + ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(destroyedStatus, shared_from_this(), 0, 0)); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(destroyedStatus, thisChannelArray, 0, 0)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(notInitializedStatus, shared_from_this(), 0, 0)); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(notInitializedStatus, thisChannelArray, 0, 0)); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_PROCESS : QOS_PROCESS)) { - EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(otherRequestPendingStatus, shared_from_this(), 0, 0)); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(otherRequestPendingStatus, thisChannelArray, 0, 0)); return; } @@ -1805,7 +1843,7 @@ namespace epics { m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(channelNotConnected, shared_from_this(), 0, 0)); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(channelNotConnected, thisChannelArray, 0, 0)); } } From 6ae61258ca39630cc1ae9e38130e99742fe8ec64 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Wed, 21 May 2014 12:01:02 +0200 Subject: [PATCH 08/32] work on server API changes --- pvAccessApp/rpcClient/rpcClient.cpp | 10 +- pvAccessApp/rpcService/rpcServer.cpp | 35 ++-- pvAccessApp/server/responseHandlers.cpp | 268 +++++++++++++++++------- pvAccessApp/server/responseHandlers.h | 78 +++++-- pvAccessApp/server/serverContext.cpp | 28 +-- pvAccessApp/server/serverContext.h | 16 +- 6 files changed, 302 insertions(+), 133 deletions(-) diff --git a/pvAccessApp/rpcClient/rpcClient.cpp b/pvAccessApp/rpcClient/rpcClient.cpp index 32f6bf3..1c8b1b3 100644 --- a/pvAccessApp/rpcClient/rpcClient.cpp +++ b/pvAccessApp/rpcClient/rpcClient.cpp @@ -73,7 +73,7 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester std::cerr << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } - virtual void channelRPCConnect(const epics::pvData::Status& status,ChannelRPC::shared_pointer const & channelRPC) + virtual void channelRPCConnect(const epics::pvData::Status& status, ChannelRPC::shared_pointer const & channelRPC) { if (status.isSuccess()) { @@ -97,7 +97,8 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester } } - virtual void requestDone (const epics::pvData::Status &status, epics::pvData::PVStructure::shared_pointer const &pvResponse) + virtual void requestDone(const epics::pvData::Status &status, ChannelRPC::shared_pointer const & /*channelRPC*/, + epics::pvData::PVStructure::shared_pointer const &pvResponse) { if (status.isSuccess()) { @@ -214,7 +215,7 @@ private: void init() { using namespace std::tr1; - m_provider = getChannelAccess()->getProvider("pva"); + m_provider = getChannelProviderRegistry()->getProvider("pva"); shared_ptr channelRequesterImpl(new ChannelRequesterImpl()); m_channelRequesterImpl = channelRequesterImpl; @@ -253,7 +254,8 @@ PVStructure::shared_pointer RPCClientImpl::request(PVStructure::shared_pointer p if (rpcRequesterImpl->waitUntilConnected(timeOut)) { - channelRPC->request(pvRequest, true); + channelRPC->lastRequest(); + channelRPC->request(pvRequest); allOK &= rpcRequesterImpl->waitUntilRPC(timeOut); response = rpcRequesterImpl->response; } diff --git a/pvAccessApp/rpcService/rpcServer.cpp b/pvAccessApp/rpcService/rpcServer.cpp index 022b961..2a38379 100644 --- a/pvAccessApp/rpcService/rpcServer.cpp +++ b/pvAccessApp/rpcService/rpcServer.cpp @@ -14,18 +14,22 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { -class ChannelRPCServiceImpl : public ChannelRPC +class ChannelRPCServiceImpl : + public ChannelRPC, + public std::tr1::enable_shared_from_this { private: ChannelRPCRequester::shared_pointer m_channelRPCRequester; RPCService::shared_pointer m_rpcService; + AtomicBoolean m_lastRequest; public: ChannelRPCServiceImpl( ChannelRPCRequester::shared_pointer const & channelRPCRequester, RPCService::shared_pointer const & rpcService) : m_channelRPCRequester(channelRPCRequester), - m_rpcService(rpcService) + m_rpcService(rpcService), + m_lastRequest() { } @@ -34,7 +38,7 @@ class ChannelRPCServiceImpl : public ChannelRPC destroy(); } - void processRequest(epics::pvData::PVStructure::shared_pointer const & pvArgument, bool lastRequest) + void processRequest(epics::pvData::PVStructure::shared_pointer const & pvArgument) { epics::pvData::PVStructure::shared_pointer result; Status status = Status::Ok; @@ -66,18 +70,23 @@ class ChannelRPCServiceImpl : public ChannelRPC status = Status(Status::STATUSTYPE_FATAL, "RPCService.request(PVStructure) returned null."); } - m_channelRPCRequester->requestDone(status, result); + m_channelRPCRequester->requestDone(status, shared_from_this(), result); - if (lastRequest) + if (m_lastRequest.get()) destroy(); } - virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument, bool lastRequest) + virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument) { - processRequest(pvArgument, lastRequest); + processRequest(pvArgument); } + void lastRequest() + { + m_lastRequest.set(); + } + virtual void cancel() { // noop @@ -197,7 +206,7 @@ public: { ChannelGet::shared_pointer nullPtr; channelGetRequester->channelGetConnect(notSupportedStatus, nullPtr, - epics::pvData::PVStructure::shared_pointer(), epics::pvData::BitSet::shared_pointer()); + epics::pvData::Structure::const_shared_pointer()); return nullPtr; } @@ -207,7 +216,7 @@ public: { ChannelPut::shared_pointer nullPtr; channelPutRequester->channelPutConnect(notSupportedStatus, nullPtr, - epics::pvData::PVStructure::shared_pointer(), epics::pvData::BitSet::shared_pointer()); + epics::pvData::Structure::const_shared_pointer()); return nullPtr; } @@ -217,7 +226,7 @@ public: epics::pvData::PVStructure::shared_pointer const & /*pvRequest*/) { ChannelPutGet::shared_pointer nullPtr; - epics::pvData::PVStructure::shared_pointer nullStructure; + epics::pvData::Structure::const_shared_pointer nullStructure; channelPutGetRequester->channelPutGetConnect(notSupportedStatus, nullPtr, nullStructure, nullStructure); return nullPtr; } @@ -257,7 +266,7 @@ public: epics::pvData::PVStructure::shared_pointer const & /*pvRequest*/) { ChannelArray::shared_pointer nullPtr; - channelArrayRequester->channelArrayConnect(notSupportedStatus, nullPtr, epics::pvData::PVArray::shared_pointer()); + channelArrayRequester->channelArrayConnect(notSupportedStatus, nullPtr, epics::pvData::Array::const_shared_pointer()); return nullPtr; } @@ -443,7 +452,7 @@ RPCServer::RPCServer() m_serverContext = ServerContextImpl::create(); m_serverContext->setChannelProviderName(m_channelProviderImpl->getProviderName()); - m_serverContext->initialize(getChannelAccess()); + m_serverContext->initialize(getChannelProviderRegistry()); } RPCServer::~RPCServer() @@ -482,7 +491,7 @@ static void threadRunner(void* usr) void RPCServer::runInNewThread(int seconds) { std::auto_ptr param(new ThreadRunnerParam()); - param->server = rpcServer; + param->server = shared_from_this(); param->timeToRun = seconds; epicsThreadCreate("RPCServer thread", diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index 4d8fb56..3dbab5e 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -29,6 +30,38 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { +// TODO this is a copy from clientContextImpl.cpp + static PVDataCreatePtr pvDataCreate = getPVDataCreate(); + + + static BitSet::shared_pointer createBitSetFor( + PVStructure::shared_pointer const & pvStructure, + BitSet::shared_pointer const & existingBitSet) + { + int pvStructureSize = pvStructure->getNumberFields(); + if (existingBitSet.get() && static_cast(existingBitSet->size()) >= pvStructureSize) + { + // clear existing BitSet + // also necessary if larger BitSet is reused + existingBitSet->clear(); + return existingBitSet; + } + else + return BitSet::shared_pointer(new BitSet(pvStructureSize)); + } + + static PVField::shared_pointer reuseOrCreatePVField( + Field::const_shared_pointer const & field, + PVField::shared_pointer const & existingPVField) + { + if (existingPVField.get() && *field == *existingPVField->getField()) + return existingPVField; + else + return pvDataCreate->createPVField(field); + } + + + void ServerBadResponse::handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer const & transport, int8 version, int8 command, size_t payloadSize, ByteBuffer* payloadBuffer) @@ -574,7 +607,9 @@ void ServerGetHandler::handleResponse(osiSockAddr* responseFrom, MB_POINT(channelGet, 4, "server channelGet->deserialize request (end)"); - request->getChannelGet()->get(lastRequest); + if (lastRequest) + request->getChannelGet()->lastRequest(); + request->getChannelGet()->get(); } } @@ -609,7 +644,7 @@ void ServerGetHandler::handleResponse(osiSockAddr* responseFrom, } ServerChannelGetRequesterImpl::ServerChannelGetRequesterImpl(ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel, const pvAccessID ioid, Transport::shared_pointer const & transport) : - BaseChannelRequester(context, channel, ioid, transport), _channelGet(), _bitSet(), _pvStructure() + BaseChannelRequester(context, channel, ioid, transport) { } @@ -631,14 +666,13 @@ void ServerChannelGetRequesterImpl::activate(PVStructure::shared_pointer const & INIT_EXCEPTION_GUARD(CMD_GET, _channelGet = _channel->getChannel()->createChannelGet(thisPointer, pvRequest)); } -void ServerChannelGetRequesterImpl::channelGetConnect(const Status& status, ChannelGet::shared_pointer const & channelGet, PVStructure::shared_pointer const & pvStructure, BitSet::shared_pointer const & bitSet) +void ServerChannelGetRequesterImpl::channelGetConnect(const Status& status, ChannelGet::shared_pointer const & channelGet, Structure::const_shared_pointer const & structure) { { Lock guard(_mutex); - _bitSet = bitSet; - _pvStructure = pvStructure; _status = status; _channelGet = channelGet; + _structure = structure; } TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -650,12 +684,15 @@ void ServerChannelGetRequesterImpl::channelGetConnect(const Status& status, Chan } } -void ServerChannelGetRequesterImpl::getDone(const Status& status) +void ServerChannelGetRequesterImpl::getDone(const Status& status, ChannelGet::shared_pointer const & /*channelGet*/, + PVStructure::shared_pointer const & pvStructure, BitSet::shared_pointer const & bitSet) { MB_POINT(channelGet, 5, "server channelGet->getDone()"); { Lock guard(_mutex); _status = status; + _pvStructure = pvStructure; + _bitSet = bitSet; } TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -687,12 +724,12 @@ ChannelGet::shared_pointer ServerChannelGetRequesterImpl::getChannelGet() void ServerChannelGetRequesterImpl::lock() { - //noop + // noop } void ServerChannelGetRequesterImpl::unlock() { - //noop + // noop } void ServerChannelGetRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) @@ -719,18 +756,20 @@ void ServerChannelGetRequesterImpl::send(ByteBuffer* buffer, TransportSendContro if (request & QOS_INIT) { Lock guard(_mutex); - control->cachedSerialize(_pvStructure != NULL ? _pvStructure->getField() : FieldConstPtr(), buffer); - + control->cachedSerialize(_structure, buffer); } else { MB_POINT(channelGet, 6, "server channelGet->serialize response (start)"); { - // we locked _mutex above, so _channelGet is valid - ScopedLock lock(_channelGet); - - _bitSet->serialize(buffer, control); - _pvStructure->serialize(buffer, control, _bitSet.get()); + // we locked _mutex above, so _channelGet is valid + ScopedLock lock(_channelGet); + + _bitSet->serialize(buffer, control); + _pvStructure->serialize(buffer, control, _bitSet.get()); + + _pvStructure.reset(); + _bitSet.reset(); } MB_POINT(channelGet, 7, "server channelGet->serialize response (end)"); } @@ -796,33 +835,40 @@ void ServerPutHandler::handleResponse(osiSockAddr* responseFrom, return; } + ChannelPut::shared_pointer channelPut = request->getChannelPut(); + + if (lastRequest) + channelPut->lastRequest(); + if (get) { // no destroy w/ get - request->getChannelPut()->get(); + channelPut->get(); } else { // deserialize bitSet and do a put - ChannelPut::shared_pointer channelPut = request->getChannelPut(); + { ScopedLock lock(channelPut); // TODO not needed if put is processed by the same thread - BitSet::shared_pointer putBitSet = request->getBitSet(); + BitSet::shared_pointer putBitSet = request->getPutBitSet(); + PVStructure::shared_pointer putPVStructure = request->getPutPVStructure(); DESERIALIZE_EXCEPTION_GUARD( putBitSet->deserialize(payloadBuffer, transport.get()); - request->getPVStructure()->deserialize(payloadBuffer, transport.get(), putBitSet.get()); + putPVStructure->deserialize(payloadBuffer, transport.get(), putBitSet.get()); ); - + + lock.unlock(); + channelPut->put(putPVStructure, putBitSet); } - channelPut->put(lastRequest); } } } ServerChannelPutRequesterImpl::ServerChannelPutRequesterImpl(ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel, const pvAccessID ioid, Transport::shared_pointer const & transport): - BaseChannelRequester(context, channel, ioid, transport), _channelPut(), _bitSet(), _pvStructure() + BaseChannelRequester(context, channel, ioid, transport) { } @@ -843,15 +889,17 @@ void ServerChannelPutRequesterImpl::activate(PVStructure::shared_pointer const & INIT_EXCEPTION_GUARD(CMD_PUT, _channelPut = _channel->getChannel()->createChannelPut(thisPointer, pvRequest)); } -void ServerChannelPutRequesterImpl::channelPutConnect(const Status& status, ChannelPut::shared_pointer const & channelPut, PVStructure::shared_pointer const & pvStructure, BitSet::shared_pointer const & bitSet) +void ServerChannelPutRequesterImpl::channelPutConnect(const Status& status, ChannelPut::shared_pointer const & channelPut, Structure::const_shared_pointer const & structure) { { Lock guard(_mutex); - _bitSet = bitSet; - _pvStructure = pvStructure; _status = status; _channelPut = channelPut; + _structure = structure; } + + _putPVStructure = std::tr1::static_pointer_cast(reuseOrCreatePVField(_structure, _putPVStructure)); + _putBitSet = createBitSetFor(_putPVStructure, _putBitSet); TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -863,7 +911,7 @@ void ServerChannelPutRequesterImpl::channelPutConnect(const Status& status, Chan } } -void ServerChannelPutRequesterImpl::putDone(const Status& status) +void ServerChannelPutRequesterImpl::putDone(const Status& status, ChannelPut::shared_pointer const & /*channelPut*/) { { Lock guard(_mutex); @@ -873,11 +921,13 @@ void ServerChannelPutRequesterImpl::putDone(const Status& status) _transport->enqueueSendRequest(thisSender); } -void ServerChannelPutRequesterImpl::getDone(const Status& status) +void ServerChannelPutRequesterImpl::getDone(const Status& status, ChannelPut::shared_pointer const & /*channelPut*/, PVStructure::shared_pointer const & pvStructure, BitSet::shared_pointer const & bitSet) { { Lock guard(_mutex); _status = status; + _pvStructure = pvStructure; + _bitSet = bitSet; } TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -918,16 +968,16 @@ ChannelPut::shared_pointer ServerChannelPutRequesterImpl::getChannelPut() return _channelPut; } -BitSet::shared_pointer ServerChannelPutRequesterImpl::getBitSet() +BitSet::shared_pointer ServerChannelPutRequesterImpl::getPutBitSet() { //Lock guard(_mutex); - return _bitSet; + return _putBitSet; } -PVStructure::shared_pointer ServerChannelPutRequesterImpl::getPVStructure() +PVStructure::shared_pointer ServerChannelPutRequesterImpl::getPutPVStructure() { //Lock guard(_mutex); - return _pvStructure; + return _putPVStructure; } void ServerChannelPutRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) @@ -947,12 +997,13 @@ void ServerChannelPutRequesterImpl::send(ByteBuffer* buffer, TransportSendContro if ((QOS_INIT & request) != 0) { Lock guard(_mutex); - control->cachedSerialize(_pvStructure != NULL ? _pvStructure->getField() : FieldConstPtr(), buffer); + control->cachedSerialize(_structure, buffer); } else if ((QOS_GET & request) != 0) { ScopedLock lock(_channelPut); // _channelPut is valid because we required _mutex above - _pvStructure->serialize(buffer, control); + _bitSet->serialize(buffer, control); + _pvStructure->serialize(buffer, control, _bitSet.get()); } } @@ -1016,26 +1067,34 @@ void ServerPutGetHandler::handleResponse(osiSockAddr* responseFrom, return; } + ChannelPutGet::shared_pointer channelPutGet = request->getChannelPutGet(); + if (lastRequest) + channelPutGet->lastRequest(); + if (getGet) { - request->getChannelPutGet()->getGet(); + channelPutGet->getGet(); } else if(getPut) { - request->getChannelPutGet()->getPut(); + channelPutGet->getPut(); } else { // deserialize bitSet and do a put - ChannelPutGet::shared_pointer channelPutGet = request->getChannelPutGet(); { ScopedLock lock(channelPutGet); // TODO not necessary if read is done in putGet + BitSet::shared_pointer putBitSet = request->getPutGetBitSet(); + PVStructure::shared_pointer putPVStructure = request->getPutGetPVStructure(); DESERIALIZE_EXCEPTION_GUARD( - request->getPVPutStructure()->deserialize(payloadBuffer, transport.get()); - ); + putBitSet->deserialize(payloadBuffer, transport.get()); + putPVStructure->deserialize(payloadBuffer, transport.get(), putBitSet.get()); + ); + + lock.unlock(); + channelPutGet->putGet(putPVStructure, putBitSet); } - channelPutGet->putGet(lastRequest); } } } @@ -1064,15 +1123,18 @@ void ServerChannelPutGetRequesterImpl::activate(PVStructure::shared_pointer cons } void ServerChannelPutGetRequesterImpl::channelPutGetConnect(const Status& status, ChannelPutGet::shared_pointer const & channelPutGet, - PVStructure::shared_pointer const & pvPutStructure, PVStructure::shared_pointer const & pvGetStructure) + Structure::const_shared_pointer const & putStructure, Structure::const_shared_pointer const & getStructure) { { Lock guard(_mutex); - _pvPutStructure = pvPutStructure; - _pvGetStructure = pvGetStructure; _status = status; _channelPutGet = channelPutGet; + _putStructure = putStructure; + _getStructure = getStructure; } + + _pvPutGetStructure = std::tr1::static_pointer_cast(reuseOrCreatePVField(_putStructure, _pvPutGetStructure)); + _pvPutGetBitSet = createBitSetFor(_pvPutGetStructure, _pvPutGetBitSet); TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -1084,31 +1146,40 @@ void ServerChannelPutGetRequesterImpl::channelPutGetConnect(const Status& status } } -void ServerChannelPutGetRequesterImpl::getGetDone(const Status& status) +void ServerChannelPutGetRequesterImpl::getGetDone(const Status& status, ChannelPutGet::shared_pointer const & /*channelPutGet*/, + PVStructure::shared_pointer const & pvStructure, BitSet::shared_pointer const & bitSet) { { Lock guard(_mutex); _status = status; + _pvGetStructure = pvStructure; + _pvGetBitSet = bitSet; } TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); } -void ServerChannelPutGetRequesterImpl::getPutDone(const Status& status) +void ServerChannelPutGetRequesterImpl::getPutDone(const Status& status, ChannelPutGet::shared_pointer const & /*channelPutGet*/, + PVStructure::shared_pointer const & pvStructure, BitSet::shared_pointer const & bitSet) { { Lock guard(_mutex); _status = status; + _pvPutStructure = pvStructure; + _pvPutBitSet = bitSet; } TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); } -void ServerChannelPutGetRequesterImpl::putGetDone(const Status& status) +void ServerChannelPutGetRequesterImpl::putGetDone(const Status& status, ChannelPutGet::shared_pointer const & /*channelPutGet*/, + PVStructure::shared_pointer const & pvStructure, BitSet::shared_pointer const & bitSet) { { Lock guard(_mutex); _status = status; + _pvGetStructure = pvStructure; + _pvGetBitSet = bitSet; } TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -1116,12 +1187,12 @@ void ServerChannelPutGetRequesterImpl::putGetDone(const Status& status) void ServerChannelPutGetRequesterImpl::lock() { - //noop + // noop } void ServerChannelPutGetRequesterImpl::unlock() { - //noop + // noop } void ServerChannelPutGetRequesterImpl::destroy() @@ -1149,10 +1220,16 @@ ChannelPutGet::shared_pointer ServerChannelPutGetRequesterImpl::getChannelPutGet return _channelPutGet; } -PVStructure::shared_pointer ServerChannelPutGetRequesterImpl::getPVPutStructure() +PVStructure::shared_pointer ServerChannelPutGetRequesterImpl::getPutGetPVStructure() { //Lock guard(_mutex); - return _pvPutStructure; + return _pvPutGetStructure; +} + +BitSet::shared_pointer ServerChannelPutGetRequesterImpl::getPutGetBitSet() +{ + //Lock guard(_mutex); + return _pvPutGetBitSet; } void ServerChannelPutGetRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) @@ -1172,25 +1249,28 @@ void ServerChannelPutGetRequesterImpl::send(ByteBuffer* buffer, TransportSendCon if ((QOS_INIT & request) != 0) { Lock guard(_mutex); - control->cachedSerialize(_pvPutStructure != NULL ? _pvPutStructure->getField() : FieldConstPtr(), buffer); - control->cachedSerialize(_pvGetStructure != NULL ? _pvGetStructure->getField() : FieldConstPtr(), buffer); + control->cachedSerialize(_putStructure, buffer); + control->cachedSerialize(_getStructure, buffer); } else if ((QOS_GET & request) != 0) { Lock guard(_mutex); - _pvGetStructure->serialize(buffer, control); + _pvGetBitSet->serialize(buffer, control); + _pvGetStructure->serialize(buffer, control, _pvGetBitSet.get()); } else if ((QOS_GET_PUT & request) != 0) { ScopedLock lock(_channelPutGet); // valid due to _mutex lock above //Lock guard(_mutex); - _pvPutStructure->serialize(buffer, control); + _pvPutBitSet->serialize(buffer, control); + _pvPutStructure->serialize(buffer, control, _pvPutBitSet.get()); } else { ScopedLock lock(_channelPutGet); // valid due to _mutex lock above //Lock guard(_mutex); - _pvGetStructure->serialize(buffer, control); + _pvGetBitSet->serialize(buffer, control); + _pvGetStructure->serialize(buffer, control, _pvGetBitSet.get()); } } @@ -1465,6 +1545,7 @@ void ServerArrayHandler::handleResponse(osiSockAddr* responseFrom, const bool lastRequest = (QOS_DESTROY & qosCode) != 0; const bool get = (QOS_GET & qosCode) != 0; const bool setLength = (QOS_GET_PUT & qosCode) != 0; + const bool getLength = (QOS_PROCESS & qosCode) != 0; ServerChannelArrayRequesterImpl::shared_pointer request = static_pointer_cast(channel->getRequest(ioid)); if (request == NULL) @@ -1479,34 +1560,43 @@ void ServerArrayHandler::handleResponse(osiSockAddr* responseFrom, return; } - + ChannelArray::shared_pointer channelArray = request->getChannelArray(); + if (lastRequest) + channelArray->lastRequest(); + if (get) { size_t offset = SerializeHelper::readSize(payloadBuffer, transport.get()); size_t count = SerializeHelper::readSize(payloadBuffer, transport.get()); - request->getChannelArray()->getArray(lastRequest, offset, count); + size_t stride = SerializeHelper::readSize(payloadBuffer, transport.get()); + request->getChannelArray()->getArray(offset, count, stride); } else if (setLength) { size_t length = SerializeHelper::readSize(payloadBuffer, transport.get()); size_t capacity = SerializeHelper::readSize(payloadBuffer, transport.get()); - request->getChannelArray()->setLength(lastRequest, length, capacity); + request->getChannelArray()->setLength(length, capacity); + } + else if (getLength) + { + request->getChannelArray()->getLength(); } else { // deserialize data to put size_t offset; - ChannelArray::shared_pointer channelArray = request->getChannelArray(); + size_t stride; PVArray::shared_pointer array = request->getPVArray(); { ScopedLock lock(channelArray); // TODO not needed if read by the same thread DESERIALIZE_EXCEPTION_GUARD( offset = SerializeHelper::readSize(payloadBuffer, transport.get()); + stride = SerializeHelper::readSize(payloadBuffer, transport.get()); array->deserialize(payloadBuffer, transport.get()); ); } - channelArray->putArray(lastRequest, offset, array->getLength()); + channelArray->putArray(array, offset, array->getLength(), stride); } } } @@ -1536,14 +1626,17 @@ void ServerChannelArrayRequesterImpl::activate(PVStructure::shared_pointer const INIT_EXCEPTION_GUARD(CMD_ARRAY, _channelArray = _channel->getChannel()->createChannelArray(thisPointer, pvRequest)); } -void ServerChannelArrayRequesterImpl::channelArrayConnect(const Status& status, ChannelArray::shared_pointer const & channelArray, PVArray::shared_pointer const & pvArray) +void ServerChannelArrayRequesterImpl::channelArrayConnect(const Status& status, ChannelArray::shared_pointer const & channelArray, Array::const_shared_pointer const & array) { { Lock guard(_mutex); _status = status; - _pvArray = pvArray; _channelArray = channelArray; + _array = array; } + + _pvArray = std::tr1::static_pointer_cast(reuseOrCreatePVField(_array, _pvArray)); + TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -1554,7 +1647,18 @@ void ServerChannelArrayRequesterImpl::channelArrayConnect(const Status& status, } } -void ServerChannelArrayRequesterImpl::getArrayDone(const Status& status) +void ServerChannelArrayRequesterImpl::getArrayDone(const Status& status, ChannelArray::shared_pointer const & /*channelArray*/, PVArray::shared_pointer const & pvArray) +{ + { + Lock guard(_mutex); + _status = status; + _pvArray = pvArray; + } + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); +} + +void ServerChannelArrayRequesterImpl::putArrayDone(const Status& status, ChannelArray::shared_pointer const & /*channelArray*/) { { Lock guard(_mutex); @@ -1564,7 +1668,7 @@ void ServerChannelArrayRequesterImpl::getArrayDone(const Status& status) _transport->enqueueSendRequest(thisSender); } -void ServerChannelArrayRequesterImpl::putArrayDone(const Status& status) +void ServerChannelArrayRequesterImpl::setLengthDone(const Status& status, ChannelArray::shared_pointer const & /*channelArray*/) { { Lock guard(_mutex); @@ -1574,11 +1678,14 @@ void ServerChannelArrayRequesterImpl::putArrayDone(const Status& status) _transport->enqueueSendRequest(thisSender); } -void ServerChannelArrayRequesterImpl::setLengthDone(const Status& status) +void ServerChannelArrayRequesterImpl::getLengthDone(const Status& status, ChannelArray::shared_pointer const & /*channelArray*/, + size_t length, size_t capacity) { { Lock guard(_mutex); _status = status; + _length = length; + _capacity = capacity; } TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -1586,12 +1693,12 @@ void ServerChannelArrayRequesterImpl::setLengthDone(const Status& status) void ServerChannelArrayRequesterImpl::lock() { - //noop + // noop } void ServerChannelArrayRequesterImpl::unlock() { - //noop + // noop } void ServerChannelArrayRequesterImpl::destroy() @@ -1644,11 +1751,18 @@ void ServerChannelArrayRequesterImpl::send(ByteBuffer* buffer, TransportSendCont //Lock guard(_mutex); ScopedLock lock(_channelArray); // valid due to _mutex lock above _pvArray->serialize(buffer, control, 0, _pvArray->getLength()); + _pvArray.reset(); + } + else if ((QOS_PROCESS & request) != 0) + { + //Lock guard(_mutex); + SerializeHelper::writeSize(_length, buffer, control); + SerializeHelper::writeSize(_capacity, buffer, control); } else if ((QOS_INIT & request) != 0) { Lock guard(_mutex); - control->cachedSerialize(_pvArray != NULL ? _pvArray->getField() : FieldConstPtr(), buffer); + control->cachedSerialize(_array, buffer); } } @@ -1794,7 +1908,9 @@ void ServerProcessHandler::handleResponse(osiSockAddr* responseFrom, return; } - request->getChannelProcess()->process(lastRequest); + if (lastRequest) + request->getChannelProcess()->lastRequest(); + request->getChannelProcess()->process(); } } @@ -1840,7 +1956,7 @@ void ServerChannelProcessRequesterImpl::channelProcessConnect(const Status& stat } } -void ServerChannelProcessRequesterImpl::processDone(const Status& status) +void ServerChannelProcessRequesterImpl::processDone(const Status& status, ChannelProcess::shared_pointer const & /*channelProcess*/) { { Lock guard(_mutex); @@ -1852,12 +1968,12 @@ void ServerChannelProcessRequesterImpl::processDone(const Status& status) void ServerChannelProcessRequesterImpl::lock() { - //noop + // noop } void ServerChannelProcessRequesterImpl::unlock() { - //noop + // noop } void ServerChannelProcessRequesterImpl::destroy() @@ -2045,7 +2161,9 @@ void ServerRPCHandler::handleResponse(osiSockAddr* responseFrom, pvArgument = SerializationHelper::deserializeStructureFull(payloadBuffer, transport.get()); ); - channelRPC->request(pvArgument, lastRequest); + if (lastRequest) + channelRPC->lastRequest(); + channelRPC->request(pvArgument); } } @@ -2093,7 +2211,7 @@ void ServerChannelRPCRequesterImpl::channelRPCConnect(const Status& status, Chan } } -void ServerChannelRPCRequesterImpl::requestDone(const Status& status, PVStructure::shared_pointer const & pvResponse) +void ServerChannelRPCRequesterImpl::requestDone(const Status& status, ChannelRPC::shared_pointer const & /*channelRPC*/, PVStructure::shared_pointer const & pvResponse) { { Lock guard(_mutex); @@ -2106,12 +2224,12 @@ void ServerChannelRPCRequesterImpl::requestDone(const Status& status, PVStructur void ServerChannelRPCRequesterImpl::lock() { - //noop + // noop } void ServerChannelRPCRequesterImpl::unlock() { - //noop + // noop } void ServerChannelRPCRequesterImpl::destroy() diff --git a/pvAccessApp/server/responseHandlers.h b/pvAccessApp/server/responseHandlers.h index 49a2912..66d7e3c 100644 --- a/pvAccessApp/server/responseHandlers.h +++ b/pvAccessApp/server/responseHandlers.h @@ -333,8 +333,10 @@ namespace pvAccess { epics::pvData::PVStructure::shared_pointer const & pvRequest); virtual ~ServerChannelGetRequesterImpl() {} void channelGetConnect(const epics::pvData::Status& status, ChannelGet::shared_pointer const & channelGet, - epics::pvData::PVStructure::shared_pointer const & pvStructure, epics::pvData::BitSet::shared_pointer const & bitSet); - void getDone(const epics::pvData::Status& status); + epics::pvData::Structure::const_shared_pointer const & structure); + void getDone(const epics::pvData::Status& status, ChannelGet::shared_pointer const & channelGet, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet); void destroy(); ChannelGet::shared_pointer getChannelGet(); @@ -344,8 +346,9 @@ namespace pvAccess { void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: ChannelGet::shared_pointer _channelGet; - epics::pvData::BitSet::shared_pointer _bitSet; + epics::pvData::Structure::const_shared_pointer _structure; epics::pvData::PVStructure::shared_pointer _pvStructure; + epics::pvData::BitSet::shared_pointer _bitSet; epics::pvData::Status _status; }; @@ -387,21 +390,30 @@ namespace pvAccess { Transport::shared_pointer const & transport,epics::pvData::PVStructure::shared_pointer const & pvRequest); virtual ~ServerChannelPutRequesterImpl() {} - void channelPutConnect(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut, epics::pvData::PVStructure::shared_pointer const & pvStructure, epics::pvData::BitSet::shared_pointer const & bitSet); - void putDone(const epics::pvData::Status& status); - void getDone(const epics::pvData::Status& status); + void channelPutConnect(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut, epics::pvData::Structure::const_shared_pointer const & structure); + void putDone(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut); + void getDone(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut, epics::pvData::PVStructure::shared_pointer const & pvStructure, epics::pvData::BitSet::shared_pointer const & bitSet); void lock(); void unlock(); void destroy(); ChannelPut::shared_pointer getChannelPut(); - epics::pvData::BitSet::shared_pointer getBitSet(); - epics::pvData::PVStructure::shared_pointer getPVStructure(); + epics::pvData::BitSet::shared_pointer getPutBitSet(); + epics::pvData::PVStructure::shared_pointer getPutPVStructure(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: ChannelPut::shared_pointer _channelPut; + + epics::pvData::Structure::const_shared_pointer _structure; + + // reference store (for get) epics::pvData::BitSet::shared_pointer _bitSet; epics::pvData::PVStructure::shared_pointer _pvStructure; + + // data store (for put) + epics::pvData::BitSet::shared_pointer _putBitSet; + epics::pvData::PVStructure::shared_pointer _putPVStructure; + epics::pvData::Status _status; }; @@ -442,21 +454,43 @@ namespace pvAccess { Transport::shared_pointer const & transport,epics::pvData::PVStructure::shared_pointer const & pvRequest); virtual ~ServerChannelPutGetRequesterImpl() {} - void channelPutGetConnect(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const & channelPutGet, epics::pvData::PVStructure::shared_pointer const & pvPutStructure, epics::pvData::PVStructure::shared_pointer const & pvGetStructure); - void getGetDone(const epics::pvData::Status& status); - void getPutDone(const epics::pvData::Status& status); - void putGetDone(const epics::pvData::Status& status); + void channelPutGetConnect(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::Structure::const_shared_pointer const & putStructure, + epics::pvData::Structure::const_shared_pointer const & getStructure); + void getGetDone(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet); + void getPutDone(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet); + void putGetDone(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet); void lock(); void unlock(); void destroy(); ChannelPutGet::shared_pointer getChannelPutGet(); - epics::pvData::PVStructure::shared_pointer getPVPutStructure(); + + epics::pvData::PVStructure::shared_pointer getPutGetPVStructure(); + epics::pvData::BitSet::shared_pointer getPutGetBitSet(); + void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: ChannelPutGet::shared_pointer _channelPutGet; + epics::pvData::Structure::const_shared_pointer _putStructure; + epics::pvData::Structure::const_shared_pointer _getStructure; + + // reference store epics::pvData::PVStructure::shared_pointer _pvPutStructure; + epics::pvData::BitSet::shared_pointer _pvPutBitSet; epics::pvData::PVStructure::shared_pointer _pvGetStructure; + epics::pvData::BitSet::shared_pointer _pvGetBitSet; + + // data container (for put-get) + epics::pvData::PVStructure::shared_pointer _pvPutGetStructure; + epics::pvData::BitSet::shared_pointer _pvPutGetBitSet; + epics::pvData::Status _status; }; @@ -552,10 +586,13 @@ namespace pvAccess { Transport::shared_pointer const & transport,epics::pvData::PVStructure::shared_pointer const & pvRequest); virtual ~ServerChannelArrayRequesterImpl() {} - void channelArrayConnect(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray, epics::pvData::PVArray::shared_pointer const & pvArray); - void getArrayDone(const epics::pvData::Status& status); - void putArrayDone(const epics::pvData::Status& status); - void setLengthDone(const epics::pvData::Status& status); + void channelArrayConnect(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray, epics::pvData::Array::const_shared_pointer const & array); + void getArrayDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray, + epics::pvData::PVArray::shared_pointer const & pvArray); + void putArrayDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray); + void setLengthDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray); + void getLengthDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray, + std::size_t length, std::size_t capacity); void lock(); void unlock(); void destroy(); @@ -567,7 +604,10 @@ namespace pvAccess { private: ChannelArray::shared_pointer _channelArray; + epics::pvData::Array::const_shared_pointer _array; epics::pvData::PVArray::shared_pointer _pvArray; + std::size_t _length; + std::size_t _capacity; epics::pvData::Status _status; }; @@ -651,7 +691,7 @@ namespace pvAccess { virtual ~ServerChannelProcessRequesterImpl() {} void channelProcessConnect(const epics::pvData::Status& status, ChannelProcess::shared_pointer const & channelProcess); - void processDone(const epics::pvData::Status& status); + void processDone(const epics::pvData::Status& status, ChannelProcess::shared_pointer const & channelProcess); void lock(); void unlock(); void destroy(); @@ -777,7 +817,7 @@ namespace pvAccess { virtual ~ServerChannelRPCRequesterImpl() {} void channelRPCConnect(const epics::pvData::Status& status, ChannelRPC::shared_pointer const & channelRPC); - void requestDone(const epics::pvData::Status& status, epics::pvData::PVStructure::shared_pointer const & pvResponse); + void requestDone(const epics::pvData::Status& status, ChannelRPC::shared_pointer const & channelRPC, epics::pvData::PVStructure::shared_pointer const & pvResponse); void lock(); void unlock(); void destroy(); diff --git a/pvAccessApp/server/serverContext.cpp b/pvAccessApp/server/serverContext.cpp index d16f9bb..c357d23 100644 --- a/pvAccessApp/server/serverContext.cpp +++ b/pvAccessApp/server/serverContext.cpp @@ -36,7 +36,7 @@ ServerContextImpl::ServerContextImpl(): _beaconEmitter(), _acceptor(), _transportRegistry(), - _channelAccess(), + _channelProviderRegistry(), _channelProviderNames(PVACCESS_DEFAULT_PROVIDER), _channelProviders(), _beaconServerStatusProvider() @@ -126,12 +126,12 @@ bool ServerContextImpl::isChannelProviderNamePreconfigured() return config->hasProperty("EPICS_PVA_PROVIDER_NAMES") || config->hasProperty("EPICS_PVAS_PROVIDER_NAMES"); } -void ServerContextImpl::initialize(ChannelAccess::shared_pointer const & channelAccess) +void ServerContextImpl::initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry) { Lock guard(_mutex); - if (channelAccess == NULL) + if (channelProviderRegistry == NULL) { - THROW_BASE_EXCEPTION("non null channelAccess expected"); + THROW_BASE_EXCEPTION("non null channelProviderRegistry expected"); } if (_state == DESTROYED) @@ -143,7 +143,7 @@ void ServerContextImpl::initialize(ChannelAccess::shared_pointer const & channel THROW_BASE_EXCEPTION("Context already initialized."); } - _channelAccess = channelAccess; + _channelProviderRegistry = channelProviderRegistry; // user all providers @@ -151,10 +151,10 @@ void ServerContextImpl::initialize(ChannelAccess::shared_pointer const & channel { _channelProviderNames.resize(0); // VxWorks 5.5 omits clear() - std::auto_ptr names = _channelAccess->getProviderNames(); - for (ChannelAccess::stringVector_t::iterator iter = names->begin(); iter != names->end(); iter++) + std::auto_ptr names = _channelProviderRegistry->getProviderNames(); + for (ChannelProviderRegistry::stringVector_t::iterator iter = names->begin(); iter != names->end(); iter++) { - ChannelProvider::shared_pointer channelProvider = _channelAccess->getProvider(*iter); + ChannelProvider::shared_pointer channelProvider = _channelProviderRegistry->getProvider(*iter); if (channelProvider) { _channelProviders.push_back(channelProvider); @@ -173,13 +173,13 @@ void ServerContextImpl::initialize(ChannelAccess::shared_pointer const & channel std::string providerName; while (std::getline(ss, providerName, ' ')) { - ChannelProvider::shared_pointer channelProvider = _channelAccess->getProvider(providerName); + ChannelProvider::shared_pointer channelProvider = _channelProviderRegistry->getProvider(providerName); if (channelProvider) _channelProviders.push_back(channelProvider); } } - //_channelProvider = _channelAccess->getProvider(_channelProviderNames); + //_channelProvider = _channelProviderRegistry->getProvider(_channelProviderNames); if (_channelProviders.size() == 0) { std::string msg = "None of the specified channel providers are available: " + _channelProviderNames + "."; @@ -545,9 +545,9 @@ BlockingUDPTransport::shared_pointer ServerContextImpl::getBroadcastTransport() return _broadcastTransport; } -ChannelAccess::shared_pointer ServerContextImpl::getChannelAccess() +ChannelProviderRegistry::shared_pointer ServerContextImpl::getChannelProviderRegistry() { - return _channelAccess; + return _channelProviderRegistry; } std::string ServerContextImpl::getChannelProviderName() @@ -621,8 +621,8 @@ ServerContext::shared_pointer startPVAServer(String const & providerNames, int t if (!ctx->isChannelProviderNamePreconfigured()) ctx->setChannelProviderName(providerNames); - ChannelAccess::shared_pointer channelAccess = getChannelAccess(); - ctx->initialize(channelAccess); + ChannelProviderRegistry::shared_pointer channelProviderRegistry = getChannelProviderRegistry(); + ctx->initialize(channelProviderRegistry); if (printInfo) ctx->printInfo(); diff --git a/pvAccessApp/server/serverContext.h b/pvAccessApp/server/serverContext.h index 79dd3d4..bb9afd0 100644 --- a/pvAccessApp/server/serverContext.h +++ b/pvAccessApp/server/serverContext.h @@ -42,10 +42,10 @@ public: virtual const Version& getVersion() = 0; /** - * Set ChannelAccess implementation and initialize server. - * @param channelAccess implementation of channel access to be served. + * Set ChannelProviderRegistry implementation and initialize server. + * @param channelProviderRegistry channel providers registry to be used. */ - virtual void initialize(ChannelAccess::shared_pointer const & channelAccess) = 0; + virtual void initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry) = 0; /** * Run server (process events). @@ -116,7 +116,7 @@ public: //**************** derived from ServerContext ****************// const Version& getVersion(); - void initialize(ChannelAccess::shared_pointer const & channelAccess); + void initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry); void run(epics::pvData::int32 seconds); void shutdown(); void destroy(); @@ -253,10 +253,10 @@ public: BlockingUDPTransport::shared_pointer getBroadcastTransport(); /** - * Get channel access implementation. - * @return channel access implementation. + * Get channel provider registry implementation used by this instance. + * @return channel provider registry used by this instance. */ - ChannelAccess::shared_pointer getChannelAccess(); + ChannelProviderRegistry::shared_pointer getChannelProviderRegistry(); /** * Get channel provider name. @@ -354,7 +354,7 @@ private: /** * Channel access. */ - ChannelAccess::shared_pointer _channelAccess; + ChannelProviderRegistry::shared_pointer _channelProviderRegistry; /** * Channel provider name. From fbb108652e27fb34d5f8f305776ab453352ee4f7 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Wed, 21 May 2014 23:01:03 +0200 Subject: [PATCH 09/32] ca provider ported to new API --- pvAccessApp/ca/caChannel.cpp | 56 ++++++++++++++++++++++++------------ pvAccessApp/ca/caChannel.h | 15 ++++++++-- 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/pvAccessApp/ca/caChannel.cpp b/pvAccessApp/ca/caChannel.cpp index bba7c38..d7c6220 100644 --- a/pvAccessApp/ca/caChannel.cpp +++ b/pvAccessApp/ca/caChannel.cpp @@ -343,7 +343,7 @@ ChannelPutGet::shared_pointer CAChannel::createChannelPutGet( Status errorStatus(Status::STATUSTYPE_ERROR, "not supported"); ChannelPutGet::shared_pointer nullChannelPutGet; EXCEPTION_GUARD(channelPutGetRequester->channelPutGetConnect(errorStatus, nullChannelPutGet, - PVStructure::shared_pointer(), PVStructure::shared_pointer())); + Structure::const_shared_pointer(), Structure::const_shared_pointer())); return nullChannelPutGet; } @@ -374,7 +374,7 @@ ChannelArray::shared_pointer CAChannel::createChannelArray( Status errorStatus(Status::STATUSTYPE_ERROR, "not supported"); ChannelArray::shared_pointer nullChannelArray; EXCEPTION_GUARD(channelArrayRequester->channelArrayConnect(errorStatus, nullChannelArray, - PVArray::shared_pointer())); + Array::const_shared_pointer())); return nullChannelArray; } @@ -527,7 +527,7 @@ CAChannelGet::CAChannelGet(CAChannel::shared_pointer const & _channel, void CAChannelGet::activate() { EXCEPTION_GUARD(channelGetRequester->channelGetConnect(Status::Ok, shared_from_this(), - pvStructure, bitSet)); + pvStructure->getStructure())); } @@ -852,17 +852,17 @@ void CAChannelGet::getDone(struct event_handler_args &args) std::cout << "no copy func implemented" << std::endl; } - EXCEPTION_GUARD(channelGetRequester->getDone(Status::Ok)); + EXCEPTION_GUARD(channelGetRequester->getDone(Status::Ok, shared_from_this(), pvStructure, bitSet)); } else { Status errorStatus(Status::STATUSTYPE_ERROR, String(ca_message(args.status))); - EXCEPTION_GUARD(channelGetRequester->getDone(errorStatus)); + EXCEPTION_GUARD(channelGetRequester->getDone(errorStatus, shared_from_this(), PVStructure::shared_pointer(), BitSet::shared_pointer())); } } -void CAChannelGet::get(bool lastRequest) +void CAChannelGet::get() { int result = ca_array_get_callback(getType, channel->getElementCount(), channel->getChannelID(), ca_get_handler, this); @@ -873,10 +873,10 @@ void CAChannelGet::get(bool lastRequest) else { Status errorStatus(Status::STATUSTYPE_ERROR, String(ca_message(result))); - EXCEPTION_GUARD(channelGetRequester->getDone(errorStatus)); + EXCEPTION_GUARD(channelGetRequester->getDone(errorStatus, shared_from_this(), PVStructure::shared_pointer(), BitSet::shared_pointer())); } - if (lastRequest) + if (lastRequestFlag) destroy(); } @@ -888,6 +888,12 @@ void CAChannelGet::cancel() // noop } +void CAChannelGet::lastRequest() +{ + // TODO sync !!! + lastRequestFlag = true; +} + /* --------------- epics::pvData::Destroyable --------------- */ @@ -955,7 +961,7 @@ CAChannelPut::CAChannelPut(CAChannel::shared_pointer const & _channel, void CAChannelPut::activate() { EXCEPTION_GUARD(channelPutRequester->channelPutConnect(Status::Ok, shared_from_this(), - pvStructure, bitSet)); + pvStructure->getStructure())); } @@ -1110,26 +1116,28 @@ void CAChannelPut::putDone(struct event_handler_args &args) { if (args.status == ECA_NORMAL) { - EXCEPTION_GUARD(channelPutRequester->putDone(Status::Ok)); + EXCEPTION_GUARD(channelPutRequester->putDone(Status::Ok, shared_from_this())); } else { Status errorStatus(Status::STATUSTYPE_ERROR, String(ca_message(args.status))); - EXCEPTION_GUARD(channelPutRequester->putDone(errorStatus)); + EXCEPTION_GUARD(channelPutRequester->putDone(errorStatus, shared_from_this())); } } -void CAChannelPut::put(bool lastRequest) +void CAChannelPut::put(PVStructure::shared_pointer const & pvPutStructure, + BitSet::shared_pointer const & /*putBitSet*/) { doPut putFunc = doPutFuncTable[channel->getNativeType()]; if (putFunc) { - int result = putFunc(channel, this, pvStructure); + // TODO now we always put all + int result = putFunc(channel, this, pvPutStructure); if (result != ECA_NORMAL) { Status errorStatus(Status::STATUSTYPE_ERROR, String(ca_message(result))); - EXCEPTION_GUARD(channelPutRequester->getDone(errorStatus)); + EXCEPTION_GUARD(channelPutRequester->putDone(errorStatus, shared_from_this())); } } else @@ -1139,7 +1147,7 @@ void CAChannelPut::put(bool lastRequest) } // TODO here???!!! - if (lastRequest) + if (lastRequestFlag) destroy(); } @@ -1157,13 +1165,18 @@ void CAChannelPut::getDone(struct event_handler_args &args) std::cout << "no copy func implemented" << std::endl; } - EXCEPTION_GUARD(channelPutRequester->getDone(Status::Ok)); + EXCEPTION_GUARD(channelPutRequester->getDone(Status::Ok, shared_from_this(), pvStructure, bitSet)); } else { Status errorStatus(Status::STATUSTYPE_ERROR, String(ca_message(args.status))); - EXCEPTION_GUARD(channelPutRequester->getDone(errorStatus)); + EXCEPTION_GUARD(channelPutRequester->getDone(errorStatus, shared_from_this(), + PVStructure::shared_pointer(), BitSet::shared_pointer())); } + + // TODO here???!!! + if (lastRequestFlag) + destroy(); } @@ -1178,7 +1191,8 @@ void CAChannelPut::get() else { Status errorStatus(Status::STATUSTYPE_ERROR, String(ca_message(result))); - EXCEPTION_GUARD(channelPutRequester->getDone(errorStatus)); + EXCEPTION_GUARD(channelPutRequester->getDone(errorStatus, shared_from_this(), + PVStructure::shared_pointer(), BitSet::shared_pointer())); } } @@ -1191,6 +1205,12 @@ void CAChannelPut::cancel() // noop } +void CAChannelPut::lastRequest() +{ + // TODO sync !!! + lastRequestFlag = true; +} + /* --------------- epics::pvData::Destroyable --------------- */ diff --git a/pvAccessApp/ca/caChannel.h b/pvAccessApp/ca/caChannel.h index ee8b845..511da8f 100644 --- a/pvAccessApp/ca/caChannel.h +++ b/pvAccessApp/ca/caChannel.h @@ -142,11 +142,12 @@ public: /* --------------- epics::pvAccess::ChannelGet --------------- */ - virtual void get(bool lastRequest); + virtual void get(); /* --------------- epics::pvData::ChannelRequest --------------- */ virtual void cancel(); + virtual void lastRequest(); /* --------------- epics::pvData::Destroyable --------------- */ @@ -170,6 +171,9 @@ private: epics::pvData::PVStructure::shared_pointer pvStructure; epics::pvData::BitSet::shared_pointer bitSet; + + // TODO AtomicBoolean !!! + bool lastRequestFlag; }; @@ -193,12 +197,16 @@ public: /* --------------- epics::pvAccess::ChannelPut --------------- */ - virtual void put(bool lastRequest); + virtual void put( + epics::pvData::PVStructure::shared_pointer const & pvPutStructure, + epics::pvData::BitSet::shared_pointer const & putBitSet + ); virtual void get(); /* --------------- epics::pvData::ChannelRequest --------------- */ virtual void cancel(); + virtual void lastRequest(); /* --------------- epics::pvData::Destroyable --------------- */ @@ -222,6 +230,9 @@ private: epics::pvData::PVStructure::shared_pointer pvStructure; epics::pvData::BitSet::shared_pointer bitSet; + + // TODO AtomicBoolean !!! + bool lastRequestFlag; }; From cdc03d8e9732d40f000907772ce438ef1b8b7092 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Thu, 22 May 2014 22:31:20 +0200 Subject: [PATCH 10/32] porting tests and utils --- pvAccessApp/ca/caChannel.cpp | 10 + pvAccessApp/ca/caChannel.h | 2 + pvAccessApp/client/pvAccess.h | 8 +- .../remoteClient/clientContextImpl.cpp | 44 +++- pvAccessApp/rpcService/rpcServer.cpp | 17 +- pvAccessApp/v3ioc/syncChannelFind.h | 2 +- testApp/client/MockClientImpl.cpp | 2 +- testApp/client/testChannelAccessFactory.cpp | 2 +- testApp/remote/eget.cpp | 6 +- testApp/remote/pvget.cpp | 4 +- testApp/remote/pvinfo.cpp | 2 +- testApp/remote/pvput.cpp | 4 +- testApp/remote/testChannelAccess.cpp | 2 +- testApp/remote/testChannelConnect.cpp | 2 +- testApp/remote/testGetPerformance.cpp | 2 +- testApp/remote/testRemoteClientImpl.cpp | 199 ++++++++---------- testApp/remote/testServer.cpp | 4 +- testApp/remote/testServerContext.cpp | 6 +- 18 files changed, 181 insertions(+), 137 deletions(-) diff --git a/pvAccessApp/ca/caChannel.cpp b/pvAccessApp/ca/caChannel.cpp index d7c6220..07ab5ec 100644 --- a/pvAccessApp/ca/caChannel.cpp +++ b/pvAccessApp/ca/caChannel.cpp @@ -883,6 +883,11 @@ void CAChannelGet::get() /* --------------- epics::pvData::ChannelRequest --------------- */ +Channel::shared_pointer CAChannelGet::getChannel() +{ + return channel; +} + void CAChannelGet::cancel() { // noop @@ -1200,6 +1205,11 @@ void CAChannelPut::get() /* --------------- epics::pvData::ChannelRequest --------------- */ +Channel::shared_pointer CAChannelPut::getChannel() +{ + return channel; +} + void CAChannelPut::cancel() { // noop diff --git a/pvAccessApp/ca/caChannel.h b/pvAccessApp/ca/caChannel.h index 511da8f..e0db30a 100644 --- a/pvAccessApp/ca/caChannel.h +++ b/pvAccessApp/ca/caChannel.h @@ -146,6 +146,7 @@ public: /* --------------- epics::pvData::ChannelRequest --------------- */ + virtual Channel::shared_pointer getChannel(); virtual void cancel(); virtual void lastRequest(); @@ -205,6 +206,7 @@ public: /* --------------- epics::pvData::ChannelRequest --------------- */ + virtual Channel::shared_pointer getChannel(); virtual void cancel(); virtual void lastRequest(); diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index 178f08f..bb4295b 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -115,6 +115,12 @@ namespace pvAccess { public: POINTER_DEFINITIONS(ChannelRequest); + /** + * Get a channel instance this request belongs to. + * @return the channel instance. + */ + virtual std::tr1::shared_ptr getChannel() = 0; + /** * Cancel any pending request. * Completion will be reported via request's response callback: @@ -241,7 +247,7 @@ namespace pvAccess { POINTER_DEFINITIONS(ChannelFind); virtual std::tr1::shared_ptr getChannelProvider() = 0; - virtual void cancelChannelFind() = 0; + virtual void cancel() = 0; }; /** diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index f9f6f11..cbc26da 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -112,7 +112,7 @@ namespace epics { static Status pvRequestNull; static PVStructure::shared_pointer nullPVStructure; - static Structure::shared_pointer nullStructure; + static Structure::const_shared_pointer nullStructure; static BitSet::shared_pointer nullBitSet; static BitSet::shared_pointer createBitSetFor( @@ -291,6 +291,10 @@ namespace epics { } } + + virtual Channel::shared_pointer getChannel() { + return m_channel; + } virtual void destroy() { destroy(false); @@ -396,6 +400,7 @@ namespace epics { Status BaseRequestImpl::pvRequestNull = Status(Status::STATUSTYPE_ERROR, "pvRequest == 0"); PVStructure::shared_pointer BaseRequestImpl::nullPVStructure; + Structure::const_shared_pointer BaseRequestImpl::nullStructure; BitSet::shared_pointer BaseRequestImpl::nullBitSet; PVACCESS_REFCOUNT_MONITOR_DEFINE(channelProcess); @@ -510,6 +515,11 @@ namespace epics { } } + virtual Channel::shared_pointer getChannel() + { + return BaseRequestImpl::getChannel(); + } + virtual void cancel() { BaseRequestImpl::cancel(); @@ -717,6 +727,11 @@ namespace epics { } } + virtual Channel::shared_pointer getChannel() + { + return BaseRequestImpl::getChannel(); + } + virtual void cancel() { BaseRequestImpl::cancel(); @@ -976,6 +991,11 @@ namespace epics { } } + virtual Channel::shared_pointer getChannel() + { + return BaseRequestImpl::getChannel(); + } + virtual void cancel() { BaseRequestImpl::cancel(); @@ -1299,6 +1319,11 @@ namespace epics { } } + virtual Channel::shared_pointer getChannel() + { + return BaseRequestImpl::getChannel(); + } + virtual void cancel() { BaseRequestImpl::cancel(); @@ -1488,6 +1513,11 @@ namespace epics { } } + virtual Channel::shared_pointer getChannel() + { + return BaseRequestImpl::getChannel(); + } + virtual void cancel() { BaseRequestImpl::cancel(); @@ -1847,6 +1877,11 @@ namespace epics { } } + virtual Channel::shared_pointer getChannel() + { + return BaseRequestImpl::getChannel(); + } + virtual void cancel() { BaseRequestImpl::cancel(); @@ -1964,6 +1999,11 @@ namespace epics { } + virtual Channel::shared_pointer getChannel() + { + return m_channel; + } + virtual void cancel() { // TODO // noop @@ -2885,7 +2925,7 @@ namespace epics { return m_provider; }; - virtual void cancelChannelFind() + virtual void cancel() { throw std::runtime_error("not supported"); } diff --git a/pvAccessApp/rpcService/rpcServer.cpp b/pvAccessApp/rpcService/rpcServer.cpp index 2a38379..ebc5487 100644 --- a/pvAccessApp/rpcService/rpcServer.cpp +++ b/pvAccessApp/rpcService/rpcServer.cpp @@ -19,14 +19,17 @@ class ChannelRPCServiceImpl : public std::tr1::enable_shared_from_this { private: + Channel::shared_pointer m_channel; ChannelRPCRequester::shared_pointer m_channelRPCRequester; RPCService::shared_pointer m_rpcService; AtomicBoolean m_lastRequest; public: ChannelRPCServiceImpl( + Channel::shared_pointer const & channel, ChannelRPCRequester::shared_pointer const & channelRPCRequester, RPCService::shared_pointer const & rpcService) : + m_channel(channel), m_channelRPCRequester(channelRPCRequester), m_rpcService(rpcService), m_lastRequest() @@ -87,6 +90,11 @@ class ChannelRPCServiceImpl : m_lastRequest.set(); } + virtual Channel::shared_pointer getChannel() + { + return m_channel; + } + virtual void cancel() { // noop @@ -112,7 +120,8 @@ class ChannelRPCServiceImpl : class RPCChannel : - public virtual Channel + public virtual Channel, + public std::tr1::enable_shared_from_this { private: @@ -247,7 +256,9 @@ public: return nullPtr; } - ChannelRPC::shared_pointer channelRPCImpl(new ChannelRPCServiceImpl(channelRPCRequester, m_rpcService)); + ChannelRPC::shared_pointer channelRPCImpl( + new ChannelRPCServiceImpl(shared_from_this(), channelRPCRequester, m_rpcService) + ); channelRPCRequester->channelRPCConnect(Status::Ok, channelRPCImpl); return channelRPCImpl; } @@ -333,7 +344,7 @@ public: return shared_from_this(); } - virtual void cancelChannelFind() {} + virtual void cancel() {} virtual void destroy() {} diff --git a/pvAccessApp/v3ioc/syncChannelFind.h b/pvAccessApp/v3ioc/syncChannelFind.h index 9477c54..18227b6 100644 --- a/pvAccessApp/v3ioc/syncChannelFind.h +++ b/pvAccessApp/v3ioc/syncChannelFind.h @@ -54,7 +54,7 @@ public: return m_provider.lock(); }; - virtual void cancelChannelFind() {} + virtual void cancel() {} private: ChannelProvider::weak_pointer m_provider; diff --git a/testApp/client/MockClientImpl.cpp b/testApp/client/MockClientImpl.cpp index 9914bff..bf62862 100644 --- a/testApp/client/MockClientImpl.cpp +++ b/testApp/client/MockClientImpl.cpp @@ -556,7 +556,7 @@ class MockChannelFind : public ChannelFind return m_provider; }; - virtual void cancelChannelFind() + virtual void cancel() { throw std::runtime_error("not supported"); } diff --git a/testApp/client/testChannelAccessFactory.cpp b/testApp/client/testChannelAccessFactory.cpp index 17a04b4..c24b196 100644 --- a/testApp/client/testChannelAccessFactory.cpp +++ b/testApp/client/testChannelAccessFactory.cpp @@ -37,7 +37,7 @@ public: void testChannelAccessFactory() { printf("testChannelAccessFactory... "); - ChannelAccess* ca = getChannelAccess(); + ChannelAccess* ca = getChannelProviderRegistry(); assert(ca); // empty diff --git a/testApp/remote/eget.cpp b/testApp/remote/eget.cpp index 6d546cb..5f7fa0b 100644 --- a/testApp/remote/eget.cpp +++ b/testApp/remote/eget.cpp @@ -1729,7 +1729,7 @@ int main (int argc, char *argv[]) { shared_ptr channelRequesterImpl(new ChannelRequesterImpl(quiet)); // TODO no provider check - channels[n] = getChannelAccess()->getProvider(providerNames[n])->createChannel(pvs[n], channelRequesterImpl); + channels[n] = getChannelProviderRegistry()->getProvider(providerNames[n])->createChannel(pvs[n], channelRequesterImpl); } // TODO maybe unify for nPvs == 1?! @@ -1803,7 +1803,7 @@ int main (int argc, char *argv[]) shared_ptr channelRequesterImpl(new ChannelRequesterImpl(quiet)); // TODO no provider check - channel = getChannelAccess()->getProvider(cp)->createChannel(cn, channelRequesterImpl); + channel = getChannelProviderRegistry()->getProvider(cp)->createChannel(cn, channelRequesterImpl); } if (monitor) @@ -2035,7 +2035,7 @@ int main (int argc, char *argv[]) ClientFactory::start(); - ChannelProvider::shared_pointer provider = getChannelAccess()->getProvider("pva"); + ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); shared_ptr channelRequesterImpl(new ChannelRequesterImpl(quiet)); Channel::shared_pointer channel = diff --git a/testApp/remote/pvget.cpp b/testApp/remote/pvget.cpp index 3eb8719..fdaf450 100644 --- a/testApp/remote/pvget.cpp +++ b/testApp/remote/pvget.cpp @@ -484,10 +484,10 @@ int main (int argc, char *argv[]) } ClientFactory::start(); - ChannelProvider::shared_pointer provider = getChannelAccess()->getProvider("pva"); + ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); //epics::pvAccess::ca::CAClientFactory::start(); - //ChannelProvider::shared_pointer provider = getChannelAccess()->getProvider("ca"); + //ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("ca"); // first connect to all, this allows resource (e.g. TCP connection) sharing vector channels(nPvs); diff --git a/testApp/remote/pvinfo.cpp b/testApp/remote/pvinfo.cpp index b450a54..cf9be31 100644 --- a/testApp/remote/pvinfo.cpp +++ b/testApp/remote/pvinfo.cpp @@ -122,7 +122,7 @@ int main (int argc, char *argv[]) Requester::shared_pointer requester(new RequesterImpl("pvinfo")); ClientFactory::start(); - ChannelProvider::shared_pointer provider = getChannelAccess()->getProvider("pva"); + ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); // first connect to all, this allows resource (e.g. TCP connection) sharing vector channels(nPvs); diff --git a/testApp/remote/pvput.cpp b/testApp/remote/pvput.cpp index ff95139..ebb0e2e 100644 --- a/testApp/remote/pvput.cpp +++ b/testApp/remote/pvput.cpp @@ -551,10 +551,10 @@ int main (int argc, char *argv[]) terseSeparator(fieldSeparator); ClientFactory::start(); - ChannelProvider::shared_pointer provider = getChannelAccess()->getProvider("pva"); + ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); //epics::pvAccess::ca::CAClientFactory::start(); - //ChannelProvider::shared_pointer provider = getChannelAccess()->getProvider("ca"); + //ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("ca"); bool allOK = true; diff --git a/testApp/remote/testChannelAccess.cpp b/testApp/remote/testChannelAccess.cpp index 0f1021d..ce83c4c 100755 --- a/testApp/remote/testChannelAccess.cpp +++ b/testApp/remote/testChannelAccess.cpp @@ -61,7 +61,7 @@ class ChannelAccessIFRemoteTest: public ChannelAccessIFTest { virtual ChannelProvider::shared_pointer getChannelProvider() { - return getChannelAccess()->getProvider( + return getChannelProviderRegistry()->getProvider( "pva"); } diff --git a/testApp/remote/testChannelConnect.cpp b/testApp/remote/testChannelConnect.cpp index ed5c369..cbb10de 100644 --- a/testApp/remote/testChannelConnect.cpp +++ b/testApp/remote/testChannelConnect.cpp @@ -72,7 +72,7 @@ int main() Event g_event; ClientFactory::start(); - ChannelProvider::shared_pointer provider = getChannelAccess()->getProvider("pva"); + ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); ChannelRequester::shared_pointer channelRequester(new ChannelRequesterImpl(g_event)); Channel::shared_pointer channels[N_CHANNELS]; diff --git a/testApp/remote/testGetPerformance.cpp b/testApp/remote/testGetPerformance.cpp index b1d6ca7..81b8f44 100644 --- a/testApp/remote/testGetPerformance.cpp +++ b/testApp/remote/testGetPerformance.cpp @@ -477,7 +477,7 @@ int main (int argc, char *argv[]) } ClientFactory::start(); - provider = getChannelAccess()->getProvider("pva"); + provider = getChannelProviderRegistry()->getProvider("pva"); if (!testFile.empty()) { diff --git a/testApp/remote/testRemoteClientImpl.cpp b/testApp/remote/testRemoteClientImpl.cpp index 0d0c8ab..0fbf295 100644 --- a/testApp/remote/testRemoteClientImpl.cpp +++ b/testApp/remote/testRemoteClientImpl.cpp @@ -12,6 +12,7 @@ using namespace epics::pvData; using namespace epics::pvAccess; +#define SLEEP_TIME 1.0 class ChannelFindRequesterImpl : public ChannelFindRequester { @@ -60,7 +61,7 @@ class GetFieldRequesterImpl : public GetFieldRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } - virtual void getDone(const epics::pvData::Status& status,epics::pvData::FieldConstPtr const & field) + virtual void getDone(const epics::pvData::Status& status, epics::pvData::FieldConstPtr const & field) { std::cout << "getDone(" << status.toString() << ", "; if (status.isSuccess() && field) @@ -77,12 +78,6 @@ class GetFieldRequesterImpl : public GetFieldRequester class ChannelGetRequesterImpl : public ChannelGetRequester { - private: - - //ChannelGet::shared_pointer m_channelGet; - epics::pvData::PVStructure::shared_pointer m_pvStructure; - epics::pvData::BitSet::shared_pointer m_bitSet; - public: virtual String getRequesterName() @@ -96,8 +91,7 @@ class ChannelGetRequesterImpl : public ChannelGetRequester } virtual void channelGetConnect(const epics::pvData::Status& status,ChannelGet::shared_pointer const & /*channelGet*/, - epics::pvData::PVStructure::shared_pointer const & pvStructure, - epics::pvData::BitSet::shared_pointer const & bitSet) + epics::pvData::Structure::const_shared_pointer const & pvStructure) { std::cout << "channelGetConnect(" << status.toString() << ")" << std::endl; if (status.isSuccess()) @@ -106,20 +100,17 @@ class ChannelGetRequesterImpl : public ChannelGetRequester pvStructure->toString(&st); std::cout << st << std::endl; } - - //m_channelGet = channelGet; - m_pvStructure = pvStructure; - m_bitSet = bitSet; } - virtual void getDone(const epics::pvData::Status& status) + virtual void getDone(const epics::pvData::Status& status, ChannelGet::shared_pointer const &, + PVStructure::shared_pointer const & getData, BitSet::shared_pointer const & /*bitSet*/) { std::cout << "getDone(" << status.toString() << ")" << std::endl; if (status.isSuccess()) { String str; - m_pvStructure->toString(&str); + getData->toString(&str); std::cout << str; std::cout << std::endl; } @@ -128,12 +119,6 @@ class ChannelGetRequesterImpl : public ChannelGetRequester class ChannelPutRequesterImpl : public ChannelPutRequester { - private: - - //ChannelPut::shared_pointer m_channelPut; - epics::pvData::PVStructure::shared_pointer m_pvStructure; - epics::pvData::BitSet::shared_pointer m_bitSet; - public: virtual String getRequesterName() @@ -147,50 +132,39 @@ class ChannelPutRequesterImpl : public ChannelPutRequester } virtual void channelPutConnect(const epics::pvData::Status& status,ChannelPut::shared_pointer const & /*channelPut*/, - epics::pvData::PVStructure::shared_pointer const & pvStructure, - epics::pvData::BitSet::shared_pointer const & bitSet) + epics::pvData::Structure::const_shared_pointer const & pvStructure) { std::cout << "channelPutConnect(" << status.toString() << ")" << std::endl; - - //m_channelPut = channelPut; - m_pvStructure = pvStructure; - m_bitSet = bitSet; + if (status.isSuccess()) + { + String st; + pvStructure->toString(&st); + std::cout << st << std::endl; + } } - virtual void getDone(const epics::pvData::Status& status) + virtual void getDone(const epics::pvData::Status& status, ChannelPut::shared_pointer const &, + PVStructure::shared_pointer const & getData, BitSet::shared_pointer const & /*bitSet*/) { std::cout << "getDone(" << status.toString() << ")" << std::endl; if (status.isSuccess()) { String str; - m_pvStructure->toString(&str); + getData->toString(&str); std::cout << str; std::cout << std::endl; } } - virtual void putDone(const epics::pvData::Status& status) + virtual void putDone(const epics::pvData::Status& status, ChannelPut::shared_pointer const &) { std::cout << "putDone(" << status.toString() << ")" << std::endl; - if (status.isSuccess()) - { - String str; - m_pvStructure->toString(&str); - std::cout << str; - std::cout << std::endl; - } } }; class ChannelPutGetRequesterImpl : public ChannelPutGetRequester { - private: - - //ChannelPutGet::shared_pointer m_channelPutGet; - epics::pvData::PVStructure::shared_pointer m_putData; - epics::pvData::PVStructure::shared_pointer m_getData; - public: virtual String getRequesterName() @@ -204,62 +178,61 @@ class ChannelPutGetRequesterImpl : public ChannelPutGetRequester } virtual void channelPutGetConnect(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const & /*channelPutGet*/, - epics::pvData::PVStructure::shared_pointer const & putData, - epics::pvData::PVStructure::shared_pointer const & getData) + epics::pvData::Structure::const_shared_pointer const & putData, + epics::pvData::Structure::const_shared_pointer const & getData) { std::cout << "channelGetPutConnect(" << status.toString() << ")" << std::endl; - //m_channelPutGet = channelPutGet; - m_putData = putData; - m_getData = getData; - - if (m_putData) + if (putData) { String str; - m_putData->toString(&str); + putData->toString(&str); std::cout << str; std::cout << std::endl; } - if (m_getData) + if (getData) { String str; - m_getData->toString(&str); + getData->toString(&str); std::cout << str; std::cout << std::endl; } } - virtual void getGetDone(const epics::pvData::Status& status) + virtual void getGetDone(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const &, + PVStructure::shared_pointer const & getData, BitSet::shared_pointer const & /*bitSet*/) { std::cout << "getGetDone(" << status.toString() << ")" << std::endl; if (status.isSuccess()) { String str; - m_getData->toString(&str); + getData->toString(&str); std::cout << str; std::cout << std::endl; } } - virtual void getPutDone(const epics::pvData::Status& status) + virtual void getPutDone(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const &, + PVStructure::shared_pointer const & putData, BitSet::shared_pointer const & /*bitSet*/) { std::cout << "getPutDone(" << status.toString() << ")" << std::endl; if (status.isSuccess()) { String str; - m_putData->toString(&str); + putData->toString(&str); std::cout << str; std::cout << std::endl; } } - virtual void putGetDone(const epics::pvData::Status& status) + virtual void putGetDone(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const &, + PVStructure::shared_pointer const & putData, BitSet::shared_pointer const & /*bitSet*/) { std::cout << "putGetDone(" << status.toString() << ")" << std::endl; if (status.isSuccess()) { String str; - m_putData->toString(&str); + putData->toString(&str); std::cout << str; std::cout << std::endl; } @@ -270,8 +243,6 @@ class ChannelPutGetRequesterImpl : public ChannelPutGetRequester class ChannelRPCRequesterImpl : public ChannelRPCRequester { - //ChannelRPC::shared_pointer m_channelRPC; - virtual String getRequesterName() { return "ChannelRPCRequesterImpl"; @@ -286,11 +257,10 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester ChannelRPC::shared_pointer const & /*channelRPC*/) { std::cout << "channelRPCConnect(" << status.toString() << ")" << std::endl; - - //m_channelRPC = channelRPC; } - virtual void requestDone(const epics::pvData::Status& status,epics::pvData::PVStructure::shared_pointer const & pvResponse) + virtual void requestDone(const epics::pvData::Status& status, ChannelRPC::shared_pointer const &, + epics::pvData::PVStructure::shared_pointer const & pvResponse) { std::cout << "requestDone(" << status.toString() << ")" << std::endl; if (status.isSuccess()) @@ -305,11 +275,6 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester class ChannelArrayRequesterImpl : public ChannelArrayRequester { - private: - - //ChannelArray::shared_pointer m_channelArray; - epics::pvData::PVArray::shared_pointer m_pvArray; - public: virtual String getRequesterName() @@ -323,41 +288,46 @@ class ChannelArrayRequesterImpl : public ChannelArrayRequester } virtual void channelArrayConnect(const epics::pvData::Status& status,ChannelArray::shared_pointer const & /*channelArray*/, - epics::pvData::PVArray::shared_pointer const & pvArray) + epics::pvData::Array::const_shared_pointer const & array) { std::cout << "channelArrayConnect(" << status.toString() << ")" << std::endl; if (status.isSuccess()) { String st; - pvArray->toString(&st); + array->toString(&st); std::cout << st << std::endl; } - //m_channelArray = channelArray; - m_pvArray = pvArray; } - virtual void getArrayDone(const epics::pvData::Status& status) + virtual void getArrayDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const &, + PVArray::shared_pointer const & pvArray) { std::cout << "getArrayDone(" << status.toString() << ")" << std::endl; if (status.isSuccess()) { String str; - m_pvArray->toString(&str); + pvArray->toString(&str); std::cout << str; std::cout << std::endl; } } - virtual void putArrayDone(const epics::pvData::Status& status) + virtual void putArrayDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const &) { std::cout << "putArrayDone(" << status.toString() << ")" << std::endl; } - virtual void setLengthDone(const epics::pvData::Status& status) + virtual void setLengthDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const &) { std::cout << "setLengthDone(" << status.toString() << ")" << std::endl; } + + virtual void getLengthDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const &, + size_t length, size_t capacity) + { + std::cout << "getLengthDone(" << status.toString() << "," << length << "," << capacity << ")" << std::endl; + } }; class MonitorRequesterImpl : public MonitorRequester @@ -430,7 +400,7 @@ class ChannelProcessRequesterImpl : public ChannelProcessRequester //m_channelProcess = channelProcess; } - virtual void processDone(const epics::pvData::Status& status) + virtual void processDone(const epics::pvData::Status& status, ChannelProcess::shared_pointer const &) { std::cout << "processDone(" << status.toString() << ")" << std::endl; } @@ -449,39 +419,39 @@ int main() context->initialize(); context->printInfo(); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); ChannelProvider::shared_pointer provider = context->getProvider(); */ ClientFactory::start(); - ChannelProvider::shared_pointer provider = getChannelAccess()->getProvider("pva"); + ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); ChannelFindRequester::shared_pointer findRequester(new ChannelFindRequesterImpl()); ChannelFind::shared_pointer channelFind = provider->channelFind("testSomething", findRequester); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); //channelFind->destroy(); ChannelRequester::shared_pointer channelRequester(new ChannelRequesterImpl()); Channel::shared_pointer channel = provider->createChannel("testStructureArrayTest", channelRequester); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); channel->printInfo(); { GetFieldRequester::shared_pointer getFieldRequesterImpl(new GetFieldRequesterImpl()); channel->getField(getFieldRequesterImpl, ""); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); } { ChannelProcessRequester::shared_pointer channelProcessRequester(new ChannelProcessRequesterImpl()); PVStructure::shared_pointer pvRequest; ChannelProcess::shared_pointer channelProcess = channel->createChannelProcess(channelProcessRequester, pvRequest); - epicsThreadSleep ( 1.0 ); - channelProcess->process(false); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); + channelProcess->process(); + epicsThreadSleep ( SLEEP_TIME ); channelProcess->destroy(); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); } { @@ -489,7 +459,7 @@ int main() PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest("field()"); ChannelGet::shared_pointer channelGet = channel->createChannelGet(channelGetRequesterImpl, pvRequest); epicsThreadSleep ( 3.0 ); - channelGet->get(false); + channelGet->get(); epicsThreadSleep ( 3.0 ); channelGet->destroy(); } @@ -498,11 +468,12 @@ int main() ChannelPutRequester::shared_pointer channelPutRequesterImpl(new ChannelPutRequesterImpl()); PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest("field(value,timeStamp)"); ChannelPut::shared_pointer channelPut = channel->createChannelPut(channelPutRequesterImpl, pvRequest); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); channelPut->get(); - epicsThreadSleep ( 1.0 ); - channelPut->put(false); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); + // TODO !!! + //channelPut->put(); + //epicsThreadSleep ( SLEEP_TIME ); channelPut->destroy(); } @@ -510,13 +481,14 @@ int main() ChannelPutGetRequester::shared_pointer channelPutGetRequesterImpl(new ChannelPutGetRequesterImpl()); PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest("putField(value,timeStamp)getField(timeStamp)"); ChannelPutGet::shared_pointer channelPutGet = channel->createChannelPutGet(channelPutGetRequesterImpl, pvRequest); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); channelPutGet->getGet(); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); channelPutGet->getPut(); - epicsThreadSleep ( 1.0 ); - channelPutGet->putGet(false); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); + // TODO !!! + //channelPutGet->putGet(); + //epicsThreadSleep ( SLEEP_TIME ); channelPutGet->destroy(); } @@ -524,10 +496,10 @@ int main() ChannelRPCRequester::shared_pointer channelRPCRequesterImpl(new ChannelRPCRequesterImpl()); PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest("record[]field(arguments)"); ChannelRPC::shared_pointer channelRPC = channel->createChannelRPC(channelRPCRequesterImpl, pvRequest); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); // for test simply use pvRequest as arguments - channelRPC->request(pvRequest, false); - epicsThreadSleep ( 1.0 ); + channelRPC->request(pvRequest); + epicsThreadSleep ( SLEEP_TIME ); channelRPC->destroy(); } @@ -538,13 +510,16 @@ int main() PVStructure::shared_pointer pvRequest(getPVDataCreate()->createPVStructure(getFieldCreate()->createStructure(fieldNames, fields))); ChannelArray::shared_pointer channelArray = channel->createChannelArray(channelArrayRequesterImpl, pvRequest); - epicsThreadSleep ( 1.0 ); - channelArray->getArray(false,0,0); - epicsThreadSleep ( 1.0 ); - channelArray->putArray(false,0,0); - epicsThreadSleep ( 1.0 ); - channelArray->setLength(false,3,4); - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( SLEEP_TIME ); + channelArray->getArray(0,0,1); + epicsThreadSleep ( SLEEP_TIME ); + // TODO !!! + //channelArray->putArray(0,0,1); + //epicsThreadSleep ( SLEEP_TIME ); + channelArray->setLength(3,4); + epicsThreadSleep ( SLEEP_TIME ); + channelArray->getLength(); + epicsThreadSleep ( SLEEP_TIME ); channelArray->destroy(); } @@ -553,12 +528,12 @@ int main() PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest("field()"); Monitor::shared_pointer monitor = channel->createMonitor(monitorRequesterImpl, pvRequest); - epicsThreadSleep( 1.0 ); + epicsThreadSleep( SLEEP_TIME ); Status status = monitor->start(); std::cout << "monitor->start() = " << status.toString() << std::endl; - epicsThreadSleep( 3.0 ); + epicsThreadSleep( 3*SLEEP_TIME ); status = monitor->stop(); std::cout << "monitor->stop() = " << status.toString() << std::endl; @@ -567,12 +542,12 @@ int main() monitor->destroy(); } - epicsThreadSleep ( 3.0 ); + epicsThreadSleep ( 3*SLEEP_TIME ); printf("Destroying channel... \n"); channel->destroy(); printf("done.\n"); - epicsThreadSleep ( 3.0 ); + epicsThreadSleep ( 3*SLEEP_TIME ); } @@ -584,7 +559,7 @@ int main() printf("done.\n"); */ - epicsThreadSleep ( 1.0 ); } + epicsThreadSleep ( SLEEP_TIME ); } //std::cout << "-----------------------------------------------------------------------" << std::endl; //epicsExitCallAtExits(); return(0); diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index 230e636..66fe170 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -2364,7 +2364,7 @@ public: return m_provider.lock(); }; - virtual void cancelChannelFind() + virtual void cancel() { throw std::runtime_error("not supported"); } @@ -2578,7 +2578,7 @@ void testServer(int timeToRun) //ServerContextImpl::shared_pointer ctx = ServerContextImpl::create(); ctx = ServerContextImpl::create(); - ChannelAccess::shared_pointer channelAccess = getChannelAccess(); + ChannelAccess::shared_pointer channelAccess = getChannelProviderRegistry(); ctx->initialize(channelAccess); ctx->printInfo(); diff --git a/testApp/remote/testServerContext.cpp b/testApp/remote/testServerContext.cpp index 765d6b9..2c41e68 100644 --- a/testApp/remote/testServerContext.cpp +++ b/testApp/remote/testServerContext.cpp @@ -48,10 +48,10 @@ public: }; -class TestChannelAccess : public ChannelAccess { +class TestChannelProviderRegistry : public ChannelProviderRegistry { public: - virtual ~TestChannelAccess() {}; + virtual ~TestChannelProviderRegistry() {}; ChannelProvider::shared_pointer getProvider(epics::pvData::String const & providerName) { @@ -81,7 +81,7 @@ void testServerContext() ServerContextImpl::shared_pointer ctx = ServerContextImpl::create(); - ChannelAccess::shared_pointer ca(new TestChannelAccess()); + ChannelProviderRegistry::shared_pointer ca(new TestChannelProviderRegistry()); ctx->initialize(ca); ctx->printInfo(); From 82f35f8c386126683c87084895a99af193bbc50d Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Thu, 22 May 2014 23:59:35 +0200 Subject: [PATCH 11/32] testServer and utils are back alive --- testApp/remote/eget.cpp | 85 +++--- testApp/remote/pvget.cpp | 41 +-- testApp/remote/pvput.cpp | 41 ++- testApp/remote/testGetPerformance.cpp | 19 +- testApp/remote/testServer.cpp | 367 +++++++++++++++++--------- 5 files changed, 307 insertions(+), 246 deletions(-) diff --git a/testApp/remote/eget.cpp b/testApp/remote/eget.cpp index 5f7fa0b..c528f20 100644 --- a/testApp/remote/eget.cpp +++ b/testApp/remote/eget.cpp @@ -1049,7 +1049,6 @@ private: String m_channelName; bool m_printValue; - ChannelGet::shared_pointer m_channelGet; PVStructure::shared_pointer m_pvStructure; BitSet::shared_pointer m_bitSet; Mutex m_pointerMutex; @@ -1076,9 +1075,9 @@ public: std::cerr << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } - virtual void channelGetConnect(const epics::pvData::Status& status,ChannelGet::shared_pointer const & channelGet, - epics::pvData::PVStructure::shared_pointer const & pvStructure, - epics::pvData::BitSet::shared_pointer const & bitSet) + virtual void channelGetConnect(const epics::pvData::Status& status, + ChannelGet::shared_pointer const & channelGet, + epics::pvData::Structure::const_shared_pointer const & /*structure*/) { if (status.isSuccess()) { @@ -1088,15 +1087,8 @@ public: std::cerr << "[" << m_channelName << "] channel get create: " << status << std::endl; } - // assign smart pointers - { - Lock lock(m_pointerMutex); - m_channelGet = channelGet; - m_pvStructure = pvStructure; - m_bitSet = bitSet; - } - - channelGet->get(true); + channelGet->lastRequest(); + channelGet->get(); } else { @@ -1105,7 +1097,10 @@ public: } } - virtual void getDone(const epics::pvData::Status& status) + virtual void getDone(const epics::pvData::Status& status, + ChannelGet::shared_pointer const & /*channelGet*/, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet) { if (status.isSuccess()) { @@ -1118,30 +1113,19 @@ public: // access smart pointers { Lock lock(m_pointerMutex); + m_pvStructure = pvStructure; + m_bitSet = bitSet; + m_done = true; + + if (m_printValue) { - m_done = true; - - if (m_printValue) - { - // needed since we access the data - ScopedLock dataLock(m_channelGet); - - printValue(m_channelName, m_pvStructure); - } + printValue(m_channelName, m_pvStructure); } - - // this is OK since callee holds also owns it - m_channelGet.reset(); } } else { std::cerr << "[" << m_channelName << "] failed to get: " << status << std::endl; - { - Lock lock(m_pointerMutex); - // this is OK since caller holds also owns it - m_channelGet.reset(); - } } m_event.signal(); @@ -1171,10 +1155,10 @@ public: class ChannelRPCRequesterImpl : public ChannelRPCRequester { private: - ChannelRPC::shared_pointer m_channelRPC; Mutex m_pointerMutex; Event m_event; Event m_connectionEvent; + bool m_successfullyConnected; String m_channelName; PVStructure::shared_pointer m_lastResponse; @@ -1182,7 +1166,12 @@ private: public: - ChannelRPCRequesterImpl(String channelName) : m_channelName(channelName), m_done(false) {} + ChannelRPCRequesterImpl(String channelName) : + m_successfullyConnected(false), + m_channelName(channelName), + m_done(false) + { + } virtual String getRequesterName() { @@ -1194,7 +1183,7 @@ public: std::cerr << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } - virtual void channelRPCConnect(const epics::pvData::Status& status,ChannelRPC::shared_pointer const & channelRPC) + virtual void channelRPCConnect(const epics::pvData::Status& status, ChannelRPC::shared_pointer const & /*channelRPC*/) { if (status.isSuccess()) { @@ -1204,10 +1193,9 @@ public: std::cerr << "[" << m_channelName << "] channel RPC create: " << status << std::endl; } - // assign smart pointers - { + { Lock lock(m_pointerMutex); - m_channelRPC = channelRPC; + m_successfullyConnected = status.isSuccess(); } m_connectionEvent.signal(); @@ -1219,7 +1207,9 @@ public: } } - virtual void requestDone (const epics::pvData::Status &status, epics::pvData::PVStructure::shared_pointer const &pvResponse) + virtual void requestDone (const epics::pvData::Status &status, + ChannelRPC::shared_pointer const & /*channelRPC*/, + epics::pvData::PVStructure::shared_pointer const &pvResponse) { if (status.isSuccess()) { @@ -1240,19 +1230,11 @@ public: formatNT(std::cout, pvResponse); std::cout << std::endl; */ - - // this is OK since calle holds also owns it - m_channelRPC.reset(); } } else { std::cerr << "[" << m_channelName << "] failed to RPC: " << status << std::endl; - { - Lock lock(m_pointerMutex); - // this is OK since caller holds also owns it - m_channelRPC.reset(); - } } m_event.signal(); @@ -1294,12 +1276,8 @@ public: return false; } - bool connected; - { - Lock lock(m_pointerMutex); - connected = (m_channelRPC.get() != 0); - } - return connected ? true : false; + Lock lock(m_pointerMutex); + return m_successfullyConnected; } }; @@ -2051,7 +2029,8 @@ int main (int argc, char *argv[]) if (rpcRequesterImpl->waitUntilConnected(timeOut)) { - channelRPC->request(arg, true); + channelRPC->lastRequest(); + channelRPC->request(arg); allOK &= rpcRequesterImpl->waitUntilRPC(timeOut); if (allOK) { diff --git a/testApp/remote/pvget.cpp b/testApp/remote/pvget.cpp index fdaf450..06ce127 100644 --- a/testApp/remote/pvget.cpp +++ b/testApp/remote/pvget.cpp @@ -102,7 +102,6 @@ void printValue(String const & channelName, PVStructure::shared_pointer const & class ChannelGetRequesterImpl : public ChannelGetRequester { private: - ChannelGet::shared_pointer m_channelGet; PVStructure::shared_pointer m_pvStructure; BitSet::shared_pointer m_bitSet; Mutex m_pointerMutex; @@ -125,9 +124,8 @@ class ChannelGetRequesterImpl : public ChannelGetRequester std::cerr << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } - virtual void channelGetConnect(const epics::pvData::Status& status,ChannelGet::shared_pointer const & channelGet, - epics::pvData::PVStructure::shared_pointer const & pvStructure, - epics::pvData::BitSet::shared_pointer const & bitSet) + virtual void channelGetConnect(const epics::pvData::Status& status, ChannelGet::shared_pointer const & channelGet, + epics::pvData::Structure::const_shared_pointer const & /*structure*/) { if (status.isSuccess()) { @@ -137,15 +135,8 @@ class ChannelGetRequesterImpl : public ChannelGetRequester std::cerr << "[" << m_channelName << "] channel get create: " << status << std::endl; } - // assign smart pointers - { - Lock lock(m_pointerMutex); - m_channelGet = channelGet; - m_pvStructure = pvStructure; - m_bitSet = bitSet; - } - - channelGet->get(true); + channelGet->lastRequest(); + channelGet->get(); } else { @@ -154,7 +145,10 @@ class ChannelGetRequesterImpl : public ChannelGetRequester } } - virtual void getDone(const epics::pvData::Status& status) + virtual void getDone(const epics::pvData::Status& status, + ChannelGet::shared_pointer const & /*channelGet*/, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet) { if (status.isSuccess()) { @@ -167,30 +161,17 @@ class ChannelGetRequesterImpl : public ChannelGetRequester // access smart pointers { Lock lock(m_pointerMutex); + + m_pvStructure = pvStructure; + m_bitSet = bitSet; m_done = true; - /* - { - // needed since we access the data - ScopedLock dataLock(m_channelGet); - - printValue(m_channelName, m_pvStructure); - - } - */ - // this is OK since callee holds also owns it - m_channelGet.reset(); } } else { std::cerr << "[" << m_channelName << "] failed to get: " << status << std::endl; - { - Lock lock(m_pointerMutex); - // this is OK since caller holds also owns it - m_channelGet.reset(); - } } m_event.signal(); diff --git a/testApp/remote/pvput.cpp b/testApp/remote/pvput.cpp index ebb0e2e..5d484c3 100644 --- a/testApp/remote/pvput.cpp +++ b/testApp/remote/pvput.cpp @@ -251,7 +251,6 @@ class AtomicBoolean class ChannelPutRequesterImpl : public ChannelPutRequester { private: - ChannelPut::shared_pointer m_channelPut; PVStructure::shared_pointer m_pvStructure; BitSet::shared_pointer m_bitSet; Mutex m_pointerMutex; @@ -279,8 +278,7 @@ class ChannelPutRequesterImpl : public ChannelPutRequester virtual void channelPutConnect(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut, - epics::pvData::PVStructure::shared_pointer const & pvStructure, - epics::pvData::BitSet::shared_pointer const & bitSet) + epics::pvData::Structure::const_shared_pointer const & /*structure*/) { if (status.isSuccess()) { @@ -290,14 +288,6 @@ class ChannelPutRequesterImpl : public ChannelPutRequester std::cerr << "[" << m_channelName << "] channel put create: " << status << std::endl; } - // assign smart pointers - { - Lock lock(m_pointerMutex); - m_channelPut = channelPut; - m_pvStructure = pvStructure; - m_bitSet = bitSet; - } - // we always put all m_bitSet->set(0); @@ -311,7 +301,9 @@ class ChannelPutRequesterImpl : public ChannelPutRequester } } - virtual void getDone(const epics::pvData::Status& status) + virtual void getDone(const epics::pvData::Status& status, ChannelPut::shared_pointer const & /*channelPut*/, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet) { if (status.isSuccess()) { @@ -323,21 +315,11 @@ class ChannelPutRequesterImpl : public ChannelPutRequester m_done.set(); - /* - // access smart pointers - // do not print old value in terseMode - if (!m_supressGetValue.get()) { Lock lock(m_pointerMutex); - { - - // needed since we access the data - ScopedLock dataLock(m_channelPut); - - printValue(m_channelName, m_pvStructure); - } + m_pvStructure = pvStructure; + m_bitSet = bitSet; } - */ } else @@ -348,7 +330,7 @@ class ChannelPutRequesterImpl : public ChannelPutRequester m_event->signal(); } - virtual void putDone(const epics::pvData::Status& status) + virtual void putDone(const epics::pvData::Status& status, ChannelPut::shared_pointer const & /*channelPut*/) { if (status.isSuccess()) { @@ -374,6 +356,12 @@ class ChannelPutRequesterImpl : public ChannelPutRequester return m_pvStructure; } + BitSet::shared_pointer getBitSet() + { + Lock lock(m_pointerMutex); + return m_bitSet; + } + void resetEvent() { Lock lock(m_eventMutex); @@ -587,7 +575,8 @@ int main (int argc, char *argv[]) // we do a put putRequesterImpl->resetEvent(); - channelPut->put(false); + // note on bitSet: we get all, we set all + channelPut->put(putRequesterImpl->getStructure(), putRequesterImpl->getBitSet()); allOK &= putRequesterImpl->waitUntilDone(timeOut); if (allOK) diff --git a/testApp/remote/testGetPerformance.cpp b/testApp/remote/testGetPerformance.cpp index 81b8f44..fbd3929 100644 --- a/testApp/remote/testGetPerformance.cpp +++ b/testApp/remote/testGetPerformance.cpp @@ -114,7 +114,7 @@ void get_all() for (vector::const_iterator i = channelGetList.begin(); i != channelGetList.end(); i++) - (*i)->get(false); + (*i)->get(); // we assume all channels are from the same provider if (bulkMode) provider->flush(); @@ -125,9 +125,6 @@ void get_all() class ChannelGetRequesterImpl : public ChannelGetRequester { private: - ChannelGet::shared_pointer m_channelGet; - PVStructure::shared_pointer m_pvStructure; - BitSet::shared_pointer m_bitSet; Event m_event; Event m_connectionEvent; String m_channelName; @@ -153,9 +150,8 @@ public: } virtual void channelGetConnect(const epics::pvData::Status& status, - ChannelGet::shared_pointer const & channelGet, - epics::pvData::PVStructure::shared_pointer const & pvStructure, - epics::pvData::BitSet::shared_pointer const & bitSet) + ChannelGet::shared_pointer const & /*channelGet*/, + epics::pvData::Structure::const_shared_pointer const & /*structure*/) { if (status.isSuccess()) { @@ -165,10 +161,6 @@ public: std::cout << "[" << m_channelName << "] channel get create: " << status.toString() << std::endl; } - m_channelGet = channelGet; - m_pvStructure = pvStructure; - m_bitSet = bitSet; - m_connectionEvent.signal(); } else @@ -177,7 +169,10 @@ public: } } - virtual void getDone(const epics::pvData::Status& status) + virtual void getDone(const epics::pvData::Status& status, + ChannelGet::shared_pointer const & /*channelGet*/, + epics::pvData::PVStructure::shared_pointer const & /*pvStructure*/, + epics::pvData::BitSet::shared_pointer const & /*bitSet*/) { if (status.isSuccess()) { diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index 66fe170..b0b8fed 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -138,7 +138,7 @@ public: iter++) { try { - (*iter)->process(false); + (*iter)->process(); } catch (std::exception &ex) { std::cerr << "Unhandled exception caught in ProcessAction::run(): " << ex.what() << std::endl; } catch (...) { @@ -700,7 +700,8 @@ class ChannelProcessRequesterImpl : public ChannelProcessRequester //m_channelProcess = channelProcess; } - virtual void processDone(const epics::pvData::Status& /*status*/) + virtual void processDone(const epics::pvData::Status& /*status*/, + ChannelProcess::shared_pointer const &) { //std::cout << "processDone(" << status.toString() << ")" << std::endl; } @@ -714,16 +715,17 @@ class MockChannelProcess : public std::tr1::enable_shared_from_this { private: - String m_channelName; + Channel::shared_pointer m_channel; ChannelProcessRequester::shared_pointer m_channelProcessRequester; PVStructure::shared_pointer m_pvStructure; PVScalarPtr m_valueField; PVTimeStamp m_timeStamp; + AtomicBoolean m_lastRequest; protected: - MockChannelProcess(String const & channelName, ChannelProcessRequester::shared_pointer const & channelProcessRequester, + MockChannelProcess(Channel::shared_pointer const & channel, ChannelProcessRequester::shared_pointer const & channelProcessRequester, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & /*pvRequest*/) : - m_channelName(channelName), m_channelProcessRequester(channelProcessRequester), m_pvStructure(pvStructure) + m_channel(channel), m_channelProcessRequester(channelProcessRequester), m_pvStructure(pvStructure) { PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(mockChannelProcess); @@ -755,11 +757,11 @@ protected: public: static ChannelProcess::shared_pointer create( - String const & channelName, + Channel::shared_pointer const & channel, ChannelProcessRequester::shared_pointer const & channelProcessRequester, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) { - ChannelProcess::shared_pointer thisPtr(new MockChannelProcess(channelName, channelProcessRequester, pvStructure, pvRequest)); + ChannelProcess::shared_pointer thisPtr(new MockChannelProcess(channel, channelProcessRequester, pvStructure, pvRequest)); // TODO pvRequest channelProcessRequester->channelProcessConnect(Status::Ok, thisPtr); @@ -773,7 +775,7 @@ public: } - virtual void process(bool lastRequest) + virtual void process() { { ScopedLock lock(shared_from_this()); @@ -877,14 +879,24 @@ public: m_timeStamp.set(current); } - m_channelProcessRequester->processDone(Status::Ok); + m_channelProcessRequester->processDone(Status::Ok, shared_from_this()); - notifyStructureChanged(m_channelName); + notifyStructureChanged(m_channel->getChannelName()); - if (lastRequest) + if (m_lastRequest.get()) destroy(); } + virtual void lastRequest() + { + m_lastRequest.set(); + } + + virtual Channel::shared_pointer getChannel() + { + return m_channel; + } + virtual void cancel() { } @@ -932,19 +944,20 @@ class MockChannelGet : public std::tr1::enable_shared_from_this { private: - String m_channelName; + Channel::shared_pointer m_channel; ChannelGetRequester::shared_pointer m_channelGetRequester; PVStructure::shared_pointer m_pvStructure; BitSet::shared_pointer m_bitSet; ChannelProcess::shared_pointer m_channelProcess; AtomicBoolean m_changed; + AtomicBoolean m_lastRequest; protected: MockChannelGet(Channel::shared_pointer const & channel, ChannelGetRequester::shared_pointer const & channelGetRequester, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) : - m_channelName(channel->getChannelName()), + m_channel(channel), m_channelGetRequester(channelGetRequester), m_pvStructure(getRequestedStructure(pvStructure, pvRequest)), m_bitSet(new BitSet(m_pvStructure->getNumberFields())), @@ -967,8 +980,7 @@ public: structureChangedListeners[channel->getChannelName()].push_back(std::tr1::dynamic_pointer_cast(thisPtr)); channelGetRequester->channelGetConnect(Status::Ok, thisPtr, - static_cast(thisPtr.get())->m_pvStructure, - static_cast(thisPtr.get())->m_bitSet); + static_cast(thisPtr.get())->m_pvStructure->getStructure()); return thisPtr; } @@ -977,10 +989,10 @@ public: PVACCESS_REFCOUNT_MONITOR_DESTRUCT(mockChannelGet); } - virtual void get(bool lastRequest) + virtual void get() { if (m_channelProcess) - m_channelProcess->process(false); + m_channelProcess->process(); // TODO far from being thread-safe if (m_changed.get()) @@ -991,9 +1003,9 @@ public: else m_bitSet->clear(0); - m_channelGetRequester->getDone(Status::Ok); + m_channelGetRequester->getDone(Status::Ok, shared_from_this(), m_pvStructure, m_bitSet); - if (lastRequest) + if (m_lastRequest.get()) destroy(); } @@ -1002,6 +1014,16 @@ public: m_changed.set(); } + virtual void lastRequest() + { + m_lastRequest.set(); + } + + virtual Channel::shared_pointer getChannel() + { + return m_channel; + } + virtual void cancel() { } @@ -1012,9 +1034,9 @@ public: m_channelProcess->destroy(); // remove itself from listeners table - if (structureChangedListeners.count(m_channelName)) + if (structureChangedListeners.count(m_channel->getChannelName())) { - vector &vec = structureChangedListeners[m_channelName]; + vector &vec = structureChangedListeners[m_channel->getChannelName()]; for (vector::iterator i = vec.begin(); i != vec.end(); i++) { @@ -1043,21 +1065,24 @@ public: PVACCESS_REFCOUNT_MONITOR_DEFINE(mockChannelPut); -class MockChannelPut : public ChannelPut +class MockChannelPut : + public ChannelPut, + public std::tr1::enable_shared_from_this { private: - String m_channelName; + Channel::shared_pointer m_channel; ChannelPutRequester::shared_pointer m_channelPutRequester; PVStructure::shared_pointer m_pvStructure; BitSet::shared_pointer m_bitSet; ChannelProcess::shared_pointer m_channelProcess; - + AtomicBoolean m_lastRequest; + protected: MockChannelPut(Channel::shared_pointer const & channel, ChannelPutRequester::shared_pointer const & channelPutRequester, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) : - m_channelName(channel->getChannelName()), + m_channel(channel), m_channelPutRequester(channelPutRequester), m_pvStructure(getRequestedStructure(pvStructure, pvRequest)), m_bitSet(new BitSet(m_pvStructure->getNumberFields())), @@ -1075,9 +1100,7 @@ public: { ChannelPut::shared_pointer thisPtr(new MockChannelPut(channel, channelPutRequester, pvStructure, pvRequest)); channelPutRequester->channelPutConnect(Status::Ok, thisPtr, - static_cast(thisPtr.get())->m_pvStructure, - static_cast(thisPtr.get())->m_bitSet); - + static_cast(thisPtr.get())->m_pvStructure->getStructure()); return thisPtr; } @@ -1087,28 +1110,43 @@ public: } - virtual void put(bool lastRequest) + virtual void put(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & putBitSet) { + // TODO data - do an actual put !!! + if (m_channelProcess) - m_channelProcess->process(false); + m_channelProcess->process(); - m_channelPutRequester->putDone(Status::Ok); + m_channelPutRequester->putDone(Status::Ok, shared_from_this()); - notifyStructureChanged(m_channelName); + notifyStructureChanged(m_channel->getChannelName()); - if (lastRequest) + if (m_lastRequest.get()) destroy(); } virtual void get() { - m_channelPutRequester->getDone(Status::Ok); + m_channelPutRequester->getDone(Status::Ok, shared_from_this(), m_pvStructure, m_bitSet); + + if (m_lastRequest.get()) + destroy(); } virtual void cancel() { } + virtual void lastRequest() + { + m_lastRequest.set(); + } + + virtual Channel::shared_pointer getChannel() + { + return m_channel; + } + virtual void destroy() { if (m_channelProcess) @@ -1131,28 +1169,38 @@ public: PVACCESS_REFCOUNT_MONITOR_DEFINE(mockChannelPutGet); -class MockChannelPutGet : public ChannelPutGet +class MockChannelPutGet : + public ChannelPutGet, + public std::tr1::enable_shared_from_this { private: - String m_channelName; + Channel::shared_pointer m_channel; ChannelPutGetRequester::shared_pointer m_channelPutGetRequester; PVStructure::shared_pointer m_getStructure; + BitSet::shared_pointer m_getBitSet; PVStructure::shared_pointer m_putStructure; + BitSet::shared_pointer m_putBitSet; ChannelProcess::shared_pointer m_channelProcess; + AtomicBoolean m_lastRequest; protected: MockChannelPutGet(Channel::shared_pointer const & channel, ChannelPutGetRequester::shared_pointer const & channelPutGetRequester, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) : - m_channelName(channel->getChannelName()), + m_channel(channel), m_channelPutGetRequester(channelPutGetRequester), m_getStructure(getRequestedStructure(pvStructure, pvRequest, "getField")), + m_getBitSet(new BitSet(m_getStructure->getNumberFields())), m_putStructure(getRequestedStructure(pvStructure, pvRequest, "putField")), + m_putBitSet(new BitSet(m_putStructure->getNumberFields())), m_channelProcess(getChannelProcess(channel, pvRequest)) { PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(mockChannelPutGet); + + // always all + m_getBitSet->set(0); } public: @@ -1165,8 +1213,8 @@ public: ChannelPutGet::shared_pointer thisPtr(new MockChannelPutGet(channel, channelPutGetRequester, pvStructure, pvRequest)); channelPutGetRequester->channelPutGetConnect(Status::Ok, thisPtr, - static_cast(thisPtr.get())->m_putStructure, - static_cast(thisPtr.get())->m_getStructure); + static_cast(thisPtr.get())->m_putStructure->getStructure(), + static_cast(thisPtr.get())->m_getStructure->getStructure()); return thisPtr; } @@ -1176,27 +1224,49 @@ public: PVACCESS_REFCOUNT_MONITOR_DESTRUCT(mockChannelPutGet); } - virtual void putGet(bool lastRequest) + virtual void putGet(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & putBitSet) { + // TODO !!! copy what was put... + if (m_channelProcess) - m_channelProcess->process(false); + m_channelProcess->process(); - m_channelPutGetRequester->putGetDone(Status::Ok); + m_channelPutGetRequester->putGetDone(Status::Ok, shared_from_this(), m_getStructure, m_getBitSet); - notifyStructureChanged(m_channelName); + notifyStructureChanged(m_channel->getChannelName()); - if (lastRequest) + if (m_lastRequest.get()) destroy(); } virtual void getGet() { - m_channelPutGetRequester->getGetDone(Status::Ok); + m_channelPutGetRequester->getGetDone(Status::Ok, shared_from_this(), m_getStructure, m_getBitSet); + + if (m_lastRequest.get()) + destroy(); } virtual void getPut() { - m_channelPutGetRequester->getPutDone(Status::Ok); + // putGet might mess with bitSet + m_putBitSet->clear(); + m_putBitSet->set(0); + + m_channelPutGetRequester->getPutDone(Status::Ok, shared_from_this(), m_putStructure, m_putBitSet); + + if (m_lastRequest.get()) + destroy(); + } + + virtual void lastRequest() + { + m_lastRequest.set(); + } + + virtual Channel::shared_pointer getChannel() + { + return m_channel; } virtual void cancel() @@ -1224,6 +1294,7 @@ public: static bool handleHelp( epics::pvData::PVStructure::shared_pointer const & args, + ChannelRPC::shared_pointer const & channelRPC, ChannelRPCRequester::shared_pointer const & channelRPCRequester, String const & helpText ) @@ -1244,7 +1315,7 @@ static bool handleHelp( ); static_pointer_cast(result->getStringField("value"))->put(helpText); - channelRPCRequester->requestDone(Status::Ok, result); + channelRPCRequester->requestDone(Status::Ok, channelRPC, result); return true; } else @@ -1256,26 +1327,31 @@ static bool handleHelp( PVACCESS_REFCOUNT_MONITOR_DEFINE(mockChannelRPC); -class MockChannelRPC : public ChannelRPC +class MockChannelRPC : + public ChannelRPC, + public std::tr1::enable_shared_from_this { private: ChannelRPCRequester::shared_pointer m_channelRPCRequester; - String m_channelName; + Channel::shared_pointer m_channel; PVStructure::shared_pointer m_pvStructure; + AtomicBoolean m_lastRequest; protected: MockChannelRPC(ChannelRPCRequester::shared_pointer const & channelRPCRequester, - String const & channelName, PVStructure::shared_pointer const & pvStructure, + Channel::shared_pointer const & channel, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & /*pvRequest*/) : - m_channelRPCRequester(channelRPCRequester), m_channelName(channelName), m_pvStructure(pvStructure) + m_channelRPCRequester(channelRPCRequester), m_channel(channel), m_pvStructure(pvStructure) { PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(mockChannelRPC); } public: - static ChannelRPC::shared_pointer create(ChannelRPCRequester::shared_pointer const & channelRPCRequester, String const & channelName, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) + static ChannelRPC::shared_pointer create(ChannelRPCRequester::shared_pointer const & channelRPCRequester, + Channel::shared_pointer const & channel, + PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) { - ChannelRPC::shared_pointer thisPtr(new MockChannelRPC(channelRPCRequester, channelName, pvStructure, pvRequest)); + ChannelRPC::shared_pointer thisPtr(new MockChannelRPC(channelRPCRequester, channel, pvStructure, pvRequest)); // TODO pvRequest channelRPCRequester->channelRPCConnect(Status::Ok, thisPtr); return thisPtr; @@ -1286,9 +1362,10 @@ public: PVACCESS_REFCOUNT_MONITOR_DESTRUCT(mockChannelRPC); } - virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument, bool lastRequest) + virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument) { - if (m_channelName == "testNTTable") + String channelName = m_channel->getChannelName(); + if (channelName == "testNTTable") { PVStructure::shared_pointer args( (pvArgument->getStructure()->getID() == "uri:ev4:nt/2012/pwd:NTURI") ? @@ -1300,7 +1377,7 @@ public: "Generates a NTTable structure response with 10 rows and a specified number of columns.\n" "Columns are labeled 'column' and values are ' + random [0..1)'.\n" "Arguments:\n\tstring columns\tnumber of table columns\n"; - if (handleHelp(args, m_channelRPCRequester, helpText)) + if (handleHelp(args, shared_from_this(), m_channelRPCRequester, helpText)) return; PVStringPtr columns = dynamic_pointer_cast(args->getSubField("columns")); @@ -1308,17 +1385,17 @@ public: { PVStructure::shared_pointer nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, "no string 'columns' argument specified"); - m_channelRPCRequester->requestDone(errorStatus, nullPtr); + m_channelRPCRequester->requestDone(errorStatus, shared_from_this(), nullPtr); } else { int columnsCount = atoi(columns->get().c_str()); PVStructure::shared_pointer result = createNTTable(columnsCount); generateNTTableDoubleValues(result); - m_channelRPCRequester->requestDone(Status::Ok, result); + m_channelRPCRequester->requestDone(Status::Ok, shared_from_this(), result); } } - else if (m_channelName == "testNTNameValue") + else if (channelName == "testNTNameValue") { PVStructure::shared_pointer args( (pvArgument->getStructure()->getID() == "uri:ev4:nt/2012/pwd:NTURI") ? @@ -1330,7 +1407,7 @@ public: "Generates a NTNameValue structure response with a specified number of columns.\n" "Columns are labeled 'name' and values are ' + random [0..1)'.\n" "Arguments:\n\tstring columns\tnumber of columns\n"; - if (handleHelp(args, m_channelRPCRequester, helpText)) + if (handleHelp(args, shared_from_this(), m_channelRPCRequester, helpText)) return; PVStringPtr columns = dynamic_pointer_cast(args->getSubField("columns")); @@ -1338,7 +1415,7 @@ public: { PVStructure::shared_pointer nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, "no string 'columns' argument specified"); - m_channelRPCRequester->requestDone(errorStatus, nullPtr); + m_channelRPCRequester->requestDone(errorStatus, shared_from_this(), nullPtr); } else { @@ -1374,10 +1451,10 @@ public: mv[r] = rand()/((double)RAND_MAX+1) + (int)(r); result->getSubField("value")->replace(freeze(mv)); - m_channelRPCRequester->requestDone(Status::Ok, result); + m_channelRPCRequester->requestDone(Status::Ok, shared_from_this(), result); } } - else if (m_channelName == "testNTMatrix") + else if (channelName == "testNTMatrix") { PVStructure::shared_pointer args( (pvArgument->getStructure()->getID() == "uri:ev4:nt/2012/pwd:NTURI") ? @@ -1392,7 +1469,7 @@ public: "\tstring rows\tnumber of matrix rows\n" "\tstring columns\tnumber of matrix columns\n" "\t[string bycolumns\torder matrix values in a column-major order]\n"; - if (handleHelp(args, m_channelRPCRequester, helpText)) + if (handleHelp(args, shared_from_this(), m_channelRPCRequester, helpText)) return; PVStringPtr rows = dynamic_pointer_cast(args->getSubField("rows")); @@ -1401,7 +1478,7 @@ public: { PVStructure::shared_pointer nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, "no string 'rows' and 'columns' arguments specified"); - m_channelRPCRequester->requestDone(errorStatus, nullPtr); + m_channelRPCRequester->requestDone(errorStatus, shared_from_this(), nullPtr); } else { @@ -1439,10 +1516,10 @@ public: mv[r] = rand()/((double)RAND_MAX+1) + (int)(r/colsVal); result->getSubField("value")->replace(freeze(mv)); - m_channelRPCRequester->requestDone(Status::Ok, result); + m_channelRPCRequester->requestDone(Status::Ok, shared_from_this(), result); } } - else if (m_channelName.find("testImage") == 0) + else if (channelName.find("testImage") == 0) { PVStructure::shared_pointer args( (pvArgument->getStructure()->getID() == "uri:ev4:nt/2012/pwd:NTURI") ? @@ -1461,7 +1538,7 @@ public: "\t\t\t\tconvert my_image.png my_image.rgb\n" "\tstring w\timage width\n" "\tstring h\timage height\n"; - if (handleHelp(args, m_channelRPCRequester, helpText)) + if (handleHelp(args, shared_from_this(), m_channelRPCRequester, helpText)) return; PVStringPtr file = dynamic_pointer_cast(args->getSubField("file")); @@ -1471,7 +1548,7 @@ public: { PVStructure::shared_pointer nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, "not all 'file', 'w' and 'h' arguments specified"); - m_channelRPCRequester->requestDone(errorStatus, nullPtr); + m_channelRPCRequester->requestDone(errorStatus, shared_from_this(), nullPtr); } else { @@ -1515,47 +1592,47 @@ public: in.readsome((char*)temp.data(), fileSize); value->replace(freeze(temp)); - m_channelRPCRequester->requestDone(Status::Ok, m_pvStructure); + m_channelRPCRequester->requestDone(Status::Ok, shared_from_this(), m_pvStructure); // for monitors - notifyStructureChanged(m_channelName); + notifyStructureChanged(channelName); } else { PVStructure::shared_pointer nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, "file size does not match given 'w' and 'h'"); - m_channelRPCRequester->requestDone(errorStatus, nullPtr); + m_channelRPCRequester->requestDone(errorStatus, shared_from_this(), nullPtr); } } else { PVStructure::shared_pointer nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, "failed to open image file specified"); - m_channelRPCRequester->requestDone(errorStatus, nullPtr); + m_channelRPCRequester->requestDone(errorStatus, shared_from_this(), nullPtr); } } } - else if (m_channelName == "testNTURI") + else if (channelName == "testNTURI") { const String helpText = "Returns the NTURI structure response identical the NTURI request.\n" "Arguments: (none)\n"; - if (handleHelp(pvArgument, m_channelRPCRequester, helpText)) + if (handleHelp(pvArgument, shared_from_this(), m_channelRPCRequester, helpText)) return; if (pvArgument->getStructure()->getID() != "uri:ev4:nt/2012/pwd:NTURI") { PVStructure::shared_pointer nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, "argument is not a NTURI structure"); - m_channelRPCRequester->requestDone(errorStatus, nullPtr); + m_channelRPCRequester->requestDone(errorStatus, shared_from_this(), nullPtr); } else { // return argument as result - m_channelRPCRequester->requestDone(Status::Ok, pvArgument); + m_channelRPCRequester->requestDone(Status::Ok, shared_from_this(), pvArgument); } } - else if (m_channelName == "testSum") { + else if (channelName == "testSum") { PVStructure::shared_pointer args( (pvArgument->getStructure()->getID() == "uri:ev4:nt/2012/pwd:NTURI") ? @@ -1568,7 +1645,7 @@ public: "Arguments:\n" "\tint a\tfirst integer number\n" "\tint b\tsecond integer number\n"; - if (handleHelp(args, m_channelRPCRequester, helpText)) + if (handleHelp(args, shared_from_this(), m_channelRPCRequester, helpText)) return; PVInt::shared_pointer pa = args->getSubField("a"); @@ -1577,7 +1654,7 @@ public: { PVStructure::shared_pointer nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, "int a and int b arguments are required"); - m_channelRPCRequester->requestDone(errorStatus, nullPtr); + m_channelRPCRequester->requestDone(errorStatus, shared_from_this(), nullPtr); return; } @@ -1595,13 +1672,13 @@ public: PVStructure::shared_pointer result = getPVDataCreate()->createPVStructure(resultStructure); result->getIntField("c")->put(a+b); - m_channelRPCRequester->requestDone(Status::Ok, result); + m_channelRPCRequester->requestDone(Status::Ok, shared_from_this(), result); } - else if (m_channelName.find("testServerShutdown") == 0) + else if (channelName.find("testServerShutdown") == 0) { PVStructure::shared_pointer nullPtr; - m_channelRPCRequester->requestDone(Status::Ok, nullPtr); + m_channelRPCRequester->requestDone(Status::Ok, shared_from_this(), nullPtr); testServerShutdown(); } else @@ -1611,13 +1688,23 @@ public: pvArgument->toString(&s); std::cout << "RPC" << std::endl << s << std::endl; */ - m_channelRPCRequester->requestDone(Status::Ok, m_pvStructure); + m_channelRPCRequester->requestDone(Status::Ok, shared_from_this(), m_pvStructure); } - if (lastRequest) + if (m_lastRequest.get()) destroy(); } + virtual void lastRequest() + { + m_lastRequest.set(); + } + + virtual Channel::shared_pointer getChannel() + { + return m_channel; + } + virtual void cancel() { } @@ -1643,22 +1730,24 @@ public: - - - PVACCESS_REFCOUNT_MONITOR_DEFINE(mockChannelArray); -class MockChannelArray : public ChannelArray +class MockChannelArray : + public ChannelArray, + public std::tr1::enable_shared_from_this { private: + Channel::shared_pointer m_channel; ChannelArrayRequester::shared_pointer m_channelArrayRequester; PVArray::shared_pointer m_pvArray; PVArray::shared_pointer m_pvStructureArray; + AtomicBoolean m_lastRequest; protected: - MockChannelArray(ChannelArrayRequester::shared_pointer const & channelArrayRequester, + MockChannelArray(Channel::shared_pointer const & channel, + ChannelArrayRequester::shared_pointer const & channelArrayRequester, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & /*pvRequest*/) : - m_channelArrayRequester(channelArrayRequester) + m_channel(channel), m_channelArrayRequester(channelArrayRequester) { PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(mockChannelArray); @@ -1669,17 +1758,19 @@ protected: } public: - static ChannelArray::shared_pointer create(ChannelArrayRequester::shared_pointer const & channelArrayRequester, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) + static ChannelArray::shared_pointer create(Channel::shared_pointer const & channel, + ChannelArrayRequester::shared_pointer const & channelArrayRequester, + PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) { - ChannelArray::shared_pointer thisPtr(new MockChannelArray(channelArrayRequester, pvStructure, pvRequest)); + ChannelArray::shared_pointer thisPtr(new MockChannelArray(channel, channelArrayRequester, pvStructure, pvRequest)); PVArray::shared_pointer array(static_cast(thisPtr.get())->m_pvArray); if (array.get()) - channelArrayRequester->channelArrayConnect(Status::Ok, thisPtr, array); + channelArrayRequester->channelArrayConnect(Status::Ok, thisPtr, array->getArray()); else { Status errorStatus(Status::STATUSTYPE_ERROR, "no 'value' subfield of array type"); - channelArrayRequester->channelArrayConnect(errorStatus, thisPtr, array); + channelArrayRequester->channelArrayConnect(errorStatus, thisPtr, Array::const_shared_pointer()); } return thisPtr; @@ -1713,39 +1804,42 @@ public: to->replace(freeze(temp)); } - virtual void putArray(bool lastRequest, size_t offset, size_t count) + virtual void putArray(PVArray::shared_pointer const & pvArray, size_t offset, size_t count, size_t stride) { + // TODO stride support !!! + size_t o = offset; - if (count == 0) count = m_pvArray->getLength(); + if (count == 0) count = pvArray->getLength(); size_t c = count; - Field::const_shared_pointer field = m_pvArray->getField(); + Field::const_shared_pointer field = pvArray->getField(); Type type = field->getType(); if (type == scalarArray) { switch (std::tr1::static_pointer_cast(field)->getElementType()) { - case pvBoolean: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvByte: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvShort: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvInt: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvLong: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvUByte: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvUShort: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvUInt: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvULong: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvFloat: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvDouble: put(m_pvArray, m_pvStructureArray, o, c); break; - case pvString: put(m_pvArray, m_pvStructureArray, o, c); break; + case pvBoolean: put(pvArray, m_pvStructureArray, o, c); break; + case pvByte: put(pvArray, m_pvStructureArray, o, c); break; + case pvShort: put(pvArray, m_pvStructureArray, o, c); break; + case pvInt: put(pvArray, m_pvStructureArray, o, c); break; + case pvLong: put(pvArray, m_pvStructureArray, o, c); break; + case pvUByte: put(pvArray, m_pvStructureArray, o, c); break; + case pvUShort: put(pvArray, m_pvStructureArray, o, c); break; + case pvUInt: put(pvArray, m_pvStructureArray, o, c); break; + case pvULong: put(pvArray, m_pvStructureArray, o, c); break; + case pvFloat: put(pvArray, m_pvStructureArray, o, c); break; + case pvDouble: put(pvArray, m_pvStructureArray, o, c); break; + case pvString: put(pvArray, m_pvStructureArray, o, c); break; } } else if (type == structureArray) - put(m_pvArray, m_pvStructureArray, o, c); + put(pvArray, m_pvStructureArray, o, c); else if (type == unionArray) - put(m_pvArray, m_pvStructureArray, o, c); + put(pvArray, m_pvStructureArray, o, c); - m_channelArrayRequester->putArrayDone(Status::Ok); - if (lastRequest) + m_channelArrayRequester->putArrayDone(Status::Ok, shared_from_this()); + + if (m_lastRequest.get()) destroy(); } @@ -1765,8 +1859,10 @@ public: } - virtual void getArray(bool lastRequest, size_t offset, size_t count) + virtual void getArray(size_t offset, size_t count, size_t stride) { + // TODO stride support !!! + size_t o = offset; if (count == 0) count = m_pvStructureArray->getLength(); size_t c = count; @@ -1796,12 +1892,13 @@ public: else if (type == unionArray) get(m_pvStructureArray, m_pvArray, o, c); - m_channelArrayRequester->getArrayDone(Status::Ok); - if (lastRequest) + m_channelArrayRequester->getArrayDone(Status::Ok, shared_from_this(), m_pvArray); + + if (m_lastRequest.get()) destroy(); } - virtual void setLength(bool lastRequest, size_t length, size_t capacity) + virtual void setLength(size_t length, size_t capacity) { if (capacity > 0) { m_pvStructureArray->setCapacity(capacity); @@ -1809,11 +1906,32 @@ public: m_pvStructureArray->setLength(length); - m_channelArrayRequester->setLengthDone(Status::Ok); - if (lastRequest) + m_channelArrayRequester->setLengthDone(Status::Ok, shared_from_this()); + + if (m_lastRequest.get()) destroy(); } + virtual void getLength() + { + + m_channelArrayRequester->getLengthDone(Status::Ok, shared_from_this(), + m_pvStructureArray->getLength(), m_pvStructureArray->getCapacity()); + + if (m_lastRequest.get()) + destroy(); + } + + virtual void lastRequest() + { + m_lastRequest.set(); + } + + virtual Channel::shared_pointer getChannel() + { + return m_channel; + } + virtual void cancel() { } @@ -2274,7 +2392,7 @@ public: ChannelProcessRequester::shared_pointer const & channelProcessRequester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return MockChannelProcess::create(m_name, channelProcessRequester, m_pvStructure, pvRequest); + return MockChannelProcess::create(shared_from_this(), channelProcessRequester, m_pvStructure, pvRequest); } virtual ChannelGet::shared_pointer createChannelGet( @@ -2301,7 +2419,7 @@ public: virtual ChannelRPC::shared_pointer createChannelRPC(ChannelRPCRequester::shared_pointer const & channelRPCRequester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return MockChannelRPC::create(channelRPCRequester, m_name, m_pvStructure, pvRequest); + return MockChannelRPC::create(channelRPCRequester, shared_from_this(), m_pvStructure, pvRequest); } virtual epics::pvData::Monitor::shared_pointer createMonitor( @@ -2315,7 +2433,7 @@ public: ChannelArrayRequester::shared_pointer const & channelArrayRequester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return MockChannelArray::create(channelArrayRequester, m_pvStructure, pvRequest); + return MockChannelArray::create(shared_from_this(), channelArrayRequester, m_pvStructure, pvRequest); } virtual void printInfo() { @@ -2578,8 +2696,7 @@ void testServer(int timeToRun) //ServerContextImpl::shared_pointer ctx = ServerContextImpl::create(); ctx = ServerContextImpl::create(); - ChannelAccess::shared_pointer channelAccess = getChannelProviderRegistry(); - ctx->initialize(channelAccess); + ctx->initialize(getChannelProviderRegistry()); ctx->printInfo(); From 6b388a572e97a8d0d8e1aa4b8d41e33ef25e2115 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Fri, 23 May 2014 09:29:17 +0200 Subject: [PATCH 12/32] everything compiles now --- pvAccessApp/pva/pvaVersion.h | 4 +- pvAccessApp/remote/codec.cpp | 1 + pvAccessApp/server/responseHandlers.cpp | 23 ++- testApp/remote/syncTestRequesters.h | 187 +++++++++++++++++++----- 4 files changed, 168 insertions(+), 47 deletions(-) diff --git a/pvAccessApp/pva/pvaVersion.h b/pvAccessApp/pva/pvaVersion.h index 9596237..2efb63b 100644 --- a/pvAccessApp/pva/pvaVersion.h +++ b/pvAccessApp/pva/pvaVersion.h @@ -25,8 +25,8 @@ // module version // TODO to be generated, etc. #define EPICS_PVA_MAJOR_VERSION 3 -#define EPICS_PVA_MINOR_VERSION 0 -#define EPICS_PVA_MAINTENANCE_VERSION 5 +#define EPICS_PVA_MINOR_VERSION 1 +#define EPICS_PVA_MAINTENANCE_VERSION 0 #define EPICS_PVA_DEVELOPMENT_FLAG 1 namespace epics { diff --git a/pvAccessApp/remote/codec.cpp b/pvAccessApp/remote/codec.cpp index e26f25a..f523737 100644 --- a/pvAccessApp/remote/codec.cpp +++ b/pvAccessApp/remote/codec.cpp @@ -1113,6 +1113,7 @@ namespace epics { void BlockingSocketAbstractCodec::internalDestroy() { if(_channel != INVALID_SOCKET) { + // TODO ::shutdown for some OS??!!! epicsSocketDestroy(_channel); _channel = INVALID_SOCKET; } diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index 3dbab5e..fda46aa 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -898,9 +898,12 @@ void ServerChannelPutRequesterImpl::channelPutConnect(const Status& status, Chan _structure = structure; } - _putPVStructure = std::tr1::static_pointer_cast(reuseOrCreatePVField(_structure, _putPVStructure)); - _putBitSet = createBitSetFor(_putPVStructure, _putBitSet); - + if (status.isSuccess()) + { + _putPVStructure = std::tr1::static_pointer_cast(reuseOrCreatePVField(_structure, _putPVStructure)); + _putBitSet = createBitSetFor(_putPVStructure, _putBitSet); + } + TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -1133,9 +1136,12 @@ void ServerChannelPutGetRequesterImpl::channelPutGetConnect(const Status& status _getStructure = getStructure; } - _pvPutGetStructure = std::tr1::static_pointer_cast(reuseOrCreatePVField(_putStructure, _pvPutGetStructure)); - _pvPutGetBitSet = createBitSetFor(_pvPutGetStructure, _pvPutGetBitSet); - + if (status.isSuccess()) + { + _pvPutGetStructure = std::tr1::static_pointer_cast(reuseOrCreatePVField(_putStructure, _pvPutGetStructure)); + _pvPutGetBitSet = createBitSetFor(_pvPutGetStructure, _pvPutGetBitSet); + } + TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); @@ -1635,7 +1641,10 @@ void ServerChannelArrayRequesterImpl::channelArrayConnect(const Status& status, _array = array; } - _pvArray = std::tr1::static_pointer_cast(reuseOrCreatePVField(_array, _pvArray)); + if (status.isSuccess()) + { + _pvArray = std::tr1::static_pointer_cast(reuseOrCreatePVField(_array, _pvArray)); + } TransportSender::shared_pointer thisSender = shared_from_this(); _transport->enqueueSendRequest(thisSender); diff --git a/testApp/remote/syncTestRequesters.h b/testApp/remote/syncTestRequesters.h index d100e03..0837d8b 100755 --- a/testApp/remote/syncTestRequesters.h +++ b/testApp/remote/syncTestRequesters.h @@ -307,7 +307,9 @@ class SyncChannelGetRequesterImpl : public ChannelGetRequester, public SyncBaseR bool syncGet(bool lastRequest, long timeOut) { - m_channelGet->get(lastRequest); + if (lastRequest) + m_channelGet->lastRequest(); + m_channelGet->get(); return waitUntilGetDone(timeOut); } @@ -352,8 +354,7 @@ class SyncChannelGetRequesterImpl : public ChannelGetRequester, public SyncBaseR virtual void channelGetConnect( const epics::pvData::Status& status,ChannelGet::shared_pointer const & channelGet, - epics::pvData::PVStructure::shared_pointer const & pvStructure, - epics::pvData::BitSet::shared_pointer const & bitSet) + epics::pvData::Structure::const_shared_pointer const & /*structure*/) { if (m_debug) std::cout << getRequesterName() << "." << "channelGetConnect(" << status.toString() << ")" << std::endl; @@ -363,10 +364,8 @@ class SyncChannelGetRequesterImpl : public ChannelGetRequester, public SyncBaseR { Lock lock(m_pointerMutex); m_channelGet = channelGet; - m_pvStructure = pvStructure; - m_bitSet = bitSet; } - channelGet->get(false); + channelGet->get(); } else { @@ -375,11 +374,21 @@ class SyncChannelGetRequesterImpl : public ChannelGetRequester, public SyncBaseR } - virtual void getDone(const epics::pvData::Status& status) + virtual void getDone(const epics::pvData::Status& status, + ChannelGet::shared_pointer const & channelGet, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet) { if (m_debug) std::cout << getRequesterName() << "." << "getDone(" << status.toString() << ")" << std::endl; + { + Lock lock(m_pointerMutex); + m_channelGet = channelGet; + m_pvStructure = pvStructure; + m_bitSet = bitSet; + } + setGetStatus(status.isSuccess()); signalEvent(); } @@ -405,6 +414,7 @@ class SyncChannelPutRequesterImpl : public ChannelPutRequester, public SyncBaseR SyncBaseRequester(debug), m_channelName(channelName) {} + // requires to do a get first bool syncPut(bool lastRequest, long timeOut) { @@ -412,7 +422,9 @@ class SyncChannelPutRequesterImpl : public ChannelPutRequester, public SyncBaseR return false; } - m_channelPut->put(lastRequest); + if (lastRequest) + m_channelPut->lastRequest(); + m_channelPut->put(getPVStructure(), getBitSet()); return waitUntilPutDone(timeOut); } @@ -464,8 +476,7 @@ class SyncChannelPutRequesterImpl : public ChannelPutRequester, public SyncBaseR virtual void channelPutConnect(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut, - epics::pvData::PVStructure::shared_pointer const & pvStructure, - epics::pvData::BitSet::shared_pointer const & bitSet) + epics::pvData::Structure::const_shared_pointer const & /*structure*/) { if (m_debug) @@ -477,8 +488,6 @@ class SyncChannelPutRequesterImpl : public ChannelPutRequester, public SyncBaseR { Lock lock(m_pointerMutex); m_channelPut = channelPut; - m_pvStructure = pvStructure; - m_bitSet = bitSet; } setConnectedStatus(true); } @@ -491,21 +500,37 @@ class SyncChannelPutRequesterImpl : public ChannelPutRequester, public SyncBaseR } - virtual void getDone(const epics::pvData::Status& status) + virtual void getDone(const epics::pvData::Status& status, + ChannelPut::shared_pointer const & channelPut, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet) { if (m_debug) std::cout << getRequesterName() << "." << "getDone(" << status.toString() << ")" << std::endl; + { + Lock lock(m_pointerMutex); + m_channelPut = channelPut; + m_pvStructure = pvStructure; + m_bitSet = bitSet; + } + setGetStatus(status.isSuccess()); signalEvent(); } - virtual void putDone(const epics::pvData::Status& status) + virtual void putDone(const epics::pvData::Status& status, + ChannelPut::shared_pointer const & channelPut) { if (m_debug) std::cout << getRequesterName() << "." << "putDone(" << status.toString() << ")" << std::endl; + { + Lock lock(m_pointerMutex); + m_channelPut = channelPut; + } + setPutStatus(status.isSuccess()); signalEvent(); } @@ -592,7 +617,9 @@ class SyncChannelProcessRequesterImpl : public ChannelProcessRequester, public S return false; } - m_channelProcess->process(lastRequest); + if (lastRequest) + m_channelProcess->lastRequest(); + m_channelProcess->process(); return waitUntilProcessDone(timeOut); } @@ -640,11 +667,17 @@ class SyncChannelProcessRequesterImpl : public ChannelProcessRequester, public S } - virtual void processDone(const epics::pvData::Status& status) + virtual void processDone(const epics::pvData::Status& status, + ChannelProcess::shared_pointer const & channelProcess) { if (m_debug) std::cout << getRequesterName() << "." << "processDone(" << status.toString() << ")" << std::endl; + { + Lock lock(m_pointerMutex); + m_channelProcess = channelProcess; + } + setProcessStatus(status.isSuccess()); signalEvent(); } @@ -681,13 +714,16 @@ class SyncChannelPutGetRequesterImpl : public ChannelPutGetRequester, public Syn } + // requires getput is called first bool syncPutGet(bool lastRequest, double timeOut) { if(!getConnectedStatus()) { return false; } - m_channelPutGet->putGet(lastRequest); + if (lastRequest) + m_channelPutGet->lastRequest(); + m_channelPutGet->putGet(getPVPutStructure(), getPVPutBitSet()); return waitUntilPutGetDone(timeOut); } @@ -709,6 +745,12 @@ class SyncChannelPutGetRequesterImpl : public ChannelPutGetRequester, public Syn return m_putData; } + BitSet::shared_pointer getPVPutBitSet() + { + Lock lock(m_pointerMutex); + return m_putBitSet; + } + PVStructure::shared_pointer getPVGetStructure() { @@ -716,6 +758,11 @@ class SyncChannelPutGetRequesterImpl : public ChannelPutGetRequester, public Syn return m_getData; } + BitSet::shared_pointer getPVGetBitSet() + { + Lock lock(m_pointerMutex); + return m_getBitSet; + } ChannelPutGet::shared_pointer getChannelPutGet() { @@ -740,8 +787,8 @@ class SyncChannelPutGetRequesterImpl : public ChannelPutGetRequester, public Syn virtual void channelPutGetConnect(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const & channelPutGet, - epics::pvData::PVStructure::shared_pointer const & putData, - epics::pvData::PVStructure::shared_pointer const & getData) + epics::pvData::Structure::const_shared_pointer const & /*putStructure*/, + epics::pvData::Structure::const_shared_pointer const & /*getStructure*/) { if (m_debug) std::cout << getRequesterName() << "." << "channelGetPutConnect(" @@ -752,8 +799,8 @@ class SyncChannelPutGetRequesterImpl : public ChannelPutGetRequester, public Syn { Lock lock(m_pointerMutex); m_channelPutGet = channelPutGet; - m_putData = putData; - m_getData = getData; + //m_putStructure = putStructure; + //m_getStructure = getStructure; } setConnectedStatus(true); } @@ -766,13 +813,21 @@ class SyncChannelPutGetRequesterImpl : public ChannelPutGetRequester, public Syn } - virtual void getGetDone(const epics::pvData::Status& status) + virtual void getGetDone(const epics::pvData::Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructure::shared_pointer const & getData, + epics::pvData::BitSet::shared_pointer const & getBitSet) { if (m_debug) std::cout << getRequesterName() << "." << "getGetDone(" << status.toString() << ")" << std::endl; { Lock lock(m_pointerMutex); + + m_channelPutGet = channelPutGet; + m_getData = getData; + m_getBitSet = getBitSet; + m_getGetStatus = status.isSuccess(); } @@ -780,13 +835,21 @@ class SyncChannelPutGetRequesterImpl : public ChannelPutGetRequester, public Syn } - virtual void getPutDone(const epics::pvData::Status& status) + virtual void getPutDone(const epics::pvData::Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructure::shared_pointer const & putData, + epics::pvData::BitSet::shared_pointer const & putBitSet) { if (m_debug) std::cout << getRequesterName() << "." << "getPutDone(" << status.toString() << ")" << std::endl; { Lock lock(m_pointerMutex); + + m_channelPutGet = channelPutGet; + m_putData = putData; + m_putBitSet = putBitSet; + m_getPutStatus = status.isSuccess(); } @@ -794,13 +857,21 @@ class SyncChannelPutGetRequesterImpl : public ChannelPutGetRequester, public Syn } - virtual void putGetDone(const epics::pvData::Status& status) + virtual void putGetDone(const epics::pvData::Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructure::shared_pointer const & getData, + epics::pvData::BitSet::shared_pointer const & getBitSet) { if (m_debug) std::cout << getRequesterName() << "." << "putGetDone(" << status.toString() << ")" << std::endl; { Lock lock(m_pointerMutex); + + m_channelPutGet = channelPutGet; + m_getData = getData; + m_getBitSet = getBitSet; + m_putGetStatus = status.isSuccess(); } @@ -853,7 +924,9 @@ class SyncChannelPutGetRequesterImpl : public ChannelPutGetRequester, public Syn Mutex m_pointerMutex; ChannelPutGet::shared_pointer m_channelPutGet; epics::pvData::PVStructure::shared_pointer m_putData; + epics::pvData::BitSet::shared_pointer m_putBitSet; epics::pvData::PVStructure::shared_pointer m_getData; + epics::pvData::BitSet::shared_pointer m_getBitSet; }; @@ -875,7 +948,9 @@ class SyncChannelRPCRequesterImpl : public ChannelRPCRequester, public SyncBaseR return false; } - m_channelRPC->request(pvArguments, lastRequest); + if (lastRequest) + m_channelRPC->lastRequest(); + m_channelRPC->request(pvArguments); return waitUntilRPC(timeOut); } @@ -934,6 +1009,7 @@ class SyncChannelRPCRequesterImpl : public ChannelRPCRequester, public SyncBaseR virtual void requestDone (const epics::pvData::Status &status, + ChannelRPC::shared_pointer const & channelRPC, epics::pvData::PVStructure::shared_pointer const &pvResponse) { @@ -941,14 +1017,10 @@ class SyncChannelRPCRequesterImpl : public ChannelRPCRequester, public SyncBaseR std::cout << getRequesterName() << "." << "requestDone(" << status.toString() << ")" << std::endl; - if (status.isSuccess()) { Lock lock(m_pointerMutex); + m_channelRPC = channelRPC; m_lastResponse = pvResponse; - } - - { - Lock lock(m_pointerMutex); m_done = status.isSuccess(); } @@ -1134,6 +1206,7 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB m_lengthArrayStatus(false) {} + // note you need to do a get first bool syncPut(bool lastRequest, size_t offset, size_t count, long timeOut) { @@ -1141,7 +1214,10 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB return false; } - m_channelArray->putArray(lastRequest, offset, count); + if (lastRequest) + m_channelArray->lastRequest(); + // TODO stride !!! + m_channelArray->putArray(getArray(), offset, count, 1); return waitUntilPutArrayDone(timeOut); } @@ -1153,7 +1229,10 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB return false; } - m_channelArray->getArray(lastRequest, offset, count); + if (lastRequest) + m_channelArray->lastRequest(); + // TODO stride !!! + m_channelArray->getArray(offset, count, 1); return waitUntilGetArrayDone(timeOut); } @@ -1165,7 +1244,9 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB return false; } - m_channelArray->setLength(lastRequest, length, capacity); + if (lastRequest) + m_channelArray->lastRequest(); + m_channelArray->setLength(length, capacity); return waitUntilSetLengthDone(timeOut); } @@ -1200,7 +1281,7 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB virtual void channelArrayConnect(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray, - epics::pvData::PVArray::shared_pointer const & pvArray) + epics::pvData::Array::const_shared_pointer const & /*array*/) { if (m_debug) std::cout << getRequesterName() << ".channelArrayConnect(" << status.toString() << ")" << std::endl; @@ -1209,7 +1290,6 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB { Lock lock(m_pointerMutex); m_channelArray = channelArray; - m_pvArray = pvArray; } setConnectedStatus(true); @@ -1223,38 +1303,69 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB } - virtual void getArrayDone(const epics::pvData::Status& status) + virtual void getArrayDone(const epics::pvData::Status& status, + ChannelArray::shared_pointer const & channelArray, + epics::pvData::PVArray::shared_pointer const & pvArray) { if (m_debug) std::cout << getRequesterName() << ".getArrayDone(" << status.toString() << ")" << std::endl; Lock lock(m_pointerMutex); + + m_channelArray = channelArray; + m_pvArray = pvArray; + m_getArrayStatus = status.isSuccess(); signalEvent(); } - virtual void putArrayDone(const epics::pvData::Status& status) + virtual void putArrayDone(const epics::pvData::Status& status, + ChannelArray::shared_pointer const & channelArray) { if (m_debug) std::cout << getRequesterName() << ".putArrayDone(" << status.toString() << ")" << std::endl; Lock lock(m_pointerMutex); + + m_channelArray = channelArray; + m_putArrayStatus = status.isSuccess(); signalEvent(); } - virtual void setLengthDone(const epics::pvData::Status& status) + virtual void setLengthDone(const epics::pvData::Status& status, + ChannelArray::shared_pointer const & channelArray) { if (m_debug) std::cout << getRequesterName() << ".setLengthDone(" << status.toString() << ")" << std::endl; Lock lock(m_pointerMutex); + + m_channelArray = channelArray; + m_lengthArrayStatus = status.isSuccess(); signalEvent(); } + virtual void getLengthDone(const epics::pvData::Status& status, + ChannelArray::shared_pointer const & channelArray, + size_t length, size_t capacity) + { + if (m_debug) + std::cout << getRequesterName() << ".getLengthDone(" << status.toString() << ")" << std::endl; + + Lock lock(m_pointerMutex); + + m_channelArray = channelArray; + // TODO !!! + //m_length = length; + //m_capacity = capacity; + + m_lengthArrayStatus = status.isSuccess(); + signalEvent(); + } private: From 0988f0c8fb3c1e642971a5c50403733f25007589 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Fri, 23 May 2014 13:36:21 +0200 Subject: [PATCH 13/32] EPICS_PVA_DEBUG from bool to int --- pvAccessApp/remote/abstractResponseHandler.cpp | 2 +- pvAccessApp/remote/remote.h | 4 ++-- pvAccessApp/remoteClient/clientContextImpl.cpp | 6 ++++++ pvAccessApp/server/serverContext.cpp | 5 +++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/pvAccessApp/remote/abstractResponseHandler.cpp b/pvAccessApp/remote/abstractResponseHandler.cpp index 2d36e1f..4c7c0ec 100644 --- a/pvAccessApp/remote/abstractResponseHandler.cpp +++ b/pvAccessApp/remote/abstractResponseHandler.cpp @@ -24,7 +24,7 @@ namespace epics { void AbstractResponseHandler::handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer const & /*transport*/, int8 version, int8 command, size_t payloadSize, ByteBuffer* payloadBuffer) { - if(_debug) { + if(_debugLevel >= 3) { // TODO make a constant of sth (0 - off, 1 - debug, 2 - more/trace, 3 - messages) char ipAddrStr[48]; ipAddrToDottedIP(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr)); diff --git a/pvAccessApp/remote/remote.h b/pvAccessApp/remote/remote.h index 7999293..5a53b3a 100644 --- a/pvAccessApp/remote/remote.h +++ b/pvAccessApp/remote/remote.h @@ -352,7 +352,7 @@ namespace epics { */ AbstractResponseHandler(Context* context, epics::pvData::String description) : _description(description), - _debug(context->getConfiguration()->getPropertyAsBoolean(PVACCESS_DEBUG, false)) { + _debugLevel(context->getConfiguration()->getPropertyAsInteger(PVACCESS_DEBUG, 0)) { } virtual ~AbstractResponseHandler() {} @@ -370,7 +370,7 @@ namespace epics { /** * Debug flag. */ - bool _debug; + epics::pvData::int32 _debugLevel; }; /** diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index cbc26da..fef1fbe 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -4037,6 +4037,12 @@ TODO private: void loadConfiguration() { + + // TODO for now just a simple switch + int32 debugLevel = m_configuration->getPropertyAsInteger(PVACCESS_DEBUG, 0); + if (debugLevel > 0) + SET_LOG_LEVEL(logLevelDebug); + m_addressList = m_configuration->getPropertyAsString("EPICS_PVA_ADDR_LIST", m_addressList); m_autoAddressList = m_configuration->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", m_autoAddressList); m_connectionTimeout = m_configuration->getPropertyAsFloat("EPICS_PVA_CONN_TMO", m_connectionTimeout); diff --git a/pvAccessApp/server/serverContext.cpp b/pvAccessApp/server/serverContext.cpp index c357d23..67995f0 100644 --- a/pvAccessApp/server/serverContext.cpp +++ b/pvAccessApp/server/serverContext.cpp @@ -98,6 +98,11 @@ void ServerContextImpl::loadConfiguration() { Configuration::shared_pointer config = getConfiguration(); + // TODO for now just a simple switch + int32 debugLevel = config->getPropertyAsInteger(PVACCESS_DEBUG, 0); + if (debugLevel > 0) + SET_LOG_LEVEL(logLevelDebug); + _beaconAddressList = config->getPropertyAsString("EPICS_PVA_ADDR_LIST", _beaconAddressList); _beaconAddressList = config->getPropertyAsString("EPICS_PVAS_BEACON_ADDR_LIST", _beaconAddressList); From 1f0e426413fa625434ee50b034d1edc7cf966c2d Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Sat, 24 May 2014 22:09:31 +0200 Subject: [PATCH 14/32] CreateRequestFactory.cpp removed --- pvAccessApp/factory/CreateRequestFactory.cpp | 302 ------------------- 1 file changed, 302 deletions(-) delete mode 100644 pvAccessApp/factory/CreateRequestFactory.cpp diff --git a/pvAccessApp/factory/CreateRequestFactory.cpp b/pvAccessApp/factory/CreateRequestFactory.cpp deleted file mode 100644 index 9b8e6d7..0000000 --- a/pvAccessApp/factory/CreateRequestFactory.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * pvAccessCPP is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ - -#include -#include - -#include -#include - -#define epicsExportSharedSymbols -#include - -using namespace epics::pvData; -using std::tr1::static_pointer_cast; - -namespace epics { -namespace pvAccess { - -static PVDataCreatePtr pvDataCreate = getPVDataCreate(); - -class CreateRequestImpl : public CreateRequest { -private: - - static void removeBlanks(String& str) - { - while(true) { - String::size_type pos = str.find_first_of(' '); - if(pos==String::npos) return; - str.erase(pos,1); - } - } - - static size_t findMatchingBrace(String& request, size_t index, int numOpen) { - size_t openBrace = request.find('{', index+1); - size_t closeBrace = request.find('}', index+1); - if(openBrace == String::npos && closeBrace == std::string::npos) return std::string::npos; - if (openBrace != String::npos && openBrace!=0) { - if(openBrace split(String const & commaSeparatedList) { - String::size_type numValues = 1; - String::size_type index=0; - while(true) { - String::size_type pos = commaSeparatedList.find(',',index); - if(pos==String::npos) break; - numValues++; - index = pos +1; - } - std::vector valueList(numValues,""); - index=0; - for(size_t i=0; i items = split(request); - size_t nitems = items.size(); - StringArray fieldNames; - PVFieldPtrArray pvFields; - fieldNames.reserve(nitems); - pvFields.reserve(nitems); - for(size_t j=0; j(getPVDataCreate()->createPVScalar(pvString)); - pvValue->put(value); - pvFields.push_back(pvValue); - } - PVStructurePtr pvOptions = getPVDataCreate()->createPVStructure(fieldNames,pvFields); - pvParent->appendPVField("_options",pvOptions); - return true; - } - - bool createFieldRequest( - PVStructurePtr const & pvParent, - String request) - { - static PVFieldPtrArray emptyFields; - static StringArray emptyFieldNames; - - removeBlanks(request); - if(request.length()<=0) return true; - size_t comma = request.find(','); - if(comma==0) { - return createFieldRequest(pvParent,request.substr(1)); - } - size_t openBrace = request.find('{'); - size_t openBracket = request.find('['); - PVStructurePtr pvStructure = pvDataCreate->createPVStructure(emptyFieldNames, emptyFields); - if(comma==String::npos && openBrace==std::string::npos && openBracket==std::string::npos) { - size_t period = request.find('.'); - if(period!=String::npos && period!=0) { - String fieldName = request.substr(0,period); - request = request.substr(period+1); - pvParent->appendPVField(fieldName, pvStructure); - return createFieldRequest(pvStructure,request); - } - pvParent->appendPVField(request, pvStructure); - return true; - } - size_t end = comma; - if(openBrace!=String::npos && (end>openBrace || end==std::string::npos)) end = openBrace; - if(openBracket!=String::npos && (end>openBracket || end==std::string::npos)) end = openBracket; - String nextFieldName = request.substr(0,end); - if(end==comma) { - size_t period = nextFieldName.find('.'); - if(period!=String::npos && period!=0) { - String fieldName = nextFieldName.substr(0,period); - PVStructurePtr xxx= pvDataCreate->createPVStructure(emptyFieldNames, emptyFields); - String rest = nextFieldName.substr(period+1); - createFieldRequest(xxx,rest); - pvParent->appendPVField(fieldName, xxx); - } else { - pvParent->appendPVField(nextFieldName, pvStructure); - } - request = request.substr(end+1); - return createFieldRequest(pvParent,request); - } - if(end==openBracket) { - size_t closeBracket = request.find(']'); - if(closeBracket==String::npos || closeBracket==0) { - message = request + " does not have matching ]"; - return false; - } - String options = request.substr(openBracket+1, closeBracket-openBracket-1); - size_t period = nextFieldName.find('.'); - if(period!=String::npos && period!=0) { - String fieldName = nextFieldName.substr(0,period); - PVStructurePtr xxx = pvDataCreate->createPVStructure(emptyFieldNames, emptyFields); - if(!createRequestOptions(xxx,options)) return false; - String rest = nextFieldName.substr(period+1); - createFieldRequest(xxx,rest); - pvParent->appendPVField(fieldName, xxx); - } else { - if(!createRequestOptions(pvStructure,options)) return false; - pvParent->appendPVField(nextFieldName, pvStructure); - } - request = request.substr(end+1); - return createFieldRequest(pvParent,request); - } - // end== openBrace - size_t closeBrace = findMatchingBrace(request,openBrace+1,1); - if(closeBrace==String::npos || closeBrace==0) { - message = request + " does not have matching }"; - return false; - } - String subFields = request.substr(openBrace+1, closeBrace-openBrace-1); - if(!createFieldRequest(pvStructure,subFields)) return false; - request = request.substr(closeBrace+1); - size_t period = nextFieldName.find('.'); - if(period==String::npos) { - pvParent->appendPVField(nextFieldName,pvStructure); - return createFieldRequest(pvParent,request); - } - PVStructure::shared_pointer yyy = pvParent; - while(period!=String::npos && period!=0) { - String fieldName = nextFieldName.substr(0,period); - PVStructurePtr xxx = pvDataCreate->createPVStructure(emptyFieldNames, emptyFields); - yyy->appendPVField(fieldName,xxx); - nextFieldName = nextFieldName.substr(period+1); - period = nextFieldName.find('.'); - if(period==String::npos || period==0) { - xxx->appendPVField(nextFieldName, pvStructure); - break; - } - yyy = xxx; - } - return createFieldRequest(pvParent,request); - } - -public: - - virtual PVStructure::shared_pointer createRequest( - String const & crequest) - { - String request = crequest; - PVFieldPtrArray pvFields; - StringArray fieldNames; - PVStructurePtr emptyPVStructure = pvDataCreate->createPVStructure(fieldNames,pvFields); - static PVStructure::shared_pointer nullStructure; - - if (!request.empty()) removeBlanks(request); - if (request.empty()) - { - return emptyPVStructure; - } - size_t offsetRecord = request.find("record["); - size_t offsetField = request.find("field("); - size_t offsetPutField = request.find("putField("); - size_t offsetGetField = request.find("getField("); - PVStructurePtr pvStructure = pvDataCreate->createPVStructure(emptyPVStructure); - if (offsetRecord != String::npos) { - size_t offsetBegin = request.find('[', offsetRecord); - size_t offsetEnd = request.find(']', offsetBegin); - if(offsetEnd == String::npos) { - message = request.substr(offsetRecord) - + " record[ does not have matching ]"; - return nullStructure; - } - PVStructurePtr pvStruct = pvDataCreate->createPVStructure(emptyPVStructure); - if(!createRequestOptions( - pvStruct,request.substr(offsetBegin+1, - offsetEnd-offsetBegin-1))) - { - return nullStructure; - } - pvStructure->appendPVField("record", pvStruct); - } - if (offsetField != String::npos) { - size_t offsetBegin = request.find('(', offsetField); - size_t offsetEnd = request.find(')', offsetBegin); - if(offsetEnd == String::npos) { - message = request.substr(offsetField) - + " field( does not have matching )"; - return nullStructure; - } - PVStructurePtr pvStruct = pvDataCreate->createPVStructure(emptyPVStructure); - if(!createFieldRequest( - pvStruct,request.substr(offsetBegin+1, - offsetEnd-offsetBegin-1))) - { - return nullStructure; - } - pvStructure->appendPVField("field", pvStruct); - } - if (offsetPutField != String::npos) { - size_t offsetBegin = request.find('(', offsetPutField); - size_t offsetEnd = request.find(')', offsetBegin); - if(offsetEnd == String::npos) { - message = request.substr(offsetField) - + " putField( does not have matching )"; - return nullStructure; - } - PVStructurePtr pvStruct = pvDataCreate->createPVStructure(emptyPVStructure); - if(!createFieldRequest( - pvStruct,request.substr(offsetBegin+1, - offsetEnd-offsetBegin-1))) - { - return nullStructure; - } - pvStructure->appendPVField("putField", pvStruct); - } - if (offsetGetField != String::npos) { - size_t offsetBegin = request.find('(', offsetGetField); - size_t offsetEnd = request.find(')', offsetBegin); - if(offsetEnd == String::npos) { - message = request.substr(offsetField) - + " getField( does not have matching )"; - return nullStructure; - } - PVStructurePtr pvStruct = pvDataCreate->createPVStructure(emptyPVStructure); - if(!createFieldRequest( - pvStruct,request.substr(offsetBegin+1, - offsetEnd-offsetBegin-1))) - { - return nullStructure; - } - pvStructure->appendPVField("getField", pvStruct); - } - if (pvStructure.get()->getStructure()->getNumberFields()==0) { - if(!createFieldRequest(pvStructure,request)) return nullStructure; - } - return pvStructure; - } - -}; - -CreateRequest::shared_pointer CreateRequest::create() -{ - CreateRequest::shared_pointer createRequest(new CreateRequestImpl()); - return createRequest; -} - -}} - From 1df336c6e216447360614ebdc164b4b832f1252f Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Sat, 24 May 2014 23:28:16 +0200 Subject: [PATCH 15/32] channelAccessIFTest.cpp: no crash --- testApp/remote/channelAccessIFTest.cpp | 108 +++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 8 deletions(-) diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index 492bbb9..bbc5f32 100755 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -672,6 +672,13 @@ void ChannelAccessIFTest::test_channelPutNoProcess() { return; } + // first do a get to get pvStrcuture + bool succStatus = channelPutReq->syncGet(getTimeoutSec()); + if (!succStatus) { + testFail("%s: sync get failed ", CURRENT_FUNCTION); + return; + } + std::tr1::shared_ptr value = channelPutReq->getPVStructure()->getDoubleField("value"); if (!value.get()) { testFail("%s: getting double value field failed ", CURRENT_FUNCTION); @@ -683,7 +690,7 @@ void ChannelAccessIFTest::test_channelPutNoProcess() { value->put(initVal); channelPutReq->getBitSet()->set(value->getFieldOffset()); - bool succStatus = channelPutReq->syncPut(false, getTimeoutSec()); + /*bool*/ succStatus = channelPutReq->syncPut(false, getTimeoutSec()); if (!succStatus) { testFail("%s: sync put failed ", CURRENT_FUNCTION); return; @@ -804,6 +811,13 @@ void ChannelAccessIFTest::test_channelPutIntProcessInternal(Channel::shared_poin return; } + // first do a get to get pvStructure + bool succStatus = channelPutReq->syncGet(getTimeoutSec()); + if (!succStatus) { + testFail("%s: sync get failed ", testMethodName.c_str()); + return; + } + std::tr1::shared_ptr value = channelPutReq->getPVStructure()->getIntField("value"); if (!value.get()) { testFail("%s: getting int value field failed ", testMethodName.c_str()); @@ -815,7 +829,7 @@ void ChannelAccessIFTest::test_channelPutIntProcessInternal(Channel::shared_poin value->put(initVal); channelPutReq->getBitSet()->set(value->getFieldOffset()); - bool succStatus = channelPutReq->syncPut(false, getTimeoutSec()); + /*bool*/ succStatus = channelPutReq->syncPut(false, getTimeoutSec()); if (!succStatus) { testFail("%s: sync put failed ", testMethodName.c_str()); return; @@ -1184,6 +1198,20 @@ void ChannelAccessIFTest::test_channelPutGetNoProcess_putGet() { return; } + // first get a pvStructure + bool succStatus = channelPutGetReq->syncGetPut(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetPut failed ", CURRENT_FUNCTION); + return; + } + + // first get a pvStructure + succStatus = channelPutGetReq->syncGetGet(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetGet failed ", CURRENT_FUNCTION); + return; + } + std::tr1::shared_ptr putValue = channelPutGetReq->getPVPutStructure()->getDoubleField("value"); if (!putValue.get()) { @@ -1200,7 +1228,7 @@ void ChannelAccessIFTest::test_channelPutGetNoProcess_putGet() { return; } - bool succStatus = channelPutGetReq->syncPutGet(false, getTimeoutSec()); + /*bool*/ succStatus = channelPutGetReq->syncPutGet(false, getTimeoutSec()); if (!succStatus) { testFail("%s: syncPutGet failed ", CURRENT_FUNCTION); return; @@ -1249,6 +1277,20 @@ void ChannelAccessIFTest::test_channelPutGetNoProcess_getPut() { return; } + // first get a pvStructure + bool succStatus = channelPutGetReq->syncGetPut(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetPut failed ", CURRENT_FUNCTION); + return; + } + + // first get a pvStructure + succStatus = channelPutGetReq->syncGetGet(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetGet failed ", CURRENT_FUNCTION); + return; + } + std::tr1::shared_ptr putValue = channelPutGetReq->getPVPutStructure()->getDoubleField("value"); if (!putValue.get()) { @@ -1267,7 +1309,7 @@ void ChannelAccessIFTest::test_channelPutGetNoProcess_getPut() { testDiag("%s: first put the initial pvPutStructure into the record", CURRENT_FUNCTION); - bool succStatus = channelPutGetReq->syncPutGet(false, getTimeoutSec()); + /*bool*/ succStatus = channelPutGetReq->syncPutGet(false, getTimeoutSec()); if (!succStatus) { testFail("%s: syncPutGet failed ", CURRENT_FUNCTION); return; @@ -1312,6 +1354,20 @@ void ChannelAccessIFTest::test_channelPutGetNoProcess_getGet() { return; } + // first get a pvStructure + bool succStatus = channelPutGetReq->syncGetPut(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetPut failed ", CURRENT_FUNCTION); + return; + } + + // first get a pvStructure + succStatus = channelPutGetReq->syncGetGet(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetGet failed ", CURRENT_FUNCTION); + return; + } + std::tr1::shared_ptr putValue = channelPutGetReq->getPVPutStructure()->getDoubleField("value"); if (!putValue.get()) { @@ -1330,7 +1386,7 @@ void ChannelAccessIFTest::test_channelPutGetNoProcess_getGet() { testDiag("%s: first put the initial pvPutStructure into the record", CURRENT_FUNCTION); - bool succStatus = channelPutGetReq->syncPutGet(false, getTimeoutSec()); + /*bool*/ succStatus = channelPutGetReq->syncPutGet(false, getTimeoutSec()); if (!succStatus) { testFail("%s: syncPutGet failed ", CURRENT_FUNCTION); return; @@ -1374,8 +1430,23 @@ void ChannelAccessIFTest::test_channelPutGetNoProcess_destroy() { testFail("%s: creating a channel putget failed ", CURRENT_FUNCTION); return; } + + // first get a pvStructure + bool succStatus = channelPutGetReq->syncGetPut(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetPut failed ", CURRENT_FUNCTION); + return; + } + + // first get a pvStructure + succStatus = channelPutGetReq->syncGetGet(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetGet failed ", CURRENT_FUNCTION); + return; + } + - bool succStatus = channelPutGetReq->syncPutGet(true, getTimeoutSec()); + /*bool*/ succStatus = channelPutGetReq->syncPutGet(true, getTimeoutSec()); if (!succStatus) { testFail("%s: syncPutGet failed ", CURRENT_FUNCTION); return; @@ -1419,6 +1490,20 @@ void ChannelAccessIFTest::test_channelPutGetIntProcess() { return; } + // first get a pvStructure + bool succStatus = channelPutGetReq->syncGetPut(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetPut failed ", CURRENT_FUNCTION); + return; + } + + // first get a pvStructure + succStatus = channelPutGetReq->syncGetGet(getTimeoutSec()); + if (!succStatus) { + testFail("%s: syncGetGet failed ", CURRENT_FUNCTION); + return; + } + std::tr1::shared_ptr putValue = channelPutGetReq->getPVPutStructure()->getIntField("value"); if (!putValue.get()) { @@ -1442,7 +1527,7 @@ void ChannelAccessIFTest::test_channelPutGetIntProcess() { TimeStamp timeStamp; - bool succStatus = channelPutGetReq->syncGetGet(getTimeoutSec()); + /*bool*/ succStatus = channelPutGetReq->syncGetGet(getTimeoutSec()); if (!succStatus) { testFail("%s: syncGetGet failed ", CURRENT_FUNCTION); return; @@ -1735,9 +1820,16 @@ void ChannelAccessIFTest::test_channelArray() { return; } + // first get to get pvArray + bool succStatus = arrayReq->syncGet(false, 0, 0, getTimeoutSec()); + if (!succStatus) { + testFail("%s: an array syncGet failed (3) ", CURRENT_FUNCTION); + return; + } + PVDoubleArrayPtr array = static_pointer_cast(arrayReq->getArray()); - bool succStatus = arrayReq->syncGet(false, 0, 2, getTimeoutSec()); + /*bool*/ succStatus = arrayReq->syncGet(false, 0, 2, getTimeoutSec()); if (!succStatus) { testFail("%s: an array syncGet failed (1) ", CURRENT_FUNCTION); return; From 1442c6cd41c4a042ebd0419de42c2da668cc140f Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Sun, 1 Jun 2014 23:54:40 +0200 Subject: [PATCH 16/32] pv API tests pass --- pvAccessApp/remote/codec.cpp | 15 +++++++++++-- pvAccessApp/server/responseHandlers.cpp | 6 ++--- pvAccessApp/server/responseHandlers.h | 6 +++++ testApp/remote/channelAccessIFTest.cpp | 2 +- testApp/remote/testServer.cpp | 30 ++++++++++++++++++++----- 5 files changed, 48 insertions(+), 11 deletions(-) diff --git a/pvAccessApp/remote/codec.cpp b/pvAccessApp/remote/codec.cpp index f523737..72d6304 100644 --- a/pvAccessApp/remote/codec.cpp +++ b/pvAccessApp/remote/codec.cpp @@ -153,7 +153,13 @@ namespace epics { if (!readToBuffer(PVA_MESSAGE_HEADER_SIZE, false)) { return; } - + + /* + hexDump("Header", (const int8*)_socketBuffer->getArray(), + _socketBuffer->getPosition(), PVA_MESSAGE_HEADER_SIZE); + + */ + // read header fields processHeader(); bool isControl = ((_flags & 0x01) == 0x01); @@ -166,8 +172,13 @@ namespace epics { bool notFirstSegment = (_flags & 0x20) != 0; if (notFirstSegment) { + // not-first segmented message with zero payload is "kind of" valid + // TODO this should check if previous message was first- or middle-segmented message + if (_payloadSize == 0) + continue; + LOG(logLevelWarn, - "Not-a-frst segmented message received in normal mode" + "Not-a-first segmented message received in normal mode" " from the client at %s:%d: %s, disconnecting...", __FILE__, __LINE__, inetAddressToString(*getLastReadBufferSocketAddress()).c_str()); invalidDataStreamHandler(); diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index fda46aa..d1b94da 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -1610,7 +1610,7 @@ void ServerArrayHandler::handleResponse(osiSockAddr* responseFrom, ServerChannelArrayRequesterImpl::ServerChannelArrayRequesterImpl( ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel, const pvAccessID ioid, Transport::shared_pointer const & transport): - BaseChannelRequester(context, channel, ioid, transport), _channelArray(), _pvArray() + BaseChannelRequester(context, channel, ioid, transport) { } @@ -1643,7 +1643,7 @@ void ServerChannelArrayRequesterImpl::channelArrayConnect(const Status& status, if (status.isSuccess()) { - _pvArray = std::tr1::static_pointer_cast(reuseOrCreatePVField(_array, _pvArray)); + _pvPutArray = std::tr1::static_pointer_cast(reuseOrCreatePVField(_array, _pvPutArray)); } TransportSender::shared_pointer thisSender = shared_from_this(); @@ -1738,7 +1738,7 @@ ChannelArray::shared_pointer ServerChannelArrayRequesterImpl::getChannelArray() PVArray::shared_pointer ServerChannelArrayRequesterImpl::getPVArray() { //Lock guard(_mutex); - return _pvArray; + return _pvPutArray; } void ServerChannelArrayRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) diff --git a/pvAccessApp/server/responseHandlers.h b/pvAccessApp/server/responseHandlers.h index 66d7e3c..01d23aa 100644 --- a/pvAccessApp/server/responseHandlers.h +++ b/pvAccessApp/server/responseHandlers.h @@ -605,7 +605,13 @@ namespace pvAccess { private: ChannelArray::shared_pointer _channelArray; epics::pvData::Array::const_shared_pointer _array; + + // reference store epics::pvData::PVArray::shared_pointer _pvArray; + + // data container + epics::pvData::PVArray::shared_pointer _pvPutArray; + std::size_t _length; std::size_t _capacity; epics::pvData::Status _status; diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index bbc5f32..b5999b0 100755 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -1823,7 +1823,7 @@ void ChannelAccessIFTest::test_channelArray() { // first get to get pvArray bool succStatus = arrayReq->syncGet(false, 0, 0, getTimeoutSec()); if (!succStatus) { - testFail("%s: an array syncGet failed (3) ", CURRENT_FUNCTION); + testFail("%s: an array syncGet failed (0) ", CURRENT_FUNCTION); return; } diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index b0b8fed..bbc7db2 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -19,6 +19,7 @@ #include #include +#include // TODO temp #include "testADCSim.cpp" @@ -921,7 +922,7 @@ static ChannelProcess::shared_pointer getChannelProcess( Channel::shared_pointer const & channel, PVStructure::shared_pointer const & pvRequest) { - PVScalar::shared_pointer pvScalar = pvRequest->getSubField("record._options.process"); + PVScalar::shared_pointer pvScalar = pvRequest->getSubField("record.process"); if (pvScalar && pvScalar->getAs()) { std::tr1::shared_ptr cpr(new ChannelProcessRequesterImpl()); @@ -1089,6 +1090,7 @@ protected: m_channelProcess(getChannelProcess(channel, pvRequest)) { PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(mockChannelPut); + m_bitSet->set(0); // TODO } public: @@ -1112,7 +1114,14 @@ public: virtual void put(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & putBitSet) { - // TODO data - do an actual put !!! + // TODO use putBitSet and do not copy all + // (note that server code has already not deserialized fields whose bits are not set) + if (putBitSet->cardinality()) + { + lock(); + getConvert()->copy(pvPutStructure, m_pvStructure); + unlock(); + } if (m_channelProcess) m_channelProcess->process(); @@ -1127,6 +1136,7 @@ public: virtual void get() { + // NOTE: alwasy returns entire m_bitSet m_channelPutRequester->getDone(Status::Ok, shared_from_this(), m_pvStructure, m_bitSet); if (m_lastRequest.get()) @@ -1226,7 +1236,14 @@ public: virtual void putGet(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & putBitSet) { - // TODO !!! copy what was put... + // TODO use putBitSet and do not copy all + // (note that server code has already not deserialized fields whose bits are not set) + if (putBitSet->cardinality()) + { + lock(); + getConvert()->copy(pvPutStructure, m_putStructure); + unlock(); + } if (m_channelProcess) m_channelProcess->process(); @@ -1902,9 +1919,12 @@ public: { if (capacity > 0) { m_pvStructureArray->setCapacity(capacity); + m_pvStructureArray->setLength(length > capacity ? capacity : length); + } + else + { + m_pvStructureArray->setLength(length); } - - m_pvStructureArray->setLength(length); m_channelArrayRequester->setLengthDone(Status::Ok, shared_from_this()); From 60b3e0e8e731cf215b57cff5973a7a9a41ff3d96 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 2 Jun 2014 09:24:53 +0200 Subject: [PATCH 17/32] eget: -a=value fix --- testApp/remote/eget.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/testApp/remote/eget.cpp b/testApp/remote/eget.cpp index c528f20..7afc8d6 100644 --- a/testApp/remote/eget.cpp +++ b/testApp/remote/eget.cpp @@ -1464,9 +1464,18 @@ int main (int argc, char *argv[]) { string param = optarg; size_t eqPos = param.find('='); + if (eqPos==0) + { + // no name + + fprintf(stderr, "Parameter not specified in '-a name=value' form. ('eget -h' for help.)\n"); + return 1; + } if (eqPos==string::npos) { - //fprintf(stderr, "Parameter not specified in name=value form. ('eget -h' for help.)\n"); + // no value + + //fprintf(stderr, "Parameter not specified in '-a name=value' form. ('eget -h' for help.)\n"); //return 1; parameters.push_back(pair(param, "")); } From 892961f85fc0e2cc9f11e263fdea68b222e2d990 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 2 Jun 2014 21:17:56 +0200 Subject: [PATCH 18/32] catcing all std exceptions in sendThread (and readThread) --- pvAccessApp/remote/codec.cpp | 19 +++++++++++++++++-- testApp/remote/testCodec.cpp | 8 +++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/pvAccessApp/remote/codec.cpp b/pvAccessApp/remote/codec.cpp index 72d6304..a96bebe 100644 --- a/pvAccessApp/remote/codec.cpp +++ b/pvAccessApp/remote/codec.cpp @@ -1023,10 +1023,14 @@ namespace epics { { try { bac->processRead(); - } catch (io_exception &e) { + } catch (std::exception &e) { LOG(logLevelWarn, "an exception caught while in receiveThread at %s:%d: %s", __FILE__, __LINE__, e.what()); + } catch (...) { + LOG(logLevelWarn, + "unknown exception caught while in sendThread at %s:%d", + __FILE__, __LINE__); } } @@ -1046,10 +1050,21 @@ namespace epics { { try { bac->processWrite(); - } catch (io_exception &e) { + } catch (connection_closed_exception &cce) { + // noop + /* + LOG(logLevelDebug, + "connection closed by remote host while in sendThread at %s:%d: %s", + __FILE__, __LINE__, e.what()); + */ + } catch (std::exception &e) { LOG(logLevelWarn, "an exception caught while in sendThread at %s:%d: %s", __FILE__, __LINE__, e.what()); + } catch (...) { + LOG(logLevelWarn, + "unknown exception caught while in sendThread at %s:%d", + __FILE__, __LINE__); } } diff --git a/testApp/remote/testCodec.cpp b/testApp/remote/testCodec.cpp index 8adb5c3..52b0d49 100644 --- a/testApp/remote/testCodec.cpp +++ b/testApp/remote/testCodec.cpp @@ -589,13 +589,15 @@ namespace epics { codec._readBuffer->put(PVA_VERSION); codec._readBuffer->put(invalidFlagsValues[i]); codec._readBuffer->put((int8_t)0x23); - codec._readBuffer->putInt(0); + //codec._readBuffer->putInt(0); + codec._readBuffer->putInt(i); // to check zero-payload codec._readBuffer->flip(); codec.processRead(); - testOk(codec._invalidDataStreamCount == 1, - "%s: codec._invalidDataStreamCount == 1", + testOk(codec._invalidDataStreamCount == (i != 0 ? 1 : 0), + //testOk(codec._invalidDataStreamCount == 1, + "%s: codec._invalidDataStreamCount == 1", CURRENT_FUNCTION); testOk(codec._closedCount == 0, "%s: codec._closedCount == 0", CURRENT_FUNCTION); From 0419fc6a3868e6797a604cd69cc9e3665ec57f79 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 2 Jun 2014 21:40:02 +0200 Subject: [PATCH 19/32] testChannelConnect: made a cmd-line tool out of it --- testApp/remote/testChannelConnect.cpp | 96 ++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/testApp/remote/testChannelConnect.cpp b/testApp/remote/testChannelConnect.cpp index cbb10de..068d35c 100644 --- a/testApp/remote/testChannelConnect.cpp +++ b/testApp/remote/testChannelConnect.cpp @@ -5,6 +5,10 @@ #include #include +#include +#include +#include +#include #include #include #include @@ -15,13 +19,15 @@ using namespace epics::pvData; using namespace epics::pvAccess; using namespace std; -#define N_CHANNELS 1000 +#define N_CHANNELS_DEFAULT 1000 +#define N_RUNS_DEFAULT 1 class ChannelRequesterImpl : public ChannelRequester { public: - ChannelRequesterImpl(Event& event) : count(0), g_event(event) {} + ChannelRequesterImpl(size_t channels, Event& event) : total(channels), count(0), g_event(event) {} private: + size_t total; int count; Event& g_event; @@ -50,7 +56,7 @@ private: if (connectionState == Channel::CONNECTED) { cout << c->getChannelName() << " CONNECTED: " << (count+1) << endl; - if (++count == N_CHANNELS) + if (static_cast(++count) == total) g_event.signal(); } else if (connectionState == Channel::DISCONNECTED) @@ -64,29 +70,83 @@ private: } }; - - -int main() +void usage (void) { + fprintf (stderr, "\nUsage: testChannelConnect [options]\n\n" + " -h: Help: Print this message\n" + "options:\n" + " -i : number of iterations per each run (< 0 means forever), default is '%d'\n" + " -c : number of channels, default is '%d'\n\n" + , N_RUNS_DEFAULT, N_CHANNELS_DEFAULT); +} + + +int main (int argc, char *argv[]) +{ + size_t nChannels = N_CHANNELS_DEFAULT; + int runs = N_RUNS_DEFAULT; + + int opt; // getopt() current option + setvbuf(stdout,NULL,_IOLBF,BUFSIZ); // Set stdout to line buffering + + while ((opt = getopt(argc, argv, ":hr:w:i:c:s:l:bf:v")) != -1) { + switch (opt) { + case 'h': // Print usage + usage(); + return 0; + case 'i': // iterations + runs = atoi(optarg); + break; + case 'c': // channels + { + int tmp = atoi(optarg); + if (tmp < 0) tmp = 1; + // note: possible overflow (size_t is not always unsigned int) + nChannels = static_cast(tmp); + break; + } + case '?': + fprintf(stderr, + "Unrecognized option: '-%c'. ('testChannelConnect -h' for help.)\n", + optopt); + return 1; + case ':': + fprintf(stderr, + "Option '-%c' requires an argument. ('testChannelConnect -h' for help.)\n", + optopt); + return 1; + default : + usage(); + return 1; + } + } + { Event g_event; ClientFactory::start(); ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); - ChannelRequester::shared_pointer channelRequester(new ChannelRequesterImpl(g_event)); - Channel::shared_pointer channels[N_CHANNELS]; - char buf[16]; - for (int i = 0; i < N_CHANNELS; i++) + int run = 0; + + while (runs < 0 || run++ < runs) { - sprintf(buf, "test%d", (i+1)); - channels[i] = provider->createChannel(buf, channelRequester); - } - - g_event.wait(); - - cout << "connected to all" << endl; - + vector channels(nChannels); + + ChannelRequester::shared_pointer channelRequester(new ChannelRequesterImpl(nChannels, g_event)); + + char buf[16]; + for (size_t i = 0; i < nChannels; i++) + { + sprintf(buf, "test%zu", (i+1)); + channels.push_back(provider->createChannel(buf, channelRequester)); + } + + g_event.wait(); + + cout << "connected to all" << endl; + } + ClientFactory::stop(); } From 90ca073f45d1793747c9bba8e50c2bcf9f3f9862 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Tue, 3 Jun 2014 14:17:09 +0200 Subject: [PATCH 20/32] ChannelArray.getLength() test added --- testApp/remote/channelAccessIFTest.cpp | 19 ++++++++++++++-- testApp/remote/syncTestRequesters.h | 30 +++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index b5999b0..cdda643 100755 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -43,9 +43,9 @@ std::string ChannelAccessIFTest::TEST_ARRAY_CHANNEL_NAME = "testArray1"; int ChannelAccessIFTest::runAllTest() { #ifdef ENABLE_STRESS_TESTS - testPlan(157); + testPlan(159); #else - testPlan(152); + testPlan(154); #endif test_implementation(); @@ -1973,6 +1973,21 @@ void ChannelAccessIFTest::test_channelArray() { } */ + // test setLength with capacity 0 (no change) and getLength + size_t newLen = bigCapacity/2; + succStatus = arrayReq->syncSetLength(false, newLen, bigCapacity, getTimeoutSec()); + if (!succStatus) { + testFail("%s: an array setLength failed (4) ", CURRENT_FUNCTION); + return; + } + succStatus = arrayReq->syncGetLength(false, getTimeoutSec()); + if (!succStatus) { + testFail("%s: an array getLength failed", CURRENT_FUNCTION); + return; + } + testOk(arrayReq->getLength() == newLen, "%s: retrieved length should be %zu", CURRENT_FUNCTION, newLen); + testOk(arrayReq->getCapacity() == bigCapacity, "%s: retrieved capacity should be %zu", CURRENT_FUNCTION, bigCapacity); + channel->destroy(); } diff --git a/testApp/remote/syncTestRequesters.h b/testApp/remote/syncTestRequesters.h index 0837d8b..6b452ad 100755 --- a/testApp/remote/syncTestRequesters.h +++ b/testApp/remote/syncTestRequesters.h @@ -1250,6 +1250,19 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB return waitUntilSetLengthDone(timeOut); } + bool syncGetLength(bool lastRequest, long timeOut) + { + + if (!getConnectedStatus()) { + return false; + } + + if (lastRequest) + m_channelArray->lastRequest(); + m_channelArray->getLength(); + return waitUntilSetLengthDone(timeOut); + } + ChannelArray::shared_pointer getChannelArray() { @@ -1359,13 +1372,22 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB Lock lock(m_pointerMutex); m_channelArray = channelArray; - // TODO !!! - //m_length = length; - //m_capacity = capacity; + m_length = length; + m_capacity = capacity; m_lengthArrayStatus = status.isSuccess(); signalEvent(); } + + size_t getLength() + { + return m_length; + } + + size_t getCapacity() + { + return m_capacity; + } private: @@ -1429,6 +1451,8 @@ class SyncChannelArrayRequesterImpl : public ChannelArrayRequester, public SyncB Mutex m_pointerMutex; ChannelArray::shared_pointer m_channelArray; epics::pvData::PVArray::shared_pointer m_pvArray; + size_t m_length; + size_t m_capacity; }; #endif From 030951c7f11c67db5f558bb720cc2b53755488d4 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Wed, 4 Jun 2014 08:53:59 +0200 Subject: [PATCH 21/32] testServer: erorr status returned if stride!=1 --- testApp/remote/testServer.cpp | 129 +++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 57 deletions(-) diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index bbc7db2..e4970ac 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -1823,39 +1823,47 @@ public: virtual void putArray(PVArray::shared_pointer const & pvArray, size_t offset, size_t count, size_t stride) { - // TODO stride support !!! - - size_t o = offset; - if (count == 0) count = pvArray->getLength(); - size_t c = count; - - Field::const_shared_pointer field = pvArray->getField(); - Type type = field->getType(); - if (type == scalarArray) + // TODO stride support + if (stride == 1) { - switch (std::tr1::static_pointer_cast(field)->getElementType()) + + size_t o = offset; + if (count == 0) count = pvArray->getLength(); + size_t c = count; + + Field::const_shared_pointer field = pvArray->getField(); + Type type = field->getType(); + if (type == scalarArray) { - case pvBoolean: put(pvArray, m_pvStructureArray, o, c); break; - case pvByte: put(pvArray, m_pvStructureArray, o, c); break; - case pvShort: put(pvArray, m_pvStructureArray, o, c); break; - case pvInt: put(pvArray, m_pvStructureArray, o, c); break; - case pvLong: put(pvArray, m_pvStructureArray, o, c); break; - case pvUByte: put(pvArray, m_pvStructureArray, o, c); break; - case pvUShort: put(pvArray, m_pvStructureArray, o, c); break; - case pvUInt: put(pvArray, m_pvStructureArray, o, c); break; - case pvULong: put(pvArray, m_pvStructureArray, o, c); break; - case pvFloat: put(pvArray, m_pvStructureArray, o, c); break; - case pvDouble: put(pvArray, m_pvStructureArray, o, c); break; - case pvString: put(pvArray, m_pvStructureArray, o, c); break; + switch (std::tr1::static_pointer_cast(field)->getElementType()) + { + case pvBoolean: put(pvArray, m_pvStructureArray, o, c); break; + case pvByte: put(pvArray, m_pvStructureArray, o, c); break; + case pvShort: put(pvArray, m_pvStructureArray, o, c); break; + case pvInt: put(pvArray, m_pvStructureArray, o, c); break; + case pvLong: put(pvArray, m_pvStructureArray, o, c); break; + case pvUByte: put(pvArray, m_pvStructureArray, o, c); break; + case pvUShort: put(pvArray, m_pvStructureArray, o, c); break; + case pvUInt: put(pvArray, m_pvStructureArray, o, c); break; + case pvULong: put(pvArray, m_pvStructureArray, o, c); break; + case pvFloat: put(pvArray, m_pvStructureArray, o, c); break; + case pvDouble: put(pvArray, m_pvStructureArray, o, c); break; + case pvString: put(pvArray, m_pvStructureArray, o, c); break; + } } + else if (type == structureArray) + put(pvArray, m_pvStructureArray, o, c); + else if (type == unionArray) + put(pvArray, m_pvStructureArray, o, c); + + m_channelArrayRequester->putArrayDone(Status::Ok, shared_from_this()); } - else if (type == structureArray) - put(pvArray, m_pvStructureArray, o, c); - else if (type == unionArray) - put(pvArray, m_pvStructureArray, o, c); - - m_channelArrayRequester->putArrayDone(Status::Ok, shared_from_this()); - + else + { + Status notSupported(Status::STATUSTYPE_ERROR, "stride != 1 is not supported"); + m_channelArrayRequester->putArrayDone(notSupported, shared_from_this()); + } + if (m_lastRequest.get()) destroy(); } @@ -1878,38 +1886,45 @@ public: virtual void getArray(size_t offset, size_t count, size_t stride) { - // TODO stride support !!! - - size_t o = offset; - if (count == 0) count = m_pvStructureArray->getLength(); - size_t c = count; - - Field::const_shared_pointer field = m_pvArray->getField(); - Type type = field->getType(); - if (type == scalarArray) + // TODO stride support + if (stride == 1) { - switch (std::tr1::static_pointer_cast(field)->getElementType()) + size_t o = offset; + if (count == 0) count = m_pvStructureArray->getLength(); + size_t c = count; + + Field::const_shared_pointer field = m_pvArray->getField(); + Type type = field->getType(); + if (type == scalarArray) { - case pvBoolean: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvByte: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvShort: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvInt: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvLong: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvUByte: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvUShort: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvUInt: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvULong: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvFloat: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvDouble: get(m_pvStructureArray, m_pvArray, o, c); break; - case pvString: get(m_pvStructureArray, m_pvArray, o, c); break; + switch (std::tr1::static_pointer_cast(field)->getElementType()) + { + case pvBoolean: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvByte: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvShort: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvInt: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvLong: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvUByte: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvUShort: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvUInt: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvULong: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvFloat: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvDouble: get(m_pvStructureArray, m_pvArray, o, c); break; + case pvString: get(m_pvStructureArray, m_pvArray, o, c); break; + } } + else if (type == structureArray) + get(m_pvStructureArray, m_pvArray, o, c); + else if (type == unionArray) + get(m_pvStructureArray, m_pvArray, o, c); + + m_channelArrayRequester->getArrayDone(Status::Ok, shared_from_this(), m_pvArray); + } + else + { + Status notSupported(Status::STATUSTYPE_ERROR, "stride != 1 is not supported"); + m_channelArrayRequester->putArrayDone(notSupported, shared_from_this()); } - else if (type == structureArray) - get(m_pvStructureArray, m_pvArray, o, c); - else if (type == unionArray) - get(m_pvStructureArray, m_pvArray, o, c); - - m_channelArrayRequester->getArrayDone(Status::Ok, shared_from_this(), m_pvArray); if (m_lastRequest.get()) destroy(); From 658d73d868f2e7f9db7902f5efadcd761b5bf85a Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Wed, 4 Jun 2014 09:18:48 +0200 Subject: [PATCH 22/32] rpcServiceExample.cpp: more robust, up-to-date code --- testApp/remote/rpcServiceExample.cpp | 51 +++++++++++++++++----------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/testApp/remote/rpcServiceExample.cpp b/testApp/remote/rpcServiceExample.cpp index cab6dbe..e92bc12 100644 --- a/testApp/remote/rpcServiceExample.cpp +++ b/testApp/remote/rpcServiceExample.cpp @@ -10,33 +10,46 @@ using namespace epics::pvData; using namespace epics::pvAccess; - - -static StructureConstPtr createResultField() -{ - FieldCreatePtr fieldCreate = getFieldCreate(); - - StringArray fieldNames; - fieldNames.push_back("c"); - FieldConstPtrArray fields; - fields.push_back(fieldCreate->createScalar(pvDouble)); - return fieldCreate->createStructure(fieldNames, fields); -} - -static StructureConstPtr resultStructure = createResultField(); +static Structure::const_shared_pointer resultStructure = + getFieldCreate()->createFieldBuilder()-> + add("c", pvDouble)-> + createStructure(); class SumServiceImpl : public RPCService { - PVStructure::shared_pointer request(PVStructure::shared_pointer const & args) + PVStructure::shared_pointer request(PVStructure::shared_pointer const & pvArguments) throw (RPCRequestException) { - // TODO error handling - double a = atof(args->getStringField("a")->get().c_str()); - double b = atof(args->getStringField("b")->get().c_str()); + // NTURI support + PVStructure::shared_pointer args( + (pvArguments->getStructure()->getID() == "uri:ev4:nt/2012/pwd:NTURI") ? + pvArguments->getStructureField("query") : + pvArguments + ); + // get fields and check their existence + PVScalar::shared_pointer af = args->getSubField("a"); + PVScalar::shared_pointer bf = args->getSubField("b"); + if (!af || !bf) + throw RPCRequestException(Status::STATUSTYPE_ERROR, "scalar 'a' and 'b' fields are required"); + + // get the numbers (and convert if neccessary) + double a, b; + try + { + a = af->getAs(); + b = bf->getAs(); + } + catch (std::exception &e) + { + throw RPCRequestException(Status::STATUSTYPE_ERROR, + std::string("failed to convert arguments to double: ") + e.what()); + } + + // create return structure and set data PVStructure::shared_pointer result = getPVDataCreate()->createPVStructure(resultStructure); - result->getDoubleField("c")->put(a+b); + result->getSubField("c")->put(a+b); return result; } }; From ccbfdb519b1df9517a55e5f37d5e9c802208121b Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Wed, 4 Jun 2014 10:22:04 +0200 Subject: [PATCH 23/32] nicer logs, socket shutdown --- TODO | 4 - pvAccessApp/remote/blockingTCPAcceptor.cpp | 12 +-- pvAccessApp/remote/blockingTCPConnector.cpp | 18 ++-- pvAccessApp/remote/blockingUDPTransport.cpp | 107 +++++++++----------- pvAccessApp/remote/codec.cpp | 83 +++++++++------ pvAccessApp/remote/codec.h | 2 + runTestServer | 2 +- 7 files changed, 118 insertions(+), 110 deletions(-) diff --git a/TODO b/TODO index c0e6c4d..cc19617 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,3 @@ -redefine size encoding to be able to carry negative values (to handle negative offsets), i.e. -128 means take larger integer size (same pattern for 32-bit integer). This also bings symmetric integer range (-value ... value). - opt) connection validation message sends max paylaod size readSize checks if size is in limits of size_t? @@ -19,5 +17,3 @@ readSize checks if size is in limits of size_t? void transportUnresponsive() { not implemented (also in Java) -socket termination - usage of epicsSocketSystemCallInterruptMechanismQuery() API - diff --git a/pvAccessApp/remote/blockingTCPAcceptor.cpp b/pvAccessApp/remote/blockingTCPAcceptor.cpp index bd99b9a..f778f6e 100644 --- a/pvAccessApp/remote/blockingTCPAcceptor.cpp +++ b/pvAccessApp/remote/blockingTCPAcceptor.cpp @@ -73,7 +73,7 @@ namespace pvAccess { int retval = ::bind(_serverSocketChannel, &_bindAddress.sa, sizeof(sockaddr)); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "Socket bind error: %s", strBuffer); + LOG(logLevelDebug, "Socket bind error: %s.", strBuffer); if(_bindAddress.ia.sin_port!=0) { // failed to bind to specified bind address, // try to get port dynamically, but only once @@ -163,21 +163,21 @@ namespace pvAccess { if(newClient!=INVALID_SOCKET) { // accept succeeded ipAddrToDottedIP(&address.ia, ipAddrStr, sizeof(ipAddrStr)); - LOG(logLevelDebug, "Accepted connection from PVA client: %s", ipAddrStr); + LOG(logLevelDebug, "Accepted connection from PVA client: %s.", ipAddrStr); // enable TCP_NODELAY (disable Nagle's algorithm) int optval = 1; // true int retval = ::setsockopt(newClient, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(int)); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "Error setting TCP_NODELAY: %s", strBuffer); + LOG(logLevelDebug, "Error setting TCP_NODELAY: %s.", strBuffer); } // enable TCP_KEEPALIVE retval = ::setsockopt(newClient, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(int)); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "Error setting SO_KEEPALIVE: %s", strBuffer); + LOG(logLevelDebug, "Error setting SO_KEEPALIVE: %s.", strBuffer); } // TODO tune buffer sizes?! @@ -188,7 +188,7 @@ namespace pvAccess { retval = getsockopt(newClient, SOL_SOCKET, SO_SNDBUF, (char *)&_socketSendBufferSize, &intLen); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "Error getting SO_SNDBUF: %s", strBuffer); + LOG(logLevelDebug, "Error getting SO_SNDBUF: %s.", strBuffer); } /** @@ -213,7 +213,7 @@ namespace pvAccess { return; } - LOG(logLevelDebug, "Serving to PVA client: %s", ipAddrStr); + LOG(logLevelDebug, "Serving to PVA client: %s.", ipAddrStr); }// accept succeeded else diff --git a/pvAccessApp/remote/blockingTCPConnector.cpp b/pvAccessApp/remote/blockingTCPConnector.cpp index 2e12404..7552035 100644 --- a/pvAccessApp/remote/blockingTCPConnector.cpp +++ b/pvAccessApp/remote/blockingTCPConnector.cpp @@ -50,7 +50,7 @@ namespace epics { if (socket == INVALID_SOCKET) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); - LOG(logLevelWarn, "Socket create error: %s", strBuffer); + LOG(logLevelWarn, "Socket create error: %s.", strBuffer); return INVALID_SOCKET; } else { @@ -60,7 +60,7 @@ namespace epics { else { epicsSocketDestroy (socket); epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "Socket connect error: %s", strBuffer); + LOG(logLevelDebug, "Socket connect error: %s.", strBuffer); } } } @@ -82,7 +82,7 @@ namespace epics { Transport::shared_pointer transport = context->getTransportRegistry()->get("TCP", &address, priority); if(transport.get()) { LOG(logLevelDebug, - "Reusing existing connection to PVA server: %s", + "Reusing existing connection to PVA server: %s.", ipAddrStr); if (transport->acquire(client)) return transport; @@ -95,13 +95,13 @@ namespace epics { transport = context->getTransportRegistry()->get("TCP", &address, priority); if(transport.get()) { LOG(logLevelDebug, - "Reusing existing connection to PVA server: %s", + "Reusing existing connection to PVA server: %s.", ipAddrStr); if (transport->acquire(client)) return transport; } - LOG(logLevelDebug, "Connecting to PVA server: %s", ipAddrStr); + LOG(logLevelDebug, "Connecting to PVA server: %s.", ipAddrStr); socket = tryConnect(address, 3); @@ -123,7 +123,7 @@ namespace epics { if(retval<0) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - LOG(logLevelWarn, "Error setting TCP_NODELAY: %s", errStr); + LOG(logLevelWarn, "Error setting TCP_NODELAY: %s.", errStr); } // enable TCP_KEEPALIVE @@ -133,7 +133,7 @@ namespace epics { { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - LOG(logLevelWarn, "Error setting SO_KEEPALIVE: %s", errStr); + LOG(logLevelWarn, "Error setting SO_KEEPALIVE: %s.", errStr); } // TODO tune buffer sizes?! Win32 defaults are 8k, which is OK @@ -147,7 +147,7 @@ namespace epics { if(retval<0) { char strBuffer[64]; epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); - LOG(logLevelDebug, "Error getting SO_SNDBUF: %s", strBuffer); + LOG(logLevelDebug, "Error getting SO_SNDBUF: %s.", strBuffer); } transport = detail::BlockingClientTCPTransportCodec::create( @@ -168,7 +168,7 @@ namespace epics { // TODO send security token - LOG(logLevelDebug, "Connected to PVA server: %s", ipAddrStr); + LOG(logLevelDebug, "Connected to PVA server: %s.", ipAddrStr); _namedLocker.releaseSynchronizationObject(&address); return transport; diff --git a/pvAccessApp/remote/blockingUDPTransport.cpp b/pvAccessApp/remote/blockingUDPTransport.cpp index 1c46b8c..3d20eae 100644 --- a/pvAccessApp/remote/blockingUDPTransport.cpp +++ b/pvAccessApp/remote/blockingUDPTransport.cpp @@ -52,23 +52,6 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so _threadId(0) { PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(blockingUDPTransport); - - // set receive timeout so that we do not have problems at shutdown (recvfrom would block) - struct timeval timeout; - memset(&timeout, 0, sizeof(struct timeval)); - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - if (unlikely(::setsockopt (_channel, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0)) - { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - LOG(logLevelError, - "Failed to set SO_RCVTIMEO for UDP socket %s: %s.", - inetAddressToString(_bindAddress).c_str(), errStr); - } - - } BlockingUDPTransport::~BlockingUDPTransport() { @@ -84,9 +67,13 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so void BlockingUDPTransport::start() { - String threadName = "UDP-receive "+inetAddressToString(_bindAddress); - LOG(logLevelDebug, "Starting thread: %s",threadName.c_str()); - + String threadName = "UDP-receive " + inetAddressToString(_bindAddress); + + if (IS_LOGGABLE(logLevelTrace)) + { + LOG(logLevelTrace, "Starting thread: %s.", threadName.c_str()); + } + _threadId = epicsThreadCreate(threadName.c_str(), epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackSmall), @@ -102,39 +89,44 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so Lock guard(_mutex); if(_closed.get()) return; _closed.set(); - + } + + if (IS_LOGGABLE(logLevelDebug)) + { LOG(logLevelDebug, "UDP socket %s closed.", inetAddressToString(_bindAddress).c_str()); - - epicsSocketSystemCallInterruptMechanismQueryInfo info = - epicsSocketSystemCallInterruptMechanismQuery (); - switch ( info ) { - case esscimqi_socketCloseRequired: - epicsSocketDestroy ( _channel ); - break; - case esscimqi_socketBothShutdownRequired: - { - int status = ::shutdown ( _channel, SHUT_RDWR ); - if ( status ) { - char sockErrBuf[64]; - epicsSocketConvertErrnoToString ( - sockErrBuf, sizeof ( sockErrBuf ) ); - LOG(logLevelDebug, - "UDP socket %s failed to shutdown: %s.", - inetAddressToString(_bindAddress).c_str(), sockErrBuf); - } - epicsSocketDestroy ( _channel ); } - break; - case esscimqi_socketSigAlarmRequired: - // TODO (not supported anymore anyway) - default: - epicsSocketDestroy(_channel); - } -} - // TODO send yourself a packet + epicsSocketSystemCallInterruptMechanismQueryInfo info = + epicsSocketSystemCallInterruptMechanismQuery (); + switch ( info ) + { + case esscimqi_socketCloseRequired: + epicsSocketDestroy ( _channel ); + break; + case esscimqi_socketBothShutdownRequired: + { + /*int status =*/ ::shutdown ( _channel, SHUT_RDWR ); + /* + if ( status ) { + char sockErrBuf[64]; + epicsSocketConvertErrnoToString ( + sockErrBuf, sizeof ( sockErrBuf ) ); + LOG(logLevelDebug, + "UDP socket %s failed to shutdown: %s.", + inetAddressToString(_bindAddress).c_str(), sockErrBuf); + } + */ + epicsSocketDestroy ( _channel ); + } + break; + case esscimqi_socketSigAlarmRequired: + // not supported anymore anyway + default: + epicsSocketDestroy(_channel); + } + // wait for send thread to exit cleanly if (waitForThreadToComplete) @@ -255,7 +247,7 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - LOG(logLevelError, "Socket recvfrom error: %s", errStr); + LOG(logLevelError, "Socket recvfrom error: %s.", errStr); } close(false); @@ -268,12 +260,11 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so close(false); } - String threadName = "UDP-receive "+inetAddressToString(_bindAddress); - /* - char threadName[40]; - epicsThreadGetName(_threadId, threadName, 40); - */ - LOG(logLevelDebug, "Thread '%s' exiting", threadName.c_str()); + if (IS_LOGGABLE(logLevelTrace)) + { + String threadName = "UDP-receive "+inetAddressToString(_bindAddress); + LOG(logLevelTrace, "Thread '%s' exiting.", threadName.c_str()); + } _shutdownEvent.signal(); } @@ -337,7 +328,7 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - LOG(logLevelDebug, "Socket sendto error: %s", errStr); + LOG(logLevelDebug, "Socket sendto error: %s.", errStr); return false; } @@ -358,7 +349,7 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - LOG(logLevelDebug, "Socket sendto error: %s", errStr); + LOG(logLevelDebug, "Socket sendto error: %s.", errStr); allOK = false; } } @@ -379,7 +370,7 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - LOG(logLevelError, "Socket getsockopt SO_RCVBUF error: %s", errStr); + LOG(logLevelError, "Socket getsockopt SO_RCVBUF error: %s.", errStr); } return (size_t)sockBufSize; diff --git a/pvAccessApp/remote/codec.cpp b/pvAccessApp/remote/codec.cpp index a96bebe..5cf50b0 100644 --- a/pvAccessApp/remote/codec.cpp +++ b/pvAccessApp/remote/codec.cpp @@ -131,7 +131,7 @@ namespace epics { if (magicCode != PVA_MAGIC) { LOG(logLevelError, - "Invalid header received from the client at %s:%d: %s," + "Invalid header received from the client at %s:%d: %s.," " disconnecting...", __FILE__, __LINE__, inetAddressToString(*getLastReadBufferSocketAddress()).c_str()); invalidDataStreamHandler(); @@ -406,7 +406,7 @@ namespace epics { msg << "requested for buffer size " << size << ", but maximum " << MAX_ENSURE_DATA_SIZE << " is allowed."; LOG(logLevelWarn, - "%s at %s:%d,", msg.str().c_str(), __FILE__, __LINE__); + "%s at %s:%d.,", msg.str().c_str(), __FILE__, __LINE__); std::string s = msg.str(); throw std::invalid_argument(s); } @@ -691,7 +691,7 @@ namespace epics { size << ", but only " << _maxSendPayloadSize << " available."; std::string s = msg.str(); LOG(logLevelWarn, - "%s at %s:%d,", msg.str().c_str(), __FILE__, __LINE__); + "%s at %s:%d.,", msg.str().c_str(), __FILE__, __LINE__); throw std::invalid_argument(s); } @@ -890,7 +890,7 @@ namespace epics { std::ostringstream msg; msg << "an exception caught while processing a send message: " << e.what(); - LOG(logLevelWarn, "%s at %s:%d", + LOG(logLevelWarn, "%s at %s:%d.", msg.str().c_str(), __FILE__, __LINE__); try { @@ -1029,7 +1029,7 @@ namespace epics { __FILE__, __LINE__, e.what()); } catch (...) { LOG(logLevelWarn, - "unknown exception caught while in sendThread at %s:%d", + "unknown exception caught while in sendThread at %s:%d.", __FILE__, __LINE__); } } @@ -1063,7 +1063,7 @@ namespace epics { __FILE__, __LINE__, e.what()); } catch (...) { LOG(logLevelWarn, - "unknown exception caught while in sendThread at %s:%d", + "unknown exception caught while in sendThread at %s:%d.", __FILE__, __LINE__); } } @@ -1111,38 +1111,47 @@ namespace epics { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); LOG(logLevelError, - "Error fetching socket remote address: %s", + "Error fetching socket remote address: %s.", errStr); } - - // set receive timeout so that we do not have problems at - //shutdown (recvfrom would block) - struct timeval timeout; - memset(&timeout, 0, sizeof(struct timeval)); - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - // TODO remove this and implement use epicsSocketSystemCallInterruptMechanismQuery - if (unlikely(::setsockopt (_channel, SOL_SOCKET, SO_RCVTIMEO, - (char*)&timeout, sizeof(timeout)) < 0)) - { - char errStr[64]; - epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); - LOG(logLevelError, - "Failed to set SO_RCVTIMEO for TDP socket %s: %s.", - inetAddressToString(_socketAddress).c_str(), errStr); - } - } // must be called only once, when there will be no operation on socket (e.g. just before tx/rx thread exists) void BlockingSocketAbstractCodec::internalDestroy() { - if(_channel != INVALID_SOCKET) { - // TODO ::shutdown for some OS??!!! - epicsSocketDestroy(_channel); - _channel = INVALID_SOCKET; - } + if(_channel != INVALID_SOCKET) { + + epicsSocketSystemCallInterruptMechanismQueryInfo info = + epicsSocketSystemCallInterruptMechanismQuery (); + switch ( info ) + { + case esscimqi_socketCloseRequired: + epicsSocketDestroy ( _channel ); + break; + case esscimqi_socketBothShutdownRequired: + { + /*int status =*/ ::shutdown ( _channel, SHUT_RDWR ); + /* + if ( status ) { + char sockErrBuf[64]; + epicsSocketConvertErrnoToString ( + sockErrBuf, sizeof ( sockErrBuf ) ); + LOG(logLevelDebug, + "TCP socket to %s failed to shutdown: %s.", + inetAddressToString(_socketAddress).c_str(), sockErrBuf); + } + */ + epicsSocketDestroy ( _channel ); + } + break; + case esscimqi_socketSigAlarmRequired: + // not supported anymore anyway + default: + epicsSocketDestroy(_channel); + } + + _channel = INVALID_SOCKET; + } } @@ -1250,6 +1259,16 @@ namespace epics { } + void BlockingTCPTransportCodec::internalClose(bool force) { + BlockingSocketAbstractCodec::internalClose(force); + if (IS_LOGGABLE(logLevelDebug)) + { + LOG(logLevelDebug, + "TCP socket to %s closed.", + inetAddressToString(_socketAddress).c_str()); + } + } + BlockingServerTCPTransportCodec::BlockingServerTCPTransportCodec( Context::shared_pointer const & context, SOCKET channel, @@ -1545,7 +1564,7 @@ namespace epics { { char ipAddrStr[48]; ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr)); - LOG(logLevelDebug, "Releasing transport to %s.", ipAddrStr); + LOG(logLevelDebug, "Releasing TCP transport to %s.", ipAddrStr); } _owners.erase(clientID); diff --git a/pvAccessApp/remote/codec.h b/pvAccessApp/remote/codec.h index ce4a5d3..a64406a 100644 --- a/pvAccessApp/remote/codec.h +++ b/pvAccessApp/remote/codec.h @@ -535,6 +535,8 @@ namespace epics { { } + virtual void internalClose(bool force); + Context::shared_pointer _context; IntrospectionRegistry _incomingIR; diff --git a/runTestServer b/runTestServer index 67f0e05..3a7c66a 100755 --- a/runTestServer +++ b/runTestServer @@ -16,4 +16,4 @@ fi # testServer echo "Starting pvAccess C++ test server..." -./bin/$EPICS_HOST_ARCH/testServer +./bin/$EPICS_HOST_ARCH/testServer $* From 8db40b7fabcd80e25d7b8bf2da0dd302605c7bf1 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Thu, 5 Jun 2014 13:37:30 +0200 Subject: [PATCH 24/32] pvput fixed --- testApp/remote/pvput.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/testApp/remote/pvput.cpp b/testApp/remote/pvput.cpp index 5d484c3..9e4e5ad 100644 --- a/testApp/remote/pvput.cpp +++ b/testApp/remote/pvput.cpp @@ -288,9 +288,6 @@ class ChannelPutRequesterImpl : public ChannelPutRequester std::cerr << "[" << m_channelName << "] channel put create: " << status << std::endl; } - // we always put all - m_bitSet->set(0); - // get immediately old value channelPut->get(); } @@ -318,6 +315,7 @@ class ChannelPutRequesterImpl : public ChannelPutRequester { Lock lock(m_pointerMutex); m_pvStructure = pvStructure; + // we always put all, so current bitSet is OK m_bitSet = bitSet; } From 63f23e278ad6f6ffcc6d7cfa0f871a50b734c559 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Fri, 6 Jun 2014 00:17:06 +0200 Subject: [PATCH 25/32] channelCreate w/ address prototype support; inetAddressUtil parsing error handling --- pvAccessApp/remote/blockingUDP.h | 7 +++--- pvAccessApp/remote/codec.h | 2 +- .../remoteClient/clientContextImpl.cpp | 22 +++++++++++-------- pvAccessApp/utils/inetAddressUtil.cpp | 8 +++---- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/pvAccessApp/remote/blockingUDP.h b/pvAccessApp/remote/blockingUDP.h index c467a20..cad6b22 100644 --- a/pvAccessApp/remote/blockingUDP.h +++ b/pvAccessApp/remote/blockingUDP.h @@ -70,7 +70,7 @@ namespace epics { } virtual epics::pvData::String getType() const { - return epics::pvData::String("UDP"); + return epics::pvData::String("udp"); } virtual std::size_t getReceiveBufferSize() const { @@ -135,8 +135,9 @@ namespace epics { virtual void close(); - virtual void ensureData(std::size_t /*size*/) { - // noop + virtual void ensureData(std::size_t size) { + if (_receiveBuffer->getRemaining() < size) + throw std::underflow_error("no more data in UDP packet"); } virtual void alignData(std::size_t alignment) { diff --git a/pvAccessApp/remote/codec.h b/pvAccessApp/remote/codec.h index a64406a..91eca9e 100644 --- a/pvAccessApp/remote/codec.h +++ b/pvAccessApp/remote/codec.h @@ -404,7 +404,7 @@ namespace epics { public: epics::pvData::String getType() const { - return epics::pvData::String("TCP"); + return epics::pvData::String("tcp"); } diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index fef1fbe..99468ae 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -2988,7 +2988,7 @@ namespace epics { epics::pvData::String const & channelName, ChannelRequester::shared_pointer const & channelRequester, short priority, - epics::pvData::String const & /*address*/) + epics::pvData::String const & addressesStr) { std::tr1::shared_ptr context = m_context.lock(); if (!context.get()) @@ -2999,8 +2999,12 @@ namespace epics { return nullChannel; } - // TODO support addressList auto_ptr addresses; + if (!addressesStr.empty()) + addresses.reset(getSocketAddressList(addressesStr, PVA_SERVER_PORT)); + if (addresses->empty()) + addresses.reset(); + Channel::shared_pointer channel = context->createChannelInternal(channelName, channelRequester, priority, addresses); if (channel.get()) channelRequester->channelCreated(Status::Ok, channel); @@ -3522,13 +3526,13 @@ namespace epics { { m_context->getChannelSearchManager()->registerSearchInstance(shared_from_this()); } - /* TODO - else - // TODO not only first - // TODO minor version - // TODO what to do if there is no channel, do not search in a loop!!! do this in other thread...! - searchResponse(CAConstants.PVA_MINOR_PROTOCOL_REVISION, addresses[0]); - */ + else if (!m_addresses->empty()) + { + // TODO not only first !!! + // TODO minor version !!! + // TODO what to do if there is no channel, do not search in a loop!!! do this in other thread...! + searchResponse(PVA_PROTOCOL_REVISION, &((*m_addresses)[0])); + } } virtual void searchResponse(int8 minorRevision, osiSockAddr* serverAddress) { diff --git a/pvAccessApp/utils/inetAddressUtil.cpp b/pvAccessApp/utils/inetAddressUtil.cpp index bb03abe..31996a3 100644 --- a/pvAccessApp/utils/inetAddressUtil.cpp +++ b/pvAccessApp/utils/inetAddressUtil.cpp @@ -121,15 +121,15 @@ InetAddrVector* getSocketAddressList(String list, int defaultPort, while((subEnd = list.find(' ', subStart))!=String::npos) { String address = list.substr(subStart, (subEnd-subStart)); osiSockAddr addr; - aToIPAddr(address.c_str(), defaultPort, &addr.ia); - iav->push_back(addr); + if (aToIPAddr(address.c_str(), defaultPort, &addr.ia) == 0) + iav->push_back(addr); subStart = list.find_first_not_of(" \t\r\n\v", subEnd); } if(subStart!=String::npos&&list.length()>0) { osiSockAddr addr; - aToIPAddr(list.substr(subStart).c_str(), defaultPort, &addr.ia); - iav->push_back(addr); + if (aToIPAddr(list.substr(subStart).c_str(), defaultPort, &addr.ia) == 0) + iav->push_back(addr); } if(appendList!=NULL) { From 05d4c3ea55e8867f58fc99b2c119dd3d4ab96223 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Fri, 6 Jun 2014 00:22:32 +0200 Subject: [PATCH 26/32] fixed no address case --- pvAccessApp/remoteClient/clientContextImpl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index 99468ae..80b601e 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -3001,10 +3001,12 @@ namespace epics { auto_ptr addresses; if (!addressesStr.empty()) + { addresses.reset(getSocketAddressList(addressesStr, PVA_SERVER_PORT)); - if (addresses->empty()) - addresses.reset(); - + if (addresses->empty()) + addresses.reset(); + } + Channel::shared_pointer channel = context->createChannelInternal(channelName, channelRequester, priority, addresses); if (channel.get()) channelRequester->channelCreated(Status::Ok, channel); From d19cf15a0ec481e52433a9ad7a6980bb952a224c Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 9 Jun 2014 08:25:47 +0200 Subject: [PATCH 27/32] started protocol changes --- pvAccessApp/pva/pvaConstants.h | 2 +- pvAccessApp/remote/beaconHandler.cpp | 54 +++++++++++-------- pvAccessApp/remote/beaconHandler.h | 41 +++++++++----- pvAccessApp/remote/remote.h | 5 ++ .../remoteClient/clientContextImpl.cpp | 22 +++++--- pvAccessApp/remoteClient/clientContextImpl.h | 2 +- pvAccessApp/server/beaconEmitter.cpp | 32 ++++------- pvAccessApp/server/beaconEmitter.h | 22 ++++---- pvAccessApp/server/serverContext.cpp | 19 ++++++- pvAccessApp/server/serverContext.h | 19 +++++++ 10 files changed, 141 insertions(+), 77 deletions(-) diff --git a/pvAccessApp/pva/pvaConstants.h b/pvAccessApp/pva/pvaConstants.h index d95f088..2b95c24 100644 --- a/pvAccessApp/pva/pvaConstants.h +++ b/pvAccessApp/pva/pvaConstants.h @@ -26,7 +26,7 @@ namespace pvAccess { const epics::pvData::int8 PVA_MAGIC = static_cast(0xCA); /** PVA protocol revision (implemented by this library). */ - const epics::pvData::int8 PVA_PROTOCOL_REVISION = 0; + const epics::pvData::int8 PVA_PROTOCOL_REVISION = 1; /** PVA version signature used to report this implementation version in header. */ const epics::pvData::int8 PVA_VERSION = PVA_PROTOCOL_REVISION; diff --git a/pvAccessApp/remote/beaconHandler.cpp b/pvAccessApp/remote/beaconHandler.cpp index 5bcaacc..8fafdd8 100644 --- a/pvAccessApp/remote/beaconHandler.cpp +++ b/pvAccessApp/remote/beaconHandler.cpp @@ -15,45 +15,43 @@ namespace epics { namespace pvAccess { BeaconHandler::BeaconHandler(Context::shared_pointer const & context, + std::string const & protocol, const osiSockAddr* responseFrom) : _context(Context::weak_pointer(context)), + _protocol(protocol), _responseFrom(*responseFrom), _mutex(), - _serverStartupTime(0) -{ - -} - -BeaconHandler::BeaconHandler(const osiSockAddr* responseFrom) : - _responseFrom(*responseFrom), - _mutex(), - _serverStartupTime(0) + _serverGUID(), + _serverChangeCount(-1), + _first(true) { } BeaconHandler::~BeaconHandler() { - } void BeaconHandler::beaconNotify(osiSockAddr* /*from*/, int8 remoteTransportRevision, - TimeStamp* timestamp, TimeStamp* startupTime, int16 sequentalID, + TimeStamp* timestamp, GUID const & guid, int16 sequentalID, + int16 changeCount, PVFieldPtr /*data*/) { - bool networkChanged = updateBeacon(remoteTransportRevision, timestamp, startupTime, sequentalID); + bool networkChanged = updateBeacon(remoteTransportRevision, timestamp, guid, sequentalID, changeCount); if (networkChanged) changedTransport(); } bool BeaconHandler::updateBeacon(int8 /*remoteTransportRevision*/, TimeStamp* /*timestamp*/, - TimeStamp* startupTime, int16 /*sequentalID*/) + GUID const & guid, int16 /*sequentalID*/, int16 changeCount) { - Lock guard(_mutex); - // first beacon notification check - if (_serverStartupTime.getSecondsPastEpoch() == 0) - { - _serverStartupTime = *startupTime; + Lock guard(_mutex); + // first beacon notification check + if (_first) + { + _first = false; + _serverGUID = guid; + _serverChangeCount = changeCount; // new server up.. _context.lock()->newServerDetected(); @@ -61,25 +59,35 @@ bool BeaconHandler::updateBeacon(int8 /*remoteTransportRevision*/, TimeStamp* /* return false; } - bool networkChange = !(_serverStartupTime == *startupTime); + bool networkChange = (memcmp(_serverGUID.value, guid.value, sizeof(guid.value)) != 0); if (networkChange) { - // update startup time - _serverStartupTime = *startupTime; + // update startup time and change count + _serverGUID = guid; + _serverChangeCount = changeCount; _context.lock()->newServerDetected(); return true; } + else if (_serverChangeCount != changeCount) + { + // update change count + _serverChangeCount = changeCount; + + // TODO be more specific (possible optimizations) + _context.lock()->newServerDetected(); + + return true; + } return false; } void BeaconHandler::changedTransport() { - // TODO why only TCP, actually TCP does not need this auto_ptr transports = - _context.lock()->getTransportRegistry()->get("TCP", &_responseFrom); + _context.lock()->getTransportRegistry()->get(_protocol, &_responseFrom); if (!transports.get()) return; diff --git a/pvAccessApp/remote/beaconHandler.h b/pvAccessApp/remote/beaconHandler.h index d4fdc37..941114a 100644 --- a/pvAccessApp/remote/beaconHandler.h +++ b/pvAccessApp/remote/beaconHandler.h @@ -38,36 +38,37 @@ namespace pvAccess { /** * Constructor. - * @param transport transport to be used to send beacons. - * @param context PVA context. */ - BeaconHandler(Context::shared_pointer const & context, const osiSockAddr* responseFrom); - /** - * Test Constructor (for testing) - * @param transport transport to be used to send beacons. - */ - BeaconHandler(const osiSockAddr* responseFrom); + BeaconHandler(Context::shared_pointer const & context, std::string const & protocol, + const osiSockAddr* responseFrom); + virtual ~BeaconHandler(); + /** * Update beacon period and do analitical checks (server restared, routing problems, etc.) * @param from who is notifying. * @param remoteTransportRevision encoded (major, minor) revision. - * @param timestamp time when beacon was received. - * @param startupTime server (reported) startup time. + * @param guid server GUID. * @param sequentalID sequential ID. + * @param changeCount change count. * @param data server status data, can be NULL. */ void beaconNotify(osiSockAddr* from, epics::pvData::int8 remoteTransportRevision, epics::pvData::TimeStamp* timestamp, - epics::pvData::TimeStamp* startupTime, + GUID const &guid, epics::pvData::int16 sequentalID, + epics::pvData::int16 changeCount, epics::pvData::PVFieldPtr data); private: /** * Context instance. */ Context::weak_pointer _context; + /** + * The procotol (transport), "tcp" for pvAccess TCP/IP. + */ + std::string _protocol; /** * Remote address. */ @@ -76,21 +77,33 @@ namespace pvAccess { * Mutex */ epics::pvData::Mutex _mutex; + /** + * Server GUID. + */ + GUID _serverGUID; /** * Server startup timestamp. */ - epics::pvData::TimeStamp _serverStartupTime; + epics::pvData::int16 _serverChangeCount; + /** + * First beacon flag. + */ + bool _first; + /** * Update beacon. * @param remoteTransportRevision encoded (major, minor) revision. * @param timestamp time when beacon was received. + * @param guid server GUID. * @param sequentalID sequential ID. + * @param changeCount change count. * @return network change (server restarted) detected. */ bool updateBeacon(epics::pvData::int8 remoteTransportRevision, epics::pvData::TimeStamp* timestamp, - epics::pvData::TimeStamp* startupTime, - epics::pvData::int16 sequentalID); + GUID const &guid, + epics::pvData::int16 sequentalID, + epics::pvData::int16 changeCount); /** * Changed transport (server restarted) notify. */ diff --git a/pvAccessApp/remote/remote.h b/pvAccessApp/remote/remote.h index 5a53b3a..af2e0ad 100644 --- a/pvAccessApp/remote/remote.h +++ b/pvAccessApp/remote/remote.h @@ -41,6 +41,11 @@ namespace epics { #define PVACCESS_REFCOUNT_MONITOR_DESTRUCT(name) class TransportRegistry; + + /** + * Globally unique ID. + */ + typedef struct { char value[12]; } GUID; enum QoS { /** diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index 80b601e..d778059 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -2640,10 +2640,13 @@ namespace epics { AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); - transport->ensureData((2*sizeof(int16)+2*sizeof(int32)+128)/sizeof(int8)); + transport->ensureData(12+2+2+16+2); + + GUID guid; + payloadBuffer->get(guid.value, 0, sizeof(guid.value)); int16 sequentalID = payloadBuffer->getShort(); - TimeStamp startupTimestamp(payloadBuffer->getLong(),payloadBuffer->getInt()); + int16 changeCount = payloadBuffer->getShort(); osiSockAddr serverAddress; serverAddress.ia.sin_family = AF_INET; @@ -2667,13 +2670,15 @@ namespace epics { serverAddress.ia.sin_addr = responseFrom->ia.sin_addr; serverAddress.ia.sin_port = htons(payloadBuffer->getShort()); + + std::string protocol = SerializeHelper::deserializeString(payloadBuffer, transport.get()); // TODO optimize ClientContextImpl::shared_pointer context = _context.lock(); if (!context) return; - std::tr1::shared_ptr beaconHandler = context->getBeaconHandler(responseFrom); + std::tr1::shared_ptr beaconHandler = context->getBeaconHandler(protocol, responseFrom); // currently we care only for servers used by this context if (beaconHandler == 0) return; @@ -2688,7 +2693,7 @@ namespace epics { } // notify beacon handler - beaconHandler->beaconNotify(responseFrom, version, ×tamp, &startupTimestamp, sequentalID, data); + beaconHandler->beaconNotify(responseFrom, version, ×tamp, guid, sequentalID, changeCount, data); } }; @@ -4342,17 +4347,22 @@ TODO /** * Get (and if necessary create) beacon handler. + * @param protocol the protocol. * @param responseFrom remote source address of received beacon. * @return beacon handler for particular server. */ - BeaconHandler::shared_pointer getBeaconHandler(osiSockAddr* responseFrom) + BeaconHandler::shared_pointer getBeaconHandler(std::string const & protocol, osiSockAddr* responseFrom) { + // TODO !!! protocol !!! + if (protocol != "tcp") + return BeaconHandler::shared_pointer(); + Lock guard(m_beaconMapMutex); AddressBeaconHandlerMap::iterator it = m_beaconHandlers.find(*responseFrom); BeaconHandler::shared_pointer handler; if (it == m_beaconHandlers.end()) { - handler.reset(new BeaconHandler(shared_from_this(), responseFrom)); + handler.reset(new BeaconHandler(shared_from_this(), protocol, responseFrom)); m_beaconHandlers[*responseFrom] = handler; } else diff --git a/pvAccessApp/remoteClient/clientContextImpl.h b/pvAccessApp/remoteClient/clientContextImpl.h index 3eb48d3..817aa92 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.h +++ b/pvAccessApp/remoteClient/clientContextImpl.h @@ -121,7 +121,7 @@ namespace epics { virtual void newServerDetected() = 0; - virtual std::tr1::shared_ptr getBeaconHandler(osiSockAddr* responseFrom) = 0; + virtual std::tr1::shared_ptr getBeaconHandler(std::string const & protocol, osiSockAddr* responseFrom) = 0; virtual void configure(epics::pvData::PVStructure::shared_pointer configuration) = 0; virtual void flush() = 0; diff --git a/pvAccessApp/server/beaconEmitter.cpp b/pvAccessApp/server/beaconEmitter.cpp index 7208ce8..2cfef19 100644 --- a/pvAccessApp/server/beaconEmitter.cpp +++ b/pvAccessApp/server/beaconEmitter.cpp @@ -25,10 +25,12 @@ const float BeaconEmitter::EPICS_PVA_MIN_BEACON_PERIOD = 1.0; const float BeaconEmitter::EPICS_PVA_MIN_BEACON_COUNT_LIMIT = 3.0; //BeaconEmitter::BeaconEmitter(Transport::shared_pointer const & transport, ServerContextImpl::shared_pointer const & context) : -BeaconEmitter::BeaconEmitter(Transport::shared_pointer const & transport, std::tr1::shared_ptr& context) : +BeaconEmitter::BeaconEmitter(std::string const & protocol, + Transport::shared_pointer const & transport, std::tr1::shared_ptr& context) : + _protocol(protocol), _transport(transport), _beaconSequenceID(0), - _startupTime(), + _guid(context->getGUID()), _fastBeaconPeriod(std::max(context->getBeaconPeriod(), EPICS_PVA_MIN_BEACON_PERIOD)), _slowBeaconPeriod(std::max(180.0, _fastBeaconPeriod)), // TODO configurable _beaconCountLimit((int16)std::max(10.0f, EPICS_PVA_MIN_BEACON_COUNT_LIMIT)), // TODO configurable @@ -37,22 +39,6 @@ BeaconEmitter::BeaconEmitter(Transport::shared_pointer const & transport, std::t _serverStatusProvider(context->getBeaconServerStatusProvider()), _timer(context->getTimer()) { - _startupTime.getCurrent(); -} - -BeaconEmitter::BeaconEmitter(Transport::shared_pointer const & transport, const osiSockAddr& serverAddress) : - _transport(transport), - _beaconSequenceID(0), - _startupTime(), - _fastBeaconPeriod(EPICS_PVA_MIN_BEACON_PERIOD), - _slowBeaconPeriod(180.0), - _beaconCountLimit(10), - _serverAddress(serverAddress), - _serverPort(serverAddress.ia.sin_port), - _serverStatusProvider(), - _timer(new Timer("pvAccess-server timer", lowPriority)) -{ - _startupTime.getCurrent(); } BeaconEmitter::~BeaconEmitter() @@ -89,16 +75,20 @@ void BeaconEmitter::send(ByteBuffer* buffer, TransportSendControl* control) } // send beacon - control->startMessage((int8)0, (sizeof(int16)+2*sizeof(int32)+128+sizeof(int16))/sizeof(int8)); + control->startMessage((int8)0, 12+2+2+16+2); + buffer->put(_guid.value, 0, sizeof(_guid.value)); buffer->putShort(_beaconSequenceID); - buffer->putLong((int64)_startupTime.getSecondsPastEpoch()); - buffer->putInt((int32)_startupTime.getNanoSeconds()); + + // TODO for now fixed changeCount + buffer->putShort(0); // NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0 encodeAsIPv6Address(buffer, &_serverAddress); buffer->putShort((int16)_serverPort); + SerializeHelper::serializeString(_protocol, buffer, control); + if (serverStatus) { // introspection interface + data diff --git a/pvAccessApp/server/beaconEmitter.h b/pvAccessApp/server/beaconEmitter.h index d23d93d..0c62c65 100644 --- a/pvAccessApp/server/beaconEmitter.h +++ b/pvAccessApp/server/beaconEmitter.h @@ -47,18 +47,15 @@ namespace epics { namespace pvAccess { /** * Constructor. + * @param protocol a protocol (transport) name to report. * @param transport transport to be used to send beacons. * @param context PVA context. */ -// BeaconEmitter(Transport::shared_pointer const & transport, ServerContextImpl::shared_pointer const & context); - BeaconEmitter(Transport::shared_pointer const & transport, std::tr1::shared_ptr& context); +// BeaconEmitter(std::sting const & protocol, +// Transport::shared_pointer const & transport, ServerContextImpl::shared_pointer const & context); + BeaconEmitter(std::string const & protocol, + Transport::shared_pointer const & transport, std::tr1::shared_ptr& context); - /** - * Test Constructor (ohne context) - * @param transport transport to be used to send beacons. - */ - BeaconEmitter(Transport::shared_pointer const & transport, const osiSockAddr& serverAddress); - virtual ~BeaconEmitter(); void lock(); @@ -97,6 +94,11 @@ namespace epics { namespace pvAccess { */ static const float EPICS_PVA_MIN_BEACON_COUNT_LIMIT; + /** + * Protocol. + */ + std::string _protocol; + /** * Transport. */ @@ -108,9 +110,9 @@ namespace epics { namespace pvAccess { epics::pvData::int16 _beaconSequenceID; /** - * Startup timestamp (when clients detect a change, they will consider server restarted). + * Server GUID. */ - epics::pvData::TimeStamp _startupTime; + GUID _guid; /** * Fast (at startup) beacon period (in sec). diff --git a/pvAccessApp/server/serverContext.cpp b/pvAccessApp/server/serverContext.cpp index 67995f0..b0bcc57 100644 --- a/pvAccessApp/server/serverContext.cpp +++ b/pvAccessApp/server/serverContext.cpp @@ -46,6 +46,7 @@ ServerContextImpl::ServerContextImpl(): epicsSignalInstallSigAlarmIgnore (); epicsSignalInstallSigPipeIgnore (); + generateGUID(); initializeLogger(); loadConfiguration(); } @@ -61,11 +62,26 @@ ServerContextImpl::~ServerContextImpl() dispose(); } +const GUID& ServerContextImpl::getGUID() +{ + return _guid; +} + const Version& ServerContextImpl::getVersion() { return ServerContextImpl::VERSION; } +void ServerContextImpl::generateGUID() +{ + epics::pvData::TimeStamp startupTime; + startupTime.getCurrent(); + + ByteBuffer buffer(_guid.value, sizeof(_guid.value)); + buffer.putLong(startupTime.getSecondsPastEpoch()); + buffer.putInt(startupTime.getNanoSeconds()); +} + void ServerContextImpl::initializeLogger() { //createFileLogger("serverContextImpl.log"); @@ -217,7 +233,8 @@ void ServerContextImpl::internalInitialize() // setup broadcast UDP transport initializeBroadcastTransport(); - _beaconEmitter.reset(new BeaconEmitter(_broadcastTransport, thisServerContext)); + // TODO introduce a constant + _beaconEmitter.reset(new BeaconEmitter("tcp", _broadcastTransport, thisServerContext)); } void ServerContextImpl::initializeBroadcastTransport() diff --git a/pvAccessApp/server/serverContext.h b/pvAccessApp/server/serverContext.h index bb9afd0..c7ad31a 100644 --- a/pvAccessApp/server/serverContext.h +++ b/pvAccessApp/server/serverContext.h @@ -35,6 +35,13 @@ public: * Destructor */ virtual ~ServerContext() {}; + + /** + * Returns GUID (12-byte array). + * @return GUID. + */ + virtual const GUID& getGUID() = 0; + /** * Get context implementation version. * @return version of the context implementation. @@ -115,6 +122,7 @@ public: virtual ~ServerContextImpl(); //**************** derived from ServerContext ****************// + const GUID& getGUID(); const Version& getVersion(); void initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry); void run(epics::pvData::int32 seconds); @@ -283,6 +291,12 @@ public: bool isChannelProviderNamePreconfigured(); private: + + /** + * Server GUID. + */ + GUID _guid; + /** * Initialization status. */ @@ -381,6 +395,11 @@ private: */ BeaconServerStatusProvider::shared_pointer _beaconServerStatusProvider; + /** + * Generate GUID. + */ + void generateGUID(); + /** * Initialize logger. */ From 8862d29ea51d149379e0ad8f83b5538ed9b1646d Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 9 Jun 2014 11:27:39 +0200 Subject: [PATCH 28/32] protocol change: searching messages --- pvAccessApp/remote/blockingUDP.h | 32 ++++- pvAccessApp/remote/blockingUDPConnector.cpp | 8 +- pvAccessApp/remote/blockingUDPTransport.cpp | 27 +++- .../remote/simpleChannelSearchManagerImpl.cpp | 39 ++++-- .../remote/simpleChannelSearchManagerImpl.h | 6 + .../remoteClient/clientContextImpl.cpp | 30 ++-- pvAccessApp/server/responseHandlers.cpp | 131 ++++++++++++++---- pvAccessApp/server/responseHandlers.h | 13 +- pvAccessApp/server/serverContext.cpp | 7 +- pvAccessApp/utils/inetAddressUtil.cpp | 6 + pvAccessApp/utils/inetAddressUtil.h | 7 + testApp/utils/testInetAddressUtils.cpp | 19 ++- 12 files changed, 263 insertions(+), 62 deletions(-) diff --git a/pvAccessApp/remote/blockingUDP.h b/pvAccessApp/remote/blockingUDP.h index cad6b22..02dc3da 100644 --- a/pvAccessApp/remote/blockingUDP.h +++ b/pvAccessApp/remote/blockingUDP.h @@ -35,6 +35,8 @@ namespace epics { namespace pvAccess { + enum InetAddressType { inetAddressType_all, inetAddressType_unicast, inetAddressType_broadcast_multicast }; + class BlockingUDPTransport : public epics::pvData::NoDefaultMethods, public Transport, public TransportSendControl, @@ -65,8 +67,7 @@ namespace epics { } virtual const osiSockAddr* getRemoteAddress() const { - // always connected - return &_bindAddress; + return &_remoteAddress; } virtual epics::pvData::String getType() const { @@ -228,7 +229,7 @@ namespace epics { bool send(epics::pvData::ByteBuffer* buffer, const osiSockAddr& address); - bool send(epics::pvData::ByteBuffer* buffer); + bool send(epics::pvData::ByteBuffer* buffer, InetAddressType target = inetAddressType_all); /** * Get list of send addresses. @@ -246,15 +247,31 @@ namespace epics { return &_bindAddress; } + bool isBroadcastAddress(const osiSockAddr* address, InetAddrVector *broadcastAddresses) + { + if (broadcastAddresses) + for (size_t i = 0; i < broadcastAddresses->size(); i++) + if ((*broadcastAddresses)[i].ia.sin_addr.s_addr == address->ia.sin_addr.s_addr) + return true; + return false; + } + /** * Set list of send addresses. * @param addresses list of send addresses, non-null. */ - void setBroadcastAddresses(InetAddrVector* addresses) { + void setSendAddresses(InetAddrVector* addresses) { if (addresses) { if (!_sendAddresses) _sendAddresses = new InetAddrVector; *_sendAddresses = *addresses; + + std::auto_ptr broadcastAddresses(getBroadcastAddresses(_channel, 0)); + _isSendAddressUnicast.resize(_sendAddresses->size()); + for (std::size_t i = 0; i < _sendAddresses->size(); i++) + _isSendAddressUnicast[i] = + !isBroadcastAddress(&(*_sendAddresses)[i], broadcastAddresses.get()) && + !isMulticastAddress(&(*_sendAddresses)[i]); } else { @@ -291,11 +308,18 @@ namespace epics { */ osiSockAddr _bindAddress; + /** + * Remote address. + */ + osiSockAddr _remoteAddress; + /** * Send addresses. */ InetAddrVector* _sendAddresses; + std::vector _isSendAddressUnicast; + /** * Ignore addresses. */ diff --git a/pvAccessApp/remote/blockingUDPConnector.cpp b/pvAccessApp/remote/blockingUDPConnector.cpp index ce6fa7b..a0a9ac4 100644 --- a/pvAccessApp/remote/blockingUDPConnector.cpp +++ b/pvAccessApp/remote/blockingUDPConnector.cpp @@ -45,7 +45,13 @@ namespace epics { } /* - IPv4 multicast addresses are defined by the leading address bits of 1110, originating from the classful network design of the early Internet when this group of addresses was designated as Class D. The Classless Inter-Domain Routing (CIDR) prefix of this group is 224.0.0.0/4. The group includes the addresses from 224.0.0.0 to 239.255.255.255. Address assignments from within this range are specified in RFC 5771, an Internet Engineering Task Force (IETF) Best Current Practice document (BCP 51).*/ + IPv4 multicast addresses are defined by the leading address bits of 1110, + originating from the classful network design of the early Internet when this + group of addresses was designated as Class D. The Classless Inter-Domain Routing (CIDR) + prefix of this group is 224.0.0.0/4. + The group includes the addresses from 224.0.0.0 to 239.255.255.255. + Address assignments from within this range are specified in RFC 5771, + an Internet Engineering Task Force (IETF) Best Current Practice document (BCP 51).*/ // set SO_REUSEADDR or SO_REUSEPORT, OS dependant diff --git a/pvAccessApp/remote/blockingUDPTransport.cpp b/pvAccessApp/remote/blockingUDPTransport.cpp index 3d20eae..934bf5c 100644 --- a/pvAccessApp/remote/blockingUDPTransport.cpp +++ b/pvAccessApp/remote/blockingUDPTransport.cpp @@ -52,6 +52,18 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so _threadId(0) { PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(blockingUDPTransport); + + osiSocklen_t sockLen = sizeof(sockaddr); + // read the actual socket info + int retval = ::getsockname(_channel, &_remoteAddress.sa, &sockLen); + if(retval<0) { + // error obtaining remote address, fallback to bindAddress + _remoteAddress = _bindAddress; + + char strBuffer[64]; + epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); + LOG(logLevelDebug, "getsockname error: %s", strBuffer); + } } BlockingUDPTransport::~BlockingUDPTransport() { @@ -332,16 +344,26 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so return false; } + // all sent + buffer->setPosition(buffer->getLimit()); + return true; } - bool BlockingUDPTransport::send(ByteBuffer* buffer) { + bool BlockingUDPTransport::send(ByteBuffer* buffer, InetAddressType target) { if(!_sendAddresses) return false; buffer->flip(); bool allOK = true; for(size_t i = 0; i<_sendAddresses->size(); i++) { + + // filter + if (target != inetAddressType_all) + if ((target == inetAddressType_unicast && !_isSendAddressUnicast[i]) || + (target == inetAddressType_broadcast_multicast && _isSendAddressUnicast[i])) + continue; + int retval = sendto(_channel, buffer->getArray(), buffer->getLimit(), 0, &((*_sendAddresses)[i].sa), sizeof(sockaddr)); @@ -354,6 +376,9 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so } } + // all sent + buffer->setPosition(buffer->getLimit()); + return allOK; } diff --git a/pvAccessApp/remote/simpleChannelSearchManagerImpl.cpp b/pvAccessApp/remote/simpleChannelSearchManagerImpl.cpp index f747bf5..bf234a6 100644 --- a/pvAccessApp/remote/simpleChannelSearchManagerImpl.cpp +++ b/pvAccessApp/remote/simpleChannelSearchManagerImpl.cpp @@ -20,8 +20,9 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { -const int SimpleChannelSearchManagerImpl::DATA_COUNT_POSITION = PVA_MESSAGE_HEADER_SIZE + sizeof(int32)/sizeof(int8) + 1; -const int SimpleChannelSearchManagerImpl::PAYLOAD_POSITION = sizeof(int16)/sizeof(int8) + 2; +const int SimpleChannelSearchManagerImpl::DATA_COUNT_POSITION = PVA_MESSAGE_HEADER_SIZE + 4+1+3+16+2+1+4; +const int SimpleChannelSearchManagerImpl::CAST_POSITION = PVA_MESSAGE_HEADER_SIZE + 4; +const int SimpleChannelSearchManagerImpl::PAYLOAD_POSITION = 4; // 225ms +/- 25ms random const double SimpleChannelSearchManagerImpl::ATOMIC_PERIOD = 0.225; @@ -46,6 +47,7 @@ SimpleChannelSearchManagerImpl::create(Context::shared_pointer const & context) SimpleChannelSearchManagerImpl::SimpleChannelSearchManagerImpl(Context::shared_pointer const & context) : m_context(context), + m_responseAddress(*context->getSearchTransport()->getRemoteAddress()), m_canceled(), m_sequenceNumber(0), m_sendBuffer(MAX_UDP_UNFRAGMENTED_SEND), @@ -56,6 +58,7 @@ SimpleChannelSearchManagerImpl::SimpleChannelSearchManagerImpl(Context::shared_p m_userValueMutex(), m_mutex() { + // initialize send buffer initializeSendBuffer(); @@ -177,15 +180,25 @@ void SimpleChannelSearchManagerImpl::initializeSendBuffer() m_sendBuffer.putByte(PVA_VERSION); m_sendBuffer.putByte((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) ? 0x80 : 0x00); // data + 7-bit endianess m_sendBuffer.putByte((int8_t)3); // search - m_sendBuffer.putInt(sizeof(int32_t)/sizeof(int8_t) + 1); // "zero" payload + m_sendBuffer.putInt(4+1+3+16+2+1); // "zero" payload m_sendBuffer.putInt(m_sequenceNumber); - /* - final boolean REQUIRE_REPLY = false; - sendBuffer.put(REQUIRE_REPLY ? (byte)QoS.REPLY_REQUIRED.getMaskValue() : (byte)QoS.DEFAULT.getMaskValue()); - */ + // multicast vs unicast mask + m_sendBuffer.putByte((int8_t)0); - m_sendBuffer.putByte((int8_t)QOS_DEFAULT); + // reserved part + m_sendBuffer.putByte((int8_t)0); + m_sendBuffer.putShort((int16_t)0); + + // NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0 + encodeAsIPv6Address(&m_sendBuffer, &m_responseAddress); + m_sendBuffer.putShort((int16_t)ntohs(m_responseAddress.ia.sin_port)); + + // TODO now only TCP is supported + // note: this affects DATA_COUNT_POSITION + m_sendBuffer.putByte((int8_t)1); + // TODO "tcp" constant + SerializeHelper::serializeString("tcp", &m_sendBuffer, &m_mockTransportSendControl); m_sendBuffer.putShort((int16_t)0); // count } @@ -195,8 +208,14 @@ void SimpleChannelSearchManagerImpl::flushSendBuffer() Transport::shared_pointer tt = m_context.lock()->getSearchTransport(); BlockingUDPTransport::shared_pointer ut = std::tr1::static_pointer_cast(tt); - ut->send(&m_sendBuffer); // TODO - initializeSendBuffer(); + + m_sendBuffer.putByte(CAST_POSITION, (int8_t)0x80); // unicast, no reply required + ut->send(&m_sendBuffer, inetAddressType_unicast); + + m_sendBuffer.putByte(CAST_POSITION, (int8_t)0x00); // b/m-cast, no reply required + ut->send(&m_sendBuffer, inetAddressType_broadcast_multicast); + + initializeSendBuffer(); } diff --git a/pvAccessApp/remote/simpleChannelSearchManagerImpl.h b/pvAccessApp/remote/simpleChannelSearchManagerImpl.h index d0a2e6b..d929468 100644 --- a/pvAccessApp/remote/simpleChannelSearchManagerImpl.h +++ b/pvAccessApp/remote/simpleChannelSearchManagerImpl.h @@ -133,6 +133,11 @@ class SimpleChannelSearchManagerImpl : */ Context::weak_pointer m_context; + /** + * Response address. + */ + osiSockAddr m_responseAddress; + /** * Canceled flag. */ @@ -179,6 +184,7 @@ class SimpleChannelSearchManagerImpl : epics::pvData::Mutex m_mutex; static const int DATA_COUNT_POSITION; + static const int CAST_POSITION; static const int PAYLOAD_POSITION; static const double ATOMIC_PERIOD; diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index d778059..69a1f92 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -2573,13 +2573,12 @@ namespace epics { { 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(12+4+16+2); - transport->ensureData((128+2*16)/8); + GUID guid; + payloadBuffer->get(guid.value, 0, sizeof(guid.value)); + + int32 searchSequenceId = payloadBuffer->getInt(); osiSockAddr serverAddress; serverAddress.ia.sin_family = AF_INET; @@ -2603,7 +2602,14 @@ namespace epics { serverAddress.ia.sin_addr = responseFrom->ia.sin_addr; serverAddress.ia.sin_port = htons(payloadBuffer->getShort()); - + + /*String protocol =*/ SerializeHelper::deserializeString(payloadBuffer, transport.get()); + + transport->ensureData(1); + bool found = payloadBuffer->getByte() != 0; + if (!found) + return; + // reads CIDs // TODO optimize std::tr1::shared_ptr csm = _context.lock()->getChannelSearchManager(); @@ -4070,14 +4076,14 @@ TODO m_connector.reset(new BlockingTCPConnector(thisPointer, m_receiveBufferSize, m_beaconPeriod)); m_transportRegistry.reset(new TransportRegistry()); - // setup search manager - m_channelSearchManager = SimpleChannelSearchManagerImpl::create(thisPointer); - // TODO put memory barrier here... (if not already called withing a lock?) // setup UDP transport initializeUDPTransport(); + // setup search manager + m_channelSearchManager = SimpleChannelSearchManagerImpl::create(thisPointer); + // TODO what if initialization failed!!! } @@ -4129,7 +4135,7 @@ TODO PVA_DEFAULT_PRIORITY)); if (!m_broadcastTransport.get()) return false; - m_broadcastTransport->setBroadcastAddresses(broadcastAddresses.get()); + m_broadcastTransport->setSendAddresses(broadcastAddresses.get()); // undefined address osiSockAddr undefinedAddress; @@ -4145,7 +4151,7 @@ TODO PVA_DEFAULT_PRIORITY)); if (!m_searchTransport.get()) return false; - m_searchTransport->setBroadcastAddresses(broadcastAddresses.get()); + m_searchTransport->setSendAddresses(broadcastAddresses.get()); // become active m_broadcastTransport->start(); diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index d1b94da..dbb7ec1 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -176,6 +176,8 @@ void ServerIntrospectionSearchHandler::handleResponse(osiSockAddr* responseFrom, /****************************************************************************************/ +std::string ServerSearchHandler::SUPPORTED_PROTOCOL = "tcp"; + ServerSearchHandler::ServerSearchHandler(ServerContextImpl::shared_pointer const & context) : AbstractServerResponseHandler(context, "Search request"), _providers(context->getChannelProviders()) { @@ -188,48 +190,110 @@ void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); - transport->ensureData((sizeof(int32)+sizeof(int16))/sizeof(int8)+1); + transport->ensureData(4+1+3+16+2); const int32 searchSequenceId = payloadBuffer->getInt(); const int8 qosCode = payloadBuffer->getByte(); + + // reserved part + payloadBuffer->getByte(); + payloadBuffer->getShort(); + + osiSockAddr responseAddress; + responseAddress.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 + responseAddress.ia.sin_addr.s_addr = htonl(payloadBuffer->getInt()); + if (responseAddress.ia.sin_addr.s_addr == INADDR_ANY) + responseAddress.ia.sin_addr = responseFrom->ia.sin_addr; + + responseAddress.ia.sin_port = htons(payloadBuffer->getShort()); + + size_t protocolsCount = SerializeHelper::readSize(payloadBuffer, transport.get()); + bool allowed = (protocolsCount == 0); + for (size_t i = 0; i < protocolsCount; i++) + { + String protocol = SerializeHelper::deserializeString(payloadBuffer, transport.get()); + if (SUPPORTED_PROTOCOL == protocol) + allowed = true; + } + + // NOTE: we do not stop reading the buffer + + transport->ensureData(2); const int32 count = payloadBuffer->getShort() & 0xFFFF; + const bool responseRequired = (QOS_REPLY_REQUIRED & qosCode) != 0; - for (int32 i = 0; i < count; i++) - { - transport->ensureData(sizeof(int32)/sizeof(int8)); - const int32 cid = payloadBuffer->getInt(); - const String name = SerializeHelper::deserializeString(payloadBuffer, transport.get()); - // no name check here... + // TODO locally broadcast if qosCode & 0x80 == 0x80 - // TODO object pool!!! - int providerCount = _providers.size(); - ServerChannelFindRequesterImpl* pr = new ServerChannelFindRequesterImpl(_context, providerCount); - pr->set(name, searchSequenceId, cid, responseFrom, responseRequired); - ChannelFindRequester::shared_pointer spr(pr); - - for (int i = 0; i < providerCount; i++) - _providers[i]->channelFind(name, spr); - } + if (count > 0) + { + for (int32 i = 0; i < count; i++) + { + transport->ensureData(4); + const int32 cid = payloadBuffer->getInt(); + const String name = SerializeHelper::deserializeString(payloadBuffer, transport.get()); + // no name check here... + + if (allowed) + { + // TODO object pool!!! + int providerCount = _providers.size(); + ServerChannelFindRequesterImpl* pr = new ServerChannelFindRequesterImpl(_context, providerCount); + pr->set(name, searchSequenceId, cid, responseAddress, responseRequired, false); + ChannelFindRequester::shared_pointer spr(pr); + + for (int i = 0; i < providerCount; i++) + _providers[i]->channelFind(name, spr); + } + } + } + else + { + if (allowed) + { + ServerChannelFindRequesterImpl* pr = new ServerChannelFindRequesterImpl(_context, 1); + pr->set("", searchSequenceId, 0, responseAddress, true, true); + ChannelFindRequester::shared_pointer spr(pr); + spr->channelFindResult(Status::Ok, ChannelFind::shared_pointer(), false); + } + } } ServerChannelFindRequesterImpl::ServerChannelFindRequesterImpl(ServerContextImpl::shared_pointer const & context, int32 expectedResponseCount) : - _sendTo(NULL), + _guid(context->getGUID()), + _sendTo(), _wasFound(false), _context(context), _expectedResponseCount(expectedResponseCount), - _responseCount(0) + _responseCount(0), + _serverSearch(false) {} void ServerChannelFindRequesterImpl::clear() { Lock guard(_mutex); - _sendTo = NULL; _wasFound = false; _responseCount = 0; + _serverSearch = false; } -ServerChannelFindRequesterImpl* ServerChannelFindRequesterImpl::set(String name, int32 searchSequenceId, int32 cid, osiSockAddr* sendTo, bool responseRequired) +ServerChannelFindRequesterImpl* ServerChannelFindRequesterImpl::set(String name, int32 searchSequenceId, int32 cid, osiSockAddr const & sendTo, + bool responseRequired, bool serverSearch) { Lock guard(_mutex); _name = name; @@ -237,6 +301,7 @@ ServerChannelFindRequesterImpl* ServerChannelFindRequesterImpl::set(String name, _cid = cid; _sendTo = sendTo; _responseRequired = responseRequired; + _serverSearch = serverSearch; return this; } @@ -288,20 +353,34 @@ void ServerChannelFindRequesterImpl::unlock() void ServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) { - int32 count = 1; - control->startMessage((int8)4, (sizeof(int32)+sizeof(int8)+128+2*sizeof(int16)+count*sizeof(int32))/sizeof(int8)); + control->startMessage((int8)4, 12+4+16+2); Lock guard(_mutex); + buffer->put(_guid.value, 0, sizeof(_guid.value)); buffer->putInt(_searchSequenceId); - buffer->putByte(_wasFound ? (int8)1 : (int8)0); // NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0 encodeAsIPv6Address(buffer, _context->getServerInetAddress()); buffer->putShort((int16)_context->getServerPort()); - buffer->putShort((int16)count); - buffer->putInt(_cid); - control->setRecipient(*_sendTo); + SerializeHelper::serializeString(ServerSearchHandler::SUPPORTED_PROTOCOL, buffer, control); + + control->ensureBuffer(1); + buffer->putByte(_wasFound ? (int8)1 : (int8)0); + + if (!_serverSearch) + { + // TODO for now we do not gather search responses + buffer->putShort((int16)1); + buffer->putInt(_cid); + } + else + { + buffer->putShort((int16)0); + } + + + control->setRecipient(_sendTo); } /****************************************************************************************/ diff --git a/pvAccessApp/server/responseHandlers.h b/pvAccessApp/server/responseHandlers.h index 01d23aa..a509069 100644 --- a/pvAccessApp/server/responseHandlers.h +++ b/pvAccessApp/server/responseHandlers.h @@ -159,7 +159,9 @@ namespace pvAccess { public: // TODO static std::map > s_channelNameToProvider; - + + static std::string SUPPORTED_PROTOCOL; + ServerSearchHandler(ServerContextImpl::shared_pointer const & context); virtual ~ServerSearchHandler(){} @@ -168,7 +170,7 @@ namespace pvAccess { std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer); private: - std::vector _providers; + std::vector _providers; }; @@ -181,22 +183,25 @@ namespace pvAccess { ServerChannelFindRequesterImpl(ServerContextImpl::shared_pointer const & context, epics::pvData::int32 expectedResponseCount); virtual ~ServerChannelFindRequesterImpl(){} void clear(); - ServerChannelFindRequesterImpl* set(epics::pvData::String _name, epics::pvData::int32 searchSequenceId, epics::pvData::int32 cid, osiSockAddr* sendTo, bool responseRequired); + ServerChannelFindRequesterImpl* set(epics::pvData::String _name, epics::pvData::int32 searchSequenceId, + epics::pvData::int32 cid, osiSockAddr const & sendTo, bool responseRequired, bool serverSearch); void channelFindResult(const epics::pvData::Status& status, ChannelFind::shared_pointer const & channelFind, bool wasFound); void lock(); void unlock(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: + GUID _guid; epics::pvData::String _name; epics::pvData::int32 _searchSequenceId; epics::pvData::int32 _cid; - osiSockAddr* _sendTo; + osiSockAddr _sendTo; bool _responseRequired; bool _wasFound; ServerContextImpl::shared_pointer _context; epics::pvData::Mutex _mutex; epics::pvData::int32 _expectedResponseCount; epics::pvData::int32 _responseCount; + bool _serverSearch; }; /****************************************************************************************/ diff --git a/pvAccessApp/server/serverContext.cpp b/pvAccessApp/server/serverContext.cpp index b0bcc57..a028a0a 100644 --- a/pvAccessApp/server/serverContext.cpp +++ b/pvAccessApp/server/serverContext.cpp @@ -74,6 +74,7 @@ const Version& ServerContextImpl::getVersion() void ServerContextImpl::generateGUID() { + // TODO use UUID epics::pvData::TimeStamp startupTime; startupTime.getCurrent(); @@ -84,7 +85,7 @@ void ServerContextImpl::generateGUID() void ServerContextImpl::initializeLogger() { - //createFileLogger("serverContextImpl.log"); + //createFileLogger("serverContextImpl.log"); } struct noop_deleter @@ -265,7 +266,7 @@ void ServerContextImpl::initializeBroadcastTransport() nullTransportClient, responseHandler, listenLocalAddress, PVA_PROTOCOL_REVISION, PVA_DEFAULT_PRIORITY)); - _broadcastTransport->setBroadcastAddresses(broadcastAddresses.get()); + _broadcastTransport->setSendAddresses(broadcastAddresses.get()); // set ignore address list if (!_ignoreAddressList.empty()) @@ -290,7 +291,7 @@ void ServerContextImpl::initializeBroadcastTransport() auto_ptr list(getSocketAddressList(_beaconAddressList, _broadcastPort, appendList)); if (list.get() != NULL && list->size() > 0) { - _broadcastTransport->setBroadcastAddresses(list.get()); + _broadcastTransport->setSendAddresses(list.get()); } } diff --git a/pvAccessApp/utils/inetAddressUtil.cpp b/pvAccessApp/utils/inetAddressUtil.cpp index 31996a3..2408118 100644 --- a/pvAccessApp/utils/inetAddressUtil.cpp +++ b/pvAccessApp/utils/inetAddressUtil.cpp @@ -64,6 +64,12 @@ void encodeAsIPv6Address(ByteBuffer* buffer, const osiSockAddr* address) { buffer->putByte((int8)(ipv4Addr&0xFF)); } +bool isMulticastAddress(const osiSockAddr* address) { + uint32_t ipv4Addr = ntohl(address->ia.sin_addr.s_addr); + uint8_t msB = (uint8_t)((ipv4Addr>>24)&0xFF); + return msB >= 224 && msB <= 239; +} + osiSockAddr* intToIPv4Address(int32 addr) { osiSockAddr* ret = new osiSockAddr; ret->ia.sin_family = AF_INET; diff --git a/pvAccessApp/utils/inetAddressUtil.h b/pvAccessApp/utils/inetAddressUtil.h index c33f086..2c43826 100644 --- a/pvAccessApp/utils/inetAddressUtil.h +++ b/pvAccessApp/utils/inetAddressUtil.h @@ -49,6 +49,13 @@ namespace pvAccess { */ epicsShareFunc void encodeAsIPv6Address(epics::pvData::ByteBuffer* buffer, const osiSockAddr* address); + /** + * Check if an IPv4 address is a multicast address. + * @param address IPv4 address to check. + * @return true if the adress is a multicast address. + */ + epicsShareFunc bool isMulticastAddress(const osiSockAddr* address); + /** * Convert an integer into an IPv4 INET address. * @param addr integer representation of a given address. diff --git a/testApp/utils/testInetAddressUtils.cpp b/testApp/utils/testInetAddressUtils.cpp index c79845a..b2e06a5 100644 --- a/testApp/utils/testInetAddressUtils.cpp +++ b/testApp/utils/testInetAddressUtils.cpp @@ -125,6 +125,22 @@ void test_encodeAsIPv6Address() testOk1(strncmp(buff->getArray(), src, 16) == 0); } +void test_isMulticastAddress() +{ + testDiag("Test test_isMulticastAddress()"); + + auto_ptr vec(getSocketAddressList("127.0.0.1 255.255.255.255 0.0.0.0 224.0.0.0 239.255.255.255 235.3.6.3", 0)); + + testOk1(static_cast(6) == vec->size()); + + testOk1(!isMulticastAddress(&vec->at(0))); + testOk1(!isMulticastAddress(&vec->at(1))); + testOk1(!isMulticastAddress(&vec->at(2))); + testOk1(isMulticastAddress(&vec->at(3))); + testOk1(isMulticastAddress(&vec->at(4))); + testOk1(isMulticastAddress(&vec->at(5))); +} + void test_getBroadcastAddresses() { testDiag("Test getBroadcastAddresses()"); @@ -146,13 +162,14 @@ void test_getBroadcastAddresses() MAIN(testInetAddressUtils) { - testPlan(44); + testPlan(51); testDiag("Tests for InetAddress utils"); test_getSocketAddressList(); test_ipv4AddressToInt(); test_intToIPv4Address(); test_encodeAsIPv6Address(); + test_isMulticastAddress(); test_getBroadcastAddresses(); return testDone(); From b101fa1e7a1837194d4b35c176899f9100e2ecd2 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 9 Jun 2014 12:39:29 +0200 Subject: [PATCH 29/32] protocol change: connection validation/authNZ support --- pvAccessApp/remote/blockingTCPAcceptor.cpp | 5 +- pvAccessApp/remote/blockingUDP.h | 2 +- pvAccessApp/remote/codec.cpp | 129 ++++++++++++------ pvAccessApp/remote/codec.h | 43 ++++-- pvAccessApp/remote/remote.h | 9 +- .../remoteClient/clientContextImpl.cpp | 58 ++++++-- pvAccessApp/server/responseHandlers.cpp | 37 +++-- pvAccessApp/server/responseHandlers.h | 16 --- testApp/remote/testCodec.cpp | 2 +- 9 files changed, 186 insertions(+), 115 deletions(-) diff --git a/pvAccessApp/remote/blockingTCPAcceptor.cpp b/pvAccessApp/remote/blockingTCPAcceptor.cpp index f778f6e..a63587e 100644 --- a/pvAccessApp/remote/blockingTCPAcceptor.cpp +++ b/pvAccessApp/remote/blockingTCPAcceptor.cpp @@ -180,7 +180,7 @@ namespace pvAccess { LOG(logLevelDebug, "Error setting SO_KEEPALIVE: %s.", strBuffer); } - // TODO tune buffer sizes?! + // do NOT tune socket buffer sizes, this will disable auto-tunning // get TCP send buffer size osiSocklen_t intLen = sizeof(int); @@ -223,7 +223,8 @@ namespace pvAccess { bool BlockingTCPAcceptor::validateConnection(Transport::shared_pointer const & transport, const char* address) { try { - transport->verify(0); + // TODO constant + transport->verify(5000); return true; } catch(...) { LOG(logLevelDebug, "Validation of %s failed.", address); diff --git a/pvAccessApp/remote/blockingUDP.h b/pvAccessApp/remote/blockingUDP.h index 02dc3da..4504cc6 100644 --- a/pvAccessApp/remote/blockingUDP.h +++ b/pvAccessApp/remote/blockingUDP.h @@ -115,7 +115,7 @@ namespace epics { return true; } - virtual void verified() { + virtual void verified(epics::pvData::Status const & /*status*/) { // noop } diff --git a/pvAccessApp/remote/codec.cpp b/pvAccessApp/remote/codec.cpp index 5cf50b0..2dba640 100644 --- a/pvAccessApp/remote/codec.cpp +++ b/pvAccessApp/remote/codec.cpp @@ -1269,6 +1269,35 @@ namespace epics { } } + + bool BlockingTCPTransportCodec::verify(epics::pvData::int32 timeoutMs) { + return _verifiedEvent.wait(timeoutMs/1000.0); + } + + void BlockingTCPTransportCodec::verified(epics::pvData::Status const & status) { + epics::pvData::Lock lock(_verifiedMutex); + + if (IS_LOGGABLE(logLevelDebug) && !status.isOK()) + { + char ipAddrStr[48]; + ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr)); + LOG(logLevelDebug, "Failed to verify connection to %s: %s.", ipAddrStr, status.getMessage().c_str()); + // TODO stack dump + } + + _verified = status.isSuccess(); + _verifiedEvent.signal(); + } + + + + + + + + + + BlockingServerTCPTransportCodec::BlockingServerTCPTransportCodec( Context::shared_pointer const & context, SOCKET channel, @@ -1277,7 +1306,7 @@ namespace epics { int32_t receiveBufferSize) : BlockingTCPTransportCodec(context, channel, responseHandler, sendBufferSize, receiveBufferSize, PVA_DEFAULT_PRIORITY), - _lastChannelSID(0) + _lastChannelSID(0), _verifyOrVerified(false) { // NOTE: priority not yet known, default priority is used to @@ -1343,33 +1372,59 @@ namespace epics { void BlockingServerTCPTransportCodec::send(ByteBuffer* buffer, TransportSendControl* control) { - // - // set byte order control message - // + if (!_verifyOrVerified) + { + _verifyOrVerified = true; - ensureBuffer(PVA_MESSAGE_HEADER_SIZE); - buffer->putByte(PVA_MAGIC); - buffer->putByte(PVA_VERSION); - buffer->putByte( - 0x01 | ((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) - ? 0x80 : 0x00)); // control + big endian - buffer->putByte(2); // set byte order - buffer->putInt(0); + // + // set byte order control message + // + + ensureBuffer(PVA_MESSAGE_HEADER_SIZE); + buffer->putByte(PVA_MAGIC); + buffer->putByte(PVA_VERSION); + buffer->putByte( + 0x01 | ((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) + ? 0x80 : 0x00)); // control + big endian + buffer->putByte(2); // set byte order + buffer->putInt(0); - // - // send verification message - // - control->startMessage(CMD_CONNECTION_VALIDATION, 2*sizeof(int32)); + // + // send verification message + // + control->startMessage(CMD_CONNECTION_VALIDATION, 4+2); - // receive buffer size - buffer->putInt(static_cast(getReceiveBufferSize())); + // receive buffer size + buffer->putInt(static_cast(getReceiveBufferSize())); - // socket receive buffer size - buffer->putInt(static_cast(getSocketReceiveBufferSize())); + // server introspection registy max size + // TODO + buffer->putShort(0x7FFF); - // send immediately - control->flush(true); + // list of authNZ plugin names + // TODO + buffer->putByte(0); + + // send immediately + control->flush(true); + } + else + { + // + // send verified message + // + control->startMessage(CMD_CONNECTION_VALIDATED, 0); + + { + Lock lock(_verificationStatusMutex); + _verificationStatus.serialize(buffer, control); + } + + // send immediately + control->flush(true); + + } } void BlockingServerTCPTransportCodec::destroyAllChannels() { @@ -1419,8 +1474,7 @@ namespace epics { sendBufferSize, receiveBufferSize, priority), _connectionTimeout(beaconInterval*1000), _unresponsiveTransport(false), - _verifyOrEcho(true), - _verified(false) + _verifyOrEcho(true) { // initialize owners list, send queue acquire(client); @@ -1581,16 +1635,6 @@ namespace epics { if(_unresponsiveTransport) responsiveTransport(); } - bool BlockingClientTCPTransportCodec::verify(epics::pvData::int32 timeoutMs) { - return _verifiedEvent.wait(timeoutMs/1000.0); - } - - void BlockingClientTCPTransportCodec::verified() { - epics::pvData::Lock lock(_verifiedMutex); - _verified = true; - _verifiedEvent.signal(); - } - void BlockingClientTCPTransportCodec::responsiveTransport() { Lock lock(_mutex); if(_unresponsiveTransport) { @@ -1625,25 +1669,30 @@ namespace epics { void BlockingClientTCPTransportCodec::send(ByteBuffer* buffer, TransportSendControl* control) { if(_verifyOrEcho) { + _verifyOrEcho = false; + /* * send verification response message */ - control->startMessage(CMD_CONNECTION_VALIDATION, 2*sizeof(int32)+sizeof(int16)); + control->startMessage(CMD_CONNECTION_VALIDATION, 4+2+2); // receive buffer size buffer->putInt(static_cast(getReceiveBufferSize())); - // socket receive buffer size - buffer->putInt(static_cast(getSocketReceiveBufferSize())); + // max introspection registry size + // TODO + buffer->putShort(0x7FFF); - // connection priority + // QoS (aka connection priority) buffer->putShort(getPriority()); + // authNZ plugin name + // TODO + SerializeHelper::serializeString("", buffer, control); + // send immediately control->flush(true); - - _verifyOrEcho = false; } else { control->startMessage(CMD_ECHO, 0); diff --git a/pvAccessApp/remote/codec.h b/pvAccessApp/remote/codec.h index 91eca9e..69afd4c 100644 --- a/pvAccessApp/remote/codec.h +++ b/pvAccessApp/remote/codec.h @@ -518,6 +518,10 @@ namespace epics { start(); } + bool verify(epics::pvData::int32 timeoutMs); + + void verified(epics::pvData::Status const & status); + protected: BlockingTCPTransportCodec( @@ -531,7 +535,8 @@ namespace epics { BlockingSocketAbstractCodec(channel, sendBufferSize, receiveBufferSize), _context(context), _responseHandler(responseHandler), _remoteTransportReceiveBufferSize(MAX_TCP_RECV), - _remoteTransportRevision(0), _priority(priority) + _remoteTransportRevision(0), _priority(priority), + _verified(false) { } @@ -548,6 +553,10 @@ namespace epics { size_t _remoteTransportReceiveBufferSize; epics::pvData::int8 _remoteTransportRevision; epics::pvData::int16 _priority; + + bool _verified; + epics::pvData::Mutex _verifiedMutex; + epics::pvData::Event _verifiedEvent; }; @@ -622,14 +631,23 @@ namespace epics { } bool verify(epics::pvData::int32 timeoutMs) { - TransportSender::shared_pointer transportSender = + + TransportSender::shared_pointer transportSender = std::tr1::dynamic_pointer_cast(shared_from_this()); enqueueSendRequest(transportSender); - verified(); - return true; + + bool verifiedStatus = BlockingTCPTransportCodec::verify(timeoutMs); + + enqueueSendRequest(transportSender); + + return verifiedStatus; } - void verified() { + void verified(epics::pvData::Status const & status) { + _verificationStatusMutex.lock(); + _verificationStatus = status; + _verificationStatusMutex.unlock(); + BlockingTCPTransportCodec::verified(status); } void aliveNotification() { @@ -660,6 +678,11 @@ namespace epics { epics::pvData::Mutex _channelsMutex; + epics::pvData::Status _verificationStatus; + epics::pvData::Mutex _verificationStatusMutex; + + bool _verifyOrVerified; + }; class BlockingClientTCPTransportCodec : @@ -731,10 +754,6 @@ namespace epics { // noop } - bool verify(epics::pvData::int32 timeoutMs); - - void verified(); - void aliveNotification(); void send(epics::pvData::ByteBuffer* buffer, @@ -786,13 +805,7 @@ namespace epics { */ void responsiveTransport(); - epics::pvData::Mutex _mutex; - - bool _verified; - epics::pvData::Mutex _verifiedMutex; - epics::pvData::Event _verifiedEvent; - }; } diff --git a/pvAccessApp/remote/remote.h b/pvAccessApp/remote/remote.h index af2e0ad..e1d9178 100644 --- a/pvAccessApp/remote/remote.h +++ b/pvAccessApp/remote/remote.h @@ -94,11 +94,11 @@ namespace epics { CMD_ECHO = 2, CMD_SEARCH = 3, CMD_SEARCH_RESPONSE = 4, - CMD_INTROSPECTION_SEARCH = 5, - CMD_INTROSPECTION_SEARCH_RESPONSE = 6, + CMD_AUTHNZ = 5, + CMD_ACL_CHANGE = 6, CMD_CREATE_CHANNEL = 7, CMD_DESTROY_CHANNEL = 8, - CMD_RESERVED0 = 9, + CMD_CONNECTION_VALIDATED = 9, CMD_GET = 10, CMD_PUT = 11, CMD_PUT_GET = 12, @@ -263,8 +263,9 @@ namespace epics { /** * Notify transport that it is has been verified. + * @param status vefification status; */ - virtual void verified() = 0; + virtual void verified(epics::pvData::Status const & status) = 0; /** * Waits (if needed) until transport is verified, i.e. verified() method is being called. diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index 69a1f92..1866185 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -228,14 +228,14 @@ namespace epics { transport->ensureData(1); int8 qos = payloadBuffer->getByte(); - Status m_status; - m_status.deserialize(payloadBuffer, transport.get()); + Status status; + status.deserialize(payloadBuffer, transport.get()); try { if (qos & QOS_INIT) { - if (m_status.isSuccess()) + if (status.isSuccess()) { // once created set destroy flag m_mutex.lock(); @@ -247,7 +247,7 @@ namespace epics { // this is safe since at least caller owns it m_thisPointer.reset(); - initResponse(transport, version, payloadBuffer, qos, m_status); + initResponse(transport, version, payloadBuffer, qos, status); } else { @@ -261,7 +261,7 @@ namespace epics { m_mutex.unlock(); } - normalResponse(transport, version, payloadBuffer, qos, m_status); + normalResponse(transport, version, payloadBuffer, qos, status); if (destroyReq) destroy(); @@ -2719,16 +2719,44 @@ namespace epics { { AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); - transport->ensureData(8); - transport->setRemoteTransportReceiveBufferSize(payloadBuffer->getInt()); - transport->setRemoteTransportSocketReceiveBufferSize(payloadBuffer->getInt()); - transport->setRemoteRevision(version); + + transport->ensureData(4+2); + + transport->setRemoteTransportReceiveBufferSize(payloadBuffer->getInt()); + // TODO + // TODO serverIntrospectionRegistryMaxSize + /*int serverIntrospectionRegistryMaxSize = */ payloadBuffer->getShort(); + // TODO authNZ + size_t size = SerializeHelper::readSize(payloadBuffer, transport.get()); + for (size_t i = 0; i < size; i++) + SerializeHelper::deserializeString(payloadBuffer, transport.get()); + TransportSender::shared_pointer sender = dynamic_pointer_cast(transport); - if (sender.get()) { + if (sender.get()) transport->enqueueSendRequest(sender); - } - transport->verified(); + } + }; + + class ClientConnectionValidatedHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + public: + ClientConnectionValidatedHandler(ClientContextImpl::shared_pointer context) : + AbstractClientResponseHandler(context, "Connection validated") + { + } + + virtual ~ClientConnectionValidatedHandler() { + } + + virtual void handleResponse(osiSockAddr* responseFrom, + Transport::shared_pointer const & transport, int8 version, int8 command, + size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer) + { + AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); + + Status status; + status.deserialize(payloadBuffer, transport.get()); + transport->verified(status); } }; @@ -2843,11 +2871,11 @@ namespace epics { m_handlerTable[CMD_ECHO].reset(new NoopResponse(context, "Echo")); /* 2 */ m_handlerTable[CMD_SEARCH].reset(new NoopResponse(context, "Search")); /* 3 */ m_handlerTable[CMD_SEARCH_RESPONSE].reset(new SearchResponseHandler(context)); /* 4 */ - m_handlerTable[CMD_INTROSPECTION_SEARCH].reset(new NoopResponse(context, "Introspection search")); /* 5 */ - m_handlerTable[CMD_INTROSPECTION_SEARCH_RESPONSE] = dataResponse; /* 6 - introspection search */ + m_handlerTable[CMD_AUTHNZ].reset(new NoopResponse(context, "Introspection search")); /* 5 */ + m_handlerTable[CMD_ACL_CHANGE] = dataResponse; /* 6 */ m_handlerTable[CMD_CREATE_CHANNEL].reset(new CreateChannelHandler(context)); /* 7 */ m_handlerTable[CMD_DESTROY_CHANNEL].reset(new NoopResponse(context, "Destroy channel")); /* 8 */ // TODO it might be useful to implement this... - m_handlerTable[CMD_RESERVED0] = badResponse; /* 9 */ + m_handlerTable[CMD_CONNECTION_VALIDATED].reset(new ClientConnectionValidatedHandler(context)); /* 9 */ m_handlerTable[CMD_GET] = dataResponse; /* 10 - get response */ m_handlerTable[CMD_PUT] = dataResponse; /* 11 - put response */ m_handlerTable[CMD_PUT_GET] = dataResponse; /* 12 - put-get response */ diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index dbb7ec1..8595637 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -90,11 +90,11 @@ ServerResponseHandler::ServerResponseHandler(ServerContextImpl::shared_pointer c m_handlerTable[CMD_ECHO].reset(new ServerEchoHandler(context)); /* 2 */ m_handlerTable[CMD_SEARCH].reset(new ServerSearchHandler(context)); /* 3 */ m_handlerTable[CMD_SEARCH_RESPONSE] = badResponse; - m_handlerTable[CMD_INTROSPECTION_SEARCH].reset(new ServerIntrospectionSearchHandler(context)); /* 5 */ - m_handlerTable[CMD_INTROSPECTION_SEARCH_RESPONSE] = badResponse; /* 6 - introspection search */ + m_handlerTable[CMD_AUTHNZ] = badResponse; /* 5 */ + m_handlerTable[CMD_ACL_CHANGE] = badResponse; /* 6 - introspection search */ m_handlerTable[CMD_CREATE_CHANNEL].reset(new ServerCreateChannelHandler(context)); /* 7 */ m_handlerTable[CMD_DESTROY_CHANNEL].reset(new ServerDestroyChannelHandler(context)); /* 8 */ - m_handlerTable[CMD_RESERVED0] = badResponse; /* 9 */ + m_handlerTable[CMD_CONNECTION_VALIDATED] = badResponse; /* 9 */ m_handlerTable[CMD_GET].reset(new ServerGetHandler(context)); /* 10 - get response */ m_handlerTable[CMD_PUT].reset(new ServerPutHandler(context)); /* 11 - put response */ @@ -142,14 +142,19 @@ void ServerConnectionValidationHandler::handleResponse( AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); - transport->ensureData(2*sizeof(int32)+sizeof(int16)); - transport->setRemoteTransportReceiveBufferSize( - payloadBuffer->getInt()); - transport->setRemoteTransportSocketReceiveBufferSize( - payloadBuffer->getInt()); - transport->setRemoteRevision(version); - // TODO support priority !!! - //transport.setPriority(payloadBuffer.getShort()); + transport->setRemoteRevision(version); + + transport->ensureData(4+2+2); + transport->setRemoteTransportReceiveBufferSize(payloadBuffer->getInt()); + // TODO clientIntrospectionRegistryMaxSize + /* int clientIntrospectionRegistryMaxSize = */ payloadBuffer->getShort(); + // TODO connectionQoS + /* int16 connectionQoS = */ payloadBuffer->getShort(); + // TODO authNZ + /*std::string authNZ = */ SerializeHelper::deserializeString(payloadBuffer, transport.get()); + + // TODO call this after authNZ has done their work + transport->verified(Status::Ok); } void ServerEchoHandler::handleResponse(osiSockAddr* responseFrom, @@ -164,16 +169,6 @@ void ServerEchoHandler::handleResponse(osiSockAddr* responseFrom, transport->enqueueSendRequest(echoReply); } -void ServerIntrospectionSearchHandler::handleResponse(osiSockAddr* responseFrom, - Transport::shared_pointer const & transport, int8 version, int8 command, - size_t payloadSize, ByteBuffer* payloadBuffer) -{ - AbstractServerResponseHandler::handleResponse(responseFrom, - transport, version, command, payloadSize, payloadBuffer); - - THROW_BASE_EXCEPTION("not implemented"); -} - /****************************************************************************************/ std::string ServerSearchHandler::SUPPORTED_PROTOCOL = "tcp"; diff --git a/pvAccessApp/server/responseHandlers.h b/pvAccessApp/server/responseHandlers.h index a509069..552c0c4 100644 --- a/pvAccessApp/server/responseHandlers.h +++ b/pvAccessApp/server/responseHandlers.h @@ -133,22 +133,6 @@ namespace pvAccess { osiSockAddr _echoFrom; }; - /** - * Introspection search request handler. - */ - class ServerIntrospectionSearchHandler : public AbstractServerResponseHandler - { - public: - ServerIntrospectionSearchHandler(ServerContextImpl::shared_pointer const & context) : - AbstractServerResponseHandler(context, "Search request") { - } - virtual ~ServerIntrospectionSearchHandler() {} - - virtual void handleResponse(osiSockAddr* responseFrom, - Transport::shared_pointer const & transport, epics::pvData::int8 version, epics::pvData::int8 command, - std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer); - }; - /****************************************************************************************/ /** * Search channel request handler. diff --git a/testApp/remote/testCodec.cpp b/testApp/remote/testCodec.cpp index 52b0d49..f39846a 100644 --- a/testApp/remote/testCodec.cpp +++ b/testApp/remote/testCodec.cpp @@ -352,7 +352,7 @@ namespace epics { bool verify(epics::pvData::int32 timeoutMs) { return true;} - void verified() {} + void verified(epics::pvData::Status const &) {} void aliveNotification() {} From aea156ebbb3f8ffaa0eb62c2c9a4cde84b31c1da Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 9 Jun 2014 21:32:20 +0200 Subject: [PATCH 30/32] channelList --- pvAccessApp/ca/caProvider.cpp | 13 ++ pvAccessApp/ca/caProvider.h | 2 + pvAccessApp/client/pvAccess.h | 26 +++ .../remoteClient/clientContextImpl.cpp | 13 ++ pvAccessApp/rpcService/rpcServer.cpp | 29 +++- pvAccessApp/rpcService/rpcServer.h | 4 + pvAccessApp/server/responseHandlers.cpp | 164 +++++++++++++++++- pvAccessApp/server/responseHandlers.h | 5 +- testApp/remote/testServer.cpp | 19 ++ testApp/remote/testServerContext.cpp | 8 + 10 files changed, 273 insertions(+), 10 deletions(-) diff --git a/pvAccessApp/ca/caProvider.cpp b/pvAccessApp/ca/caProvider.cpp index 3b4e9f1..87d0617 100644 --- a/pvAccessApp/ca/caProvider.cpp +++ b/pvAccessApp/ca/caProvider.cpp @@ -57,6 +57,19 @@ ChannelFind::shared_pointer CAChannelProvider::channelFind( return nullChannelFind; } +ChannelFind::shared_pointer CAChannelProvider::channelList( + ChannelListRequester::shared_pointer const & channelListRequester) +{ + if (!channelListRequester.get()) + throw std::runtime_error("null requester"); + + Status errorStatus(Status::STATUSTYPE_ERROR, "not implemented"); + ChannelFind::shared_pointer nullChannelFind; + std::set none; + EXCEPTION_GUARD(channelListRequester->channelListResult(errorStatus, nullChannelFind, none, false)); + return nullChannelFind; +} + Channel::shared_pointer CAChannelProvider::createChannel( epics::pvData::String const & channelName, ChannelRequester::shared_pointer const & channelRequester, diff --git a/pvAccessApp/ca/caProvider.h b/pvAccessApp/ca/caProvider.h index 5eb904c..a40afd7 100644 --- a/pvAccessApp/ca/caProvider.h +++ b/pvAccessApp/ca/caProvider.h @@ -35,6 +35,8 @@ public: epics::pvData::String const & channelName, ChannelFindRequester::shared_pointer const & channelFindRequester); + virtual ChannelFind::shared_pointer channelList( + ChannelListRequester::shared_pointer const & channelListRequester); virtual Channel::shared_pointer createChannel( epics::pvData::String const & channelName, diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index bb4295b..c2927d2 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -8,6 +8,7 @@ #define PVACCESS_H #include +#include #ifdef epicsExportSharedSymbols # define pvAccessEpicsExportSharedSymbols @@ -268,6 +269,24 @@ namespace pvAccess { bool wasFound) = 0; }; + /** + * + */ + class epicsShareClass ChannelListRequester { + public: + POINTER_DEFINITIONS(ChannelListRequester); + + virtual ~ChannelListRequester() {}; + + /** + * @param status Completion status. + */ + virtual void channelListResult( + const epics::pvData::Status& status, + ChannelFind::shared_pointer const & channelFind, + std::set const & channelNames, + bool hasDynamic) = 0; + }; /** * Request to get data from a channel. @@ -826,6 +845,13 @@ namespace pvAccess { virtual ChannelFind::shared_pointer channelFind(epics::pvData::String const & channelName, ChannelFindRequester::shared_pointer const & channelFindRequester) = 0; + /** + * Find channels. + * @param channelFindRequester The epics::pvData::Requester. + * @return An interface for the find. + */ + virtual ChannelFind::shared_pointer channelList(ChannelListRequester::shared_pointer const & channelListRequester) = 0; + /** * Create a channel. * @param channelName The name of the channel. diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index 1866185..40eedcf 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -3015,6 +3015,19 @@ namespace epics { return nullChannelFind; } + virtual ChannelFind::shared_pointer channelList( + ChannelListRequester::shared_pointer const & channelListRequester) + { + if (!channelListRequester.get()) + throw std::runtime_error("null requester"); + + Status errorStatus(Status::STATUSTYPE_ERROR, "not implemented"); + ChannelFind::shared_pointer nullChannelFind; + std::set none; + EXCEPTION_GUARD(channelListRequester->channelListResult(errorStatus, nullChannelFind, none, false)); + return nullChannelFind; + } + virtual Channel::shared_pointer createChannel( epics::pvData::String const & channelName, ChannelRequester::shared_pointer const & channelRequester, diff --git a/pvAccessApp/rpcService/rpcServer.cpp b/pvAccessApp/rpcService/rpcServer.cpp index ebc5487..0e362f2 100644 --- a/pvAccessApp/rpcService/rpcServer.cpp +++ b/pvAccessApp/rpcService/rpcServer.cpp @@ -316,6 +316,13 @@ public: Status RPCChannel::notSupportedStatus(Status::STATUSTYPE_ERROR, "only channelRPC requests are supported by this channel"); Status RPCChannel::destroyedStatus(Status::STATUSTYPE_ERROR, "channel destroyed"); +Channel::shared_pointer createRPCChannel(ChannelProvider::shared_pointer const & provider, + epics::pvData::String const & channelName, + ChannelRequester::shared_pointer const & channelRequester, + RPCService::shared_pointer const & rpcService) +{ + return Channel::shared_pointer(new RPCChannel(provider, channelName, channelRequester, rpcService)); +} class RPCChannelProvider : @@ -362,7 +369,27 @@ public: } - virtual Channel::shared_pointer createChannel( + virtual ChannelFind::shared_pointer channelList( + ChannelListRequester::shared_pointer const & channelListRequester) + { + if (!channelListRequester.get()) + throw std::runtime_error("null requester"); + + std::set channelNames; + { + Lock guard(m_mutex); + for (RPCServiceMap::const_iterator iter = m_services.begin(); + iter != m_services.end(); + iter++) + channelNames.insert(iter->first); + } + + ChannelFind::shared_pointer thisPtr(shared_from_this()); + channelListRequester->channelListResult(Status::Ok, thisPtr, channelNames, false); + return thisPtr; + } + + virtual Channel::shared_pointer createChannel( epics::pvData::String const & channelName, ChannelRequester::shared_pointer const & channelRequester, short /*priority*/) diff --git a/pvAccessApp/rpcService/rpcServer.h b/pvAccessApp/rpcService/rpcServer.h index fc102e2..8ff7995 100644 --- a/pvAccessApp/rpcService/rpcServer.h +++ b/pvAccessApp/rpcService/rpcServer.h @@ -64,6 +64,10 @@ class epicsShareClass RPCServer : }; +epicsShareExtern Channel::shared_pointer createRPCChannel(ChannelProvider::shared_pointer const & provider, + epics::pvData::String const & channelName, + ChannelRequester::shared_pointer const & channelRequester, + RPCService::shared_pointer const & rpcService); }} diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index 8595637..261dbd4 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -18,6 +18,7 @@ #include #include +#include using std::ostringstream; using std::hex; @@ -379,6 +380,145 @@ void ServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendContr } /****************************************************************************************/ + +class ChannelListRequesterImpl : + public ChannelListRequester +{ +public: + POINTER_DEFINITIONS(ChannelListRequesterImpl); + + std::set channelNames; + Status status; + + virtual void channelListResult( + const epics::pvData::Status& status, + ChannelFind::shared_pointer const & channelFind, + std::set const & channelNames, + bool hasDynamic) + { + epics::pvData::Lock lock(_waitMutex); + + this->status = status; + this->channelNames = channelNames; + + _waitEvent.signal(); + } + + bool waitForCompletion(int32 timeoutSec) { + return _waitEvent.wait(timeoutSec); + } + +private: + epics::pvData::Mutex _waitMutex; + epics::pvData::Event _waitEvent; + +}; + +// TODO move out to a separate class +class ServerRPCService : public RPCService { + +private: + static int32 TIMEOUT_SEC; + + static Structure::const_shared_pointer helpStructure; + static Structure::const_shared_pointer channelListStructure; + + static std::string helpString; + + ServerContextImpl::shared_pointer m_serverContext; + +public: + + ServerRPCService(ServerContextImpl::shared_pointer const & context) : + m_serverContext(context) + { + } + + virtual epics::pvData::PVStructure::shared_pointer request( + epics::pvData::PVStructure::shared_pointer const & arguments + ) throw (RPCRequestException) + { + // NTURI support + PVStructure::shared_pointer args( + (arguments->getStructure()->getID() == "uri:ev4:nt/2012/pwd:NTURI") ? + arguments->getStructureField("query") : + arguments + ); + + // help support + if (args->getSubField("help")) + { + PVStructure::shared_pointer help = getPVDataCreate()->createPVStructure(helpStructure); + help->getSubField("value")->put(helpString); + return help; + } + + PVString::shared_pointer opField = args->getSubField("op"); + if (!opField) + throw RPCRequestException(Status::STATUSTYPE_ERROR, "unspecified 'string op' field"); + + String op = opField->get(); + if (op == "channels") + { + ChannelListRequesterImpl::shared_pointer listListener(new ChannelListRequesterImpl()); + m_serverContext->getChannelProviders()[0]->channelList(listListener); // TODO multiple channel providers !!!! + if (!listListener->waitForCompletion(TIMEOUT_SEC)) + throw RPCRequestException(Status::STATUSTYPE_ERROR, "failed to fetch channel list due to timeout"); + + Status& status = listListener->status; + if (!status.isSuccess()) + { + String errorMessage = "failed to fetch channel list: " + status.getMessage(); + if (!status.getStackDump().empty()) + errorMessage += "\n" + status.getStackDump(); + throw RPCRequestException(Status::STATUSTYPE_ERROR, errorMessage); + } + + std::set& channelNames = listListener->channelNames; + + PVStructure::shared_pointer result = + getPVDataCreate()->createPVStructure(channelListStructure); + PVStringArray::shared_pointer pvArray = result->getSubField("value"); + PVStringArray::svector newdata(channelNames.size()); + size_t i = 0; + for (std::set::const_iterator iter = channelNames.begin(); + iter != channelNames.end(); + iter++) + newdata[i++] = *iter; + pvArray->replace(freeze(newdata)); + + return result; + } + else + throw RPCRequestException(Status::STATUSTYPE_ERROR, "unsupported operation '" + op + "'."); + } +}; + +int32 ServerRPCService::TIMEOUT_SEC = 3; +Structure::const_shared_pointer ServerRPCService::helpStructure = + getFieldCreate()->createFieldBuilder()-> + setId("uri:ev4:nt/2012/pwd:NTScalar")-> + add("value", pvString)-> + createStructure(); + +Structure::const_shared_pointer ServerRPCService::channelListStructure = + getFieldCreate()->createFieldBuilder()-> + setId("uri:ev4:nt/2012/pwd:NTScalarArray")-> + addArray("value", pvString)-> + createStructure(); + +std::string ServerRPCService::helpString = + "pvAccess server RPC service.\n" + "arguments:\n" + "\tstring op\toperation to execute\n" + "\n" + "\toperations:\n" + "\t\tchannels\treturns a list of 'static' channels the server can provide\n" + "\t\t\t (no arguments)\n" + "\n"; + +epics::pvData::String ServerCreateChannelHandler::SERVER_CHANNEL_NAME = "server"; + void ServerCreateChannelHandler::handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer const & transport, int8 version, int8 command, size_t payloadSize, ByteBuffer* payloadBuffer) @@ -414,14 +554,22 @@ void ServerCreateChannelHandler::handleResponse(osiSockAddr* responseFrom, return; } - // TODO !!! - //ServerChannelRequesterImpl::create(_providers[0], transport, channelName, cid); - - - if (_providers.size() == 1) - ServerChannelRequesterImpl::create(_providers[0], transport, channelName, cid); - else - ServerChannelRequesterImpl::create(ServerSearchHandler::s_channelNameToProvider[channelName].lock(), transport, channelName, cid); // TODO !!!! + if (channelName == SERVER_CHANNEL_NAME) + { + // TODO singleton!!! + ServerRPCService::shared_pointer serverRPCService(new ServerRPCService(_context)); + + ChannelRequester::shared_pointer cr(new ServerChannelRequesterImpl(transport, channelName, cid)); + Channel::shared_pointer serverChannel = createRPCChannel(ChannelProvider::shared_pointer(), channelName, cr, serverRPCService); + cr->channelCreated(Status::Ok, serverChannel); + } + else + { + if (_providers.size() == 1) + ServerChannelRequesterImpl::create(_providers[0], transport, channelName, cid); + else + ServerChannelRequesterImpl::create(ServerSearchHandler::s_channelNameToProvider[channelName].lock(), transport, channelName, cid); // TODO !!!! + } } void ServerCreateChannelHandler::disconnect(Transport::shared_pointer const & transport) diff --git a/pvAccessApp/server/responseHandlers.h b/pvAccessApp/server/responseHandlers.h index 552c0c4..f708102 100644 --- a/pvAccessApp/server/responseHandlers.h +++ b/pvAccessApp/server/responseHandlers.h @@ -206,6 +206,8 @@ namespace pvAccess { std::size_t payloadSize, epics::pvData::ByteBuffer* payloadBuffer); private: + static epics::pvData::String SERVER_CHANNEL_NAME; + void disconnect(Transport::shared_pointer const & transport); std::vector _providers; }; @@ -215,13 +217,14 @@ namespace pvAccess { public TransportSender, public std::tr1::enable_shared_from_this { + friend class ServerCreateChannelHandler; public: typedef std::tr1::shared_ptr shared_pointer; typedef std::tr1::shared_ptr const_shared_pointer; protected: ServerChannelRequesterImpl(Transport::shared_pointer const & transport, const epics::pvData::String channelName, const pvAccessID cid); public: - virtual ~ServerChannelRequesterImpl() {} + virtual ~ServerChannelRequesterImpl() {} static ChannelRequester::shared_pointer create(ChannelProvider::shared_pointer const & provider, Transport::shared_pointer const & transport, const epics::pvData::String channelName, const pvAccessID cid); void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel); void channelStateChange(Channel::shared_pointer const & c, const Channel::ConnectionState isConnected); diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index e4970ac..4669bab 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -2626,6 +2626,25 @@ public: return m_mockChannelFind; } + virtual ChannelFind::shared_pointer channelList( + ChannelListRequester::shared_pointer const & channelListRequester) + { + if (!channelListRequester.get()) + throw std::runtime_error("null requester"); + + // NOTE: this adds only active channels, not all (especially RPC ones) + std::set channelNames; + { + Lock guard(structureStoreMutex); + for (map::const_iterator iter = structureStore.begin(); + iter != structureStore.end(); + iter++) + channelNames.insert(iter->first); + } + channelListRequester->channelListResult(Status::Ok, m_mockChannelFind, channelNames, true); + return m_mockChannelFind; + } + virtual Channel::shared_pointer createChannel( epics::pvData::String const & channelName, ChannelRequester::shared_pointer const & channelRequester, diff --git a/testApp/remote/testServerContext.cpp b/testApp/remote/testServerContext.cpp index 2c41e68..a672e28 100644 --- a/testApp/remote/testServerContext.cpp +++ b/testApp/remote/testServerContext.cpp @@ -24,6 +24,14 @@ public: return nullCF; } + ChannelFind::shared_pointer channelList(ChannelListRequester::shared_pointer const & channelListRequester) + { + ChannelFind::shared_pointer nullCF; + std::set none; + channelListRequester->channelListResult(Status::Ok, nullCF, none, false); + return nullCF; + } + Channel::shared_pointer createChannel( epics::pvData::String const & channelName, ChannelRequester::shared_pointer const & channelRequester, From 4e62a7d4df1e467d2a7b499e727a444f300dbabd Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 9 Jun 2014 22:13:48 +0200 Subject: [PATCH 31/32] channelList using svector --- pvAccessApp/ca/caProvider.cpp | 2 +- pvAccessApp/client/pvAccess.h | 3 +-- pvAccessApp/remoteClient/clientContextImpl.cpp | 2 +- pvAccessApp/rpcService/rpcServer.cpp | 7 ++++--- pvAccessApp/server/responseHandlers.cpp | 14 +++----------- testApp/remote/testServer.cpp | 7 ++++--- testApp/remote/testServerContext.cpp | 2 +- 7 files changed, 15 insertions(+), 22 deletions(-) diff --git a/pvAccessApp/ca/caProvider.cpp b/pvAccessApp/ca/caProvider.cpp index 87d0617..0de7be2 100644 --- a/pvAccessApp/ca/caProvider.cpp +++ b/pvAccessApp/ca/caProvider.cpp @@ -65,7 +65,7 @@ ChannelFind::shared_pointer CAChannelProvider::channelList( Status errorStatus(Status::STATUSTYPE_ERROR, "not implemented"); ChannelFind::shared_pointer nullChannelFind; - std::set none; + PVStringArray::const_svector none; EXCEPTION_GUARD(channelListRequester->channelListResult(errorStatus, nullChannelFind, none, false)); return nullChannelFind; } diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index c2927d2..1b1ad1c 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -8,7 +8,6 @@ #define PVACCESS_H #include -#include #ifdef epicsExportSharedSymbols # define pvAccessEpicsExportSharedSymbols @@ -284,7 +283,7 @@ namespace pvAccess { virtual void channelListResult( const epics::pvData::Status& status, ChannelFind::shared_pointer const & channelFind, - std::set const & channelNames, + epics::pvData::PVStringArray::const_svector const & channelNames, bool hasDynamic) = 0; }; diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index 40eedcf..2005ea6 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -3023,7 +3023,7 @@ namespace epics { Status errorStatus(Status::STATUSTYPE_ERROR, "not implemented"); ChannelFind::shared_pointer nullChannelFind; - std::set none; + PVStringArray::const_svector none; EXCEPTION_GUARD(channelListRequester->channelListResult(errorStatus, nullChannelFind, none, false)); return nullChannelFind; } diff --git a/pvAccessApp/rpcService/rpcServer.cpp b/pvAccessApp/rpcService/rpcServer.cpp index 0e362f2..29b3132 100644 --- a/pvAccessApp/rpcService/rpcServer.cpp +++ b/pvAccessApp/rpcService/rpcServer.cpp @@ -375,17 +375,18 @@ public: if (!channelListRequester.get()) throw std::runtime_error("null requester"); - std::set channelNames; + PVStringArray::svector channelNames; { Lock guard(m_mutex); + channelNames.reserve(m_services.size()); for (RPCServiceMap::const_iterator iter = m_services.begin(); iter != m_services.end(); iter++) - channelNames.insert(iter->first); + channelNames.push_back(iter->first); } ChannelFind::shared_pointer thisPtr(shared_from_this()); - channelListRequester->channelListResult(Status::Ok, thisPtr, channelNames, false); + channelListRequester->channelListResult(Status::Ok, thisPtr, freeze(channelNames), false); return thisPtr; } diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index 261dbd4..736ad27 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -387,13 +387,13 @@ class ChannelListRequesterImpl : public: POINTER_DEFINITIONS(ChannelListRequesterImpl); - std::set channelNames; + PVStringArray::const_svector channelNames; Status status; virtual void channelListResult( const epics::pvData::Status& status, ChannelFind::shared_pointer const & channelFind, - std::set const & channelNames, + PVStringArray::const_svector const & channelNames, bool hasDynamic) { epics::pvData::Lock lock(_waitMutex); @@ -474,18 +474,10 @@ public: throw RPCRequestException(Status::STATUSTYPE_ERROR, errorMessage); } - std::set& channelNames = listListener->channelNames; - PVStructure::shared_pointer result = getPVDataCreate()->createPVStructure(channelListStructure); PVStringArray::shared_pointer pvArray = result->getSubField("value"); - PVStringArray::svector newdata(channelNames.size()); - size_t i = 0; - for (std::set::const_iterator iter = channelNames.begin(); - iter != channelNames.end(); - iter++) - newdata[i++] = *iter; - pvArray->replace(freeze(newdata)); + pvArray->replace(listListener->channelNames); return result; } diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index 4669bab..ff50740 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -2633,15 +2633,16 @@ public: throw std::runtime_error("null requester"); // NOTE: this adds only active channels, not all (especially RPC ones) - std::set channelNames; + PVStringArray::svector channelNames; { Lock guard(structureStoreMutex); + channelNames.reserve(structureStore.size()); for (map::const_iterator iter = structureStore.begin(); iter != structureStore.end(); iter++) - channelNames.insert(iter->first); + channelNames.push_back(iter->first); } - channelListRequester->channelListResult(Status::Ok, m_mockChannelFind, channelNames, true); + channelListRequester->channelListResult(Status::Ok, m_mockChannelFind, freeze(channelNames), true); return m_mockChannelFind; } diff --git a/testApp/remote/testServerContext.cpp b/testApp/remote/testServerContext.cpp index a672e28..a8f25d1 100644 --- a/testApp/remote/testServerContext.cpp +++ b/testApp/remote/testServerContext.cpp @@ -27,7 +27,7 @@ public: ChannelFind::shared_pointer channelList(ChannelListRequester::shared_pointer const & channelListRequester) { ChannelFind::shared_pointer nullCF; - std::set none; + PVStringArray::const_svector none; channelListRequester->channelListResult(Status::Ok, nullCF, none, false); return nullCF; } From c7bf9f6d6772df1bbb61830af4dfbc7eb372bb11 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 9 Jun 2014 23:56:58 +0200 Subject: [PATCH 32/32] flow: Closed 'changesAfter3_0_2'.