From 4a7f057af1bb23d75991993394f873df9ffb9b25 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Wed, 16 Dec 2015 14:45:20 +0100 Subject: [PATCH] server channel destroy notification to the client --- src/remoteClient/clientContextImpl.cpp | 43 ++++++++++++++++++++++++-- src/remoteClient/clientContextImpl.h | 1 + src/server/responseHandlers.cpp | 26 ++++++++++++++-- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 15e8e31..135d371 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -3165,6 +3165,33 @@ namespace epics { }; + class DestroyChannelHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + public: + DestroyChannelHandler(ClientContextImpl::shared_pointer const & context) : + AbstractClientResponseHandler(context, "Destroy channel") + { + } + + virtual ~DestroyChannelHandler() { + } + + 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); + + transport->ensureData(4); + pvAccessID cid = payloadBuffer->getInt(); + /*pvAccessID sid =*/ payloadBuffer->getInt(); + + // TODO optimize + ChannelImpl::shared_pointer channel = static_pointer_cast(_context.lock()->getChannel(cid)); + if (channel.get()) + channel->channelDestroyedOnServer(); + } + }; + /** * PVA response handler - main handler which dispatches responses to appripriate handlers. @@ -3200,7 +3227,7 @@ namespace epics { m_handlerTable[CMD_AUTHNZ].reset(new AuthNZHandler(context.get())); /* 5 */ m_handlerTable[CMD_ACL_CHANGE].reset(new NoopResponse(context, "Access rights change")); /* 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_DESTROY_CHANNEL].reset(new DestroyChannelHandler(context)); /* 8 */ 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 */ @@ -3859,6 +3886,16 @@ namespace epics { this->initiateSearch(); } + + void channelDestroyedOnServer() { + if (isConnected()) + { + disconnect(true, false); + + // should be called without any lock hold + reportChannelStateChange(); + } + } #define STATIC_SEARCH_BASE_DELAY_SEC 5 #define STATIC_SEARCH_MAX_MULTIPLIER 10 @@ -4059,7 +4096,7 @@ namespace epics { if (issueCreateMessage) { - control->startMessage((int8)7, 2+4); + control->startMessage((int8)CMD_CREATE_CHANNEL, 2+4); // count buffer->putShort((int16)1); @@ -4072,7 +4109,7 @@ namespace epics { } else { - control->startMessage((int8)8, 4+4); + control->startMessage((int8)CMD_DESTROY_CHANNEL, 4+4); // SID m_channelMutex.lock(); pvAccessID sid = m_serverChannelID; diff --git a/src/remoteClient/clientContextImpl.h b/src/remoteClient/clientContextImpl.h index 36c9a38..06e7c02 100644 --- a/src/remoteClient/clientContextImpl.h +++ b/src/remoteClient/clientContextImpl.h @@ -48,6 +48,7 @@ namespace epics { virtual void connectionCompleted(pvAccessID sid/*, rights*/) = 0; virtual void createChannelFailed() = 0; virtual std::tr1::shared_ptr getContext() = 0; + virtual void channelDestroyedOnServer() = 0; virtual pvAccessID getServerChannelID() = 0; virtual void registerResponseRequest(ResponseRequest::shared_pointer const & responseRequest) = 0; diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 8cf4a22..c82f247 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -843,9 +843,31 @@ void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel::s void ServerChannelRequesterImpl::channelStateChange(Channel::shared_pointer const & /*channel*/, const Channel::ConnectionState /*isConnected*/) { - // TODO should we notify remote side? + if(Transport::shared_pointer transport = _transport.lock()) + { + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); + if (!casTransport) + return; - // YES :) + ServerChannelImpl::shared_pointer channel; + { + Lock guard(_mutex); + channel= dynamic_pointer_cast(_serverChannel.lock()); + } + + if (!channel) + return; + + // destroy + channel->destroy(); + + // .. and unregister + casTransport->unregisterChannel(channel->getSID()); + + // send response back + TransportSender::shared_pointer sr(new ServerDestroyChannelHandlerTransportSender(channel->getCID(), channel->getSID())); + transport->enqueueSendRequest(sr); + } } string ServerChannelRequesterImpl::getRequesterName()