2051 lines
65 KiB
C++
2051 lines
65 KiB
C++
/**
|
|
* 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 <pv/responseHandlers.h>
|
|
#include <pv/remote.h>
|
|
#include <pv/hexDump.h>
|
|
|
|
#include <pv/byteBuffer.h>
|
|
|
|
#include <osiSock.h>
|
|
#include <pv/logger.h>
|
|
|
|
#include <sstream>
|
|
|
|
using std::ostringstream;
|
|
using std::hex;
|
|
|
|
using std::tr1::dynamic_pointer_cast;
|
|
using std::tr1::static_pointer_cast;
|
|
|
|
using namespace epics::pvData;
|
|
|
|
namespace epics {
|
|
namespace pvAccess {
|
|
|
|
void ServerBadResponse::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);
|
|
|
|
char ipAddrStr[48];
|
|
ipAddrToDottedIP(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr));
|
|
|
|
LOG(logLevelInfo,
|
|
"Undecipherable message (bad response type %d) from %s.",
|
|
command, ipAddrStr);
|
|
|
|
}
|
|
|
|
ServerResponseHandler::ServerResponseHandler(ServerContextImpl::shared_pointer const & context)
|
|
{
|
|
ResponseHandler::shared_pointer badResponse(new ServerBadResponse(context));
|
|
|
|
m_handlerTable.resize(CMD_RPC+1);
|
|
|
|
m_handlerTable[CMD_BEACON].reset(new ServerNoopResponse(context, "Beacon")); /* 0 */
|
|
m_handlerTable[CMD_CONNECTION_VALIDATION].reset(new ServerConnectionValidationHandler(context)); /* 1 */
|
|
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_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_GET].reset(new ServerGetHandler(context)); /* 10 - get response */
|
|
m_handlerTable[CMD_PUT].reset(new ServerPutHandler(context)); /* 11 - put response */
|
|
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_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 */
|
|
}
|
|
|
|
void ServerResponseHandler::handleResponse(osiSockAddr* responseFrom,
|
|
Transport::shared_pointer const & transport, int8 version, int8 command,
|
|
size_t payloadSize, ByteBuffer* payloadBuffer)
|
|
{
|
|
if(command<0||command>=(int8)m_handlerTable.size())
|
|
{
|
|
LOG(logLevelDebug,
|
|
"Invalid (or unsupported) command: %x.", (0xFF&command));
|
|
|
|
// TODO remove debug output
|
|
std::ostringstream name;
|
|
name<<"Invalid CA header "<<hex<<(int)(0xFF&command);
|
|
name<<", its payload buffer";
|
|
|
|
hexDump(name.str(), (const int8*)payloadBuffer->getArray(),
|
|
payloadBuffer->getPosition(), payloadSize);
|
|
return;
|
|
}
|
|
|
|
// delegate
|
|
m_handlerTable[command]->handleResponse(responseFrom, transport,
|
|
version, command, payloadSize, payloadBuffer);
|
|
}
|
|
|
|
void ServerConnectionValidationHandler::handleResponse(
|
|
osiSockAddr* responseFrom, Transport::shared_pointer const & transport, int8 version,
|
|
int8 command, size_t payloadSize,
|
|
ByteBuffer* payloadBuffer)
|
|
{
|
|
AbstractServerResponseHandler::handleResponse(responseFrom,
|
|
transport, version, command, payloadSize, payloadBuffer);
|
|
|
|
transport->ensureData(2*sizeof(int32)+sizeof(int16));
|
|
transport->setRemoteTransportReceiveBufferSize(
|
|
payloadBuffer->getInt());
|
|
transport->setRemoteTransportSocketReceiveBufferSize(
|
|
payloadBuffer->getInt());
|
|
transport->setRemoteMinorRevision(version);
|
|
// TODO support priority !!!
|
|
//transport.setPriority(payloadBuffer.getShort());
|
|
}
|
|
|
|
void ServerEchoHandler::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);
|
|
|
|
// send back
|
|
TransportSender::shared_pointer echoReply(new EchoTransportSender(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");
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
ServerSearchHandler::ServerSearchHandler(ServerContextImpl::shared_pointer const & context) :
|
|
AbstractServerResponseHandler(context, "Search request"), _providers(context->getChannelProviders())
|
|
{
|
|
}
|
|
|
|
ServerSearchHandler::~ServerSearchHandler()
|
|
{
|
|
}
|
|
|
|
void ServerSearchHandler::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);
|
|
|
|
transport->ensureData((sizeof(int32)+sizeof(int16))/sizeof(int8)+1);
|
|
const int32 searchSequenceId = payloadBuffer->getInt();
|
|
const int8 qosCode = payloadBuffer->getByte();
|
|
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 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);
|
|
}
|
|
}
|
|
|
|
ServerChannelFindRequesterImpl::ServerChannelFindRequesterImpl(ServerContextImpl::shared_pointer const & context,
|
|
int32 expectedResponseCount) :
|
|
_sendTo(NULL),
|
|
_wasFound(false),
|
|
_context(context),
|
|
_expectedResponseCount(expectedResponseCount),
|
|
_responseCount(0)
|
|
{}
|
|
|
|
void ServerChannelFindRequesterImpl::clear()
|
|
{
|
|
Lock guard(_mutex);
|
|
_sendTo = NULL;
|
|
_wasFound = false;
|
|
_responseCount = 0;
|
|
}
|
|
|
|
ServerChannelFindRequesterImpl* ServerChannelFindRequesterImpl::set(String name, int32 searchSequenceId, int32 cid, osiSockAddr* sendTo, bool responseRequired)
|
|
{
|
|
Lock guard(_mutex);
|
|
_name = name;
|
|
_searchSequenceId = searchSequenceId;
|
|
_cid = cid;
|
|
_sendTo = sendTo;
|
|
_responseRequired = responseRequired;
|
|
return this;
|
|
}
|
|
|
|
std::map<String, std::tr1::weak_ptr<ChannelProvider> > ServerSearchHandler::s_channelNameToProvider;
|
|
|
|
void ServerChannelFindRequesterImpl::channelFindResult(const Status& status, ChannelFind::shared_pointer const & channelFind, bool wasFound)
|
|
{
|
|
// TODO status
|
|
Lock guard(_mutex);
|
|
|
|
_responseCount++;
|
|
if (_responseCount > _expectedResponseCount)
|
|
{
|
|
if ((_responseCount+1) == _expectedResponseCount)
|
|
{
|
|
LOG(logLevelDebug,"[ServerChannelFindRequesterImpl::channelFindResult] More responses received than expected fpr channel '%s'!", _name.c_str());
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (wasFound && _wasFound)
|
|
{
|
|
LOG(logLevelDebug,"[ServerChannelFindRequesterImpl::channelFindResult] Channel '%s' is hosted by different channel providers!", _name.c_str());
|
|
return;
|
|
}
|
|
|
|
if (wasFound || (_responseRequired && (_responseCount == _expectedResponseCount)))
|
|
{
|
|
if (wasFound && _expectedResponseCount > 1)
|
|
{
|
|
ServerSearchHandler::s_channelNameToProvider[_name] = channelFind->getChannelProvider();
|
|
}
|
|
|
|
_wasFound = wasFound;
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_context->getBroadcastTransport()->enqueueSendRequest(thisSender);
|
|
}
|
|
}
|
|
|
|
void ServerChannelFindRequesterImpl::lock()
|
|
{
|
|
// noop
|
|
}
|
|
|
|
void ServerChannelFindRequesterImpl::unlock()
|
|
{
|
|
// noop
|
|
}
|
|
|
|
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));
|
|
|
|
Lock guard(_mutex);
|
|
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);
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
void ServerCreateChannelHandler::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);
|
|
|
|
// TODO for not only one request at the time is supported, i.e. dataCount == 1
|
|
transport->ensureData((sizeof(int32)+sizeof(int16))/sizeof(int8));
|
|
const int16 count = payloadBuffer->getShort();
|
|
if (count != 1)
|
|
{
|
|
THROW_BASE_EXCEPTION("only 1 supported for now");
|
|
}
|
|
const pvAccessID cid = payloadBuffer->getInt();
|
|
|
|
String channelName = SerializeHelper::deserializeString(payloadBuffer, transport.get());
|
|
if (channelName.size() == 0)
|
|
{
|
|
|
|
char host[100];
|
|
sockAddrToA(&transport->getRemoteAddress()->sa,host,100);
|
|
LOG(logLevelDebug,"Zero length channel name, disconnecting client: %s", host);
|
|
disconnect(transport);
|
|
return;
|
|
}
|
|
else if (channelName.size() > UNREASONABLE_CHANNEL_NAME_LENGTH)
|
|
{
|
|
char host[100];
|
|
sockAddrToA(&transport->getRemoteAddress()->sa,host,100);
|
|
LOG(logLevelDebug,"Unreasonable channel name length, disconnecting client: %s", host);
|
|
disconnect(transport);
|
|
return;
|
|
}
|
|
|
|
// TODO !!!
|
|
//ServerChannelRequesterImpl::create(_providers.at(0), transport, channelName, cid);
|
|
|
|
|
|
if (_providers.size() == 1)
|
|
ServerChannelRequesterImpl::create(_providers.at(0), transport, channelName, cid);
|
|
else
|
|
ServerChannelRequesterImpl::create(ServerSearchHandler::s_channelNameToProvider[channelName].lock(), transport, channelName, cid); // TODO !!!!
|
|
}
|
|
|
|
void ServerCreateChannelHandler::disconnect(Transport::shared_pointer const & transport)
|
|
{
|
|
transport->close(true);
|
|
}
|
|
|
|
ServerChannelRequesterImpl::ServerChannelRequesterImpl(Transport::shared_pointer const & transport,
|
|
const String channelName, const pvAccessID cid) :
|
|
_serverChannel(),
|
|
_transport(transport),
|
|
_channelName(channelName),
|
|
_cid(cid),
|
|
_status(),
|
|
_mutex()
|
|
{
|
|
}
|
|
|
|
ChannelRequester::shared_pointer ServerChannelRequesterImpl::create(
|
|
ChannelProvider::shared_pointer const & provider, Transport::shared_pointer const & transport,
|
|
const String channelName, const pvAccessID cid)
|
|
{
|
|
ChannelRequester::shared_pointer cr(new ServerChannelRequesterImpl(transport, channelName, cid));
|
|
// TODO exception guard and report error back
|
|
provider->createChannel(channelName, cr, transport->getPriority());
|
|
return cr;
|
|
}
|
|
|
|
void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel::shared_pointer const & channel)
|
|
{
|
|
if(Transport::shared_pointer transport = _transport.lock())
|
|
{
|
|
ServerChannel::shared_pointer serverChannel;
|
|
try
|
|
{
|
|
if (status.isSuccess())
|
|
{
|
|
// NOTE: we do not explicitly check if transport OK
|
|
ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast<ChannelHostingTransport>(transport);
|
|
if (!casTransport.get())
|
|
THROW_BASE_EXCEPTION("transport is unable to host channels");
|
|
|
|
//
|
|
// create a new channel instance
|
|
//
|
|
pvAccessID sid = casTransport->preallocateChannelSID();
|
|
try
|
|
{
|
|
epics::pvData::PVField::shared_pointer securityToken = casTransport->getSecurityToken();
|
|
serverChannel.reset(new ServerChannelImpl(channel, _cid, sid, securityToken));
|
|
|
|
// ack allocation and register
|
|
casTransport->registerChannel(sid, serverChannel);
|
|
|
|
} catch (...)
|
|
{
|
|
// depreallocate and rethrow
|
|
casTransport->depreallocateChannelSID(sid);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
_serverChannel = serverChannel;
|
|
}
|
|
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
transport->enqueueSendRequest(thisSender);
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
LOG(logLevelDebug, "Exception caught when creating channel: %s", _channelName.c_str());
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = Status(Status::STATUSTYPE_FATAL, "failed to create channel", e.what());
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
transport->enqueueSendRequest(thisSender);
|
|
// TODO make sure that serverChannel gets destroyed
|
|
}
|
|
catch (...)
|
|
{
|
|
LOG(logLevelDebug, "Exception caught when creating channel: %s", _channelName.c_str());
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = Status(Status::STATUSTYPE_FATAL, "failed to create channel");
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
transport->enqueueSendRequest(thisSender);
|
|
// TODO make sure that serverChannel gets destroyed
|
|
}
|
|
}
|
|
}
|
|
|
|
void ServerChannelRequesterImpl::channelStateChange(Channel::shared_pointer const & c, const Channel::ConnectionState isConnected)
|
|
{
|
|
// TODO should we notify remote side?
|
|
}
|
|
|
|
String ServerChannelRequesterImpl::getRequesterName()
|
|
{
|
|
std::stringstream name;
|
|
name << "ServerChannelRequesterImpl/" << _channelName << "[" << _cid << "]";
|
|
return name.str();
|
|
}
|
|
|
|
void ServerChannelRequesterImpl::message(const String message, const MessageType messageType)
|
|
{
|
|
LOG(logLevelDebug, "[%s] %s", getMessageTypeName(messageType).c_str(), message.c_str());
|
|
}
|
|
|
|
void ServerChannelRequesterImpl::lock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelRequesterImpl::unlock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control)
|
|
{
|
|
ServerChannel::shared_pointer serverChannel;
|
|
Status status;
|
|
{
|
|
Lock guard(_mutex);
|
|
serverChannel = _serverChannel.lock();
|
|
status = _status;
|
|
}
|
|
|
|
// error response
|
|
if (serverChannel.get() == NULL)
|
|
{
|
|
createChannelFailedResponse(buffer, control, status);
|
|
}
|
|
// OK
|
|
else if (Transport::shared_pointer transport = _transport.lock())
|
|
{
|
|
ServerChannelImpl::shared_pointer serverChannelImpl = dynamic_pointer_cast<ServerChannelImpl>(serverChannel);
|
|
control->startMessage((int8)CMD_CREATE_CHANNEL, 2*sizeof(int32)/sizeof(int8));
|
|
buffer->putInt(serverChannelImpl->getCID());
|
|
buffer->putInt(serverChannelImpl->getSID());
|
|
transport->getIntrospectionRegistry()->serializeStatus(buffer, control, status);
|
|
}
|
|
}
|
|
|
|
|
|
void ServerChannelRequesterImpl::createChannelFailedResponse(ByteBuffer* buffer, TransportSendControl* control, const Status& status)
|
|
{
|
|
if (Transport::shared_pointer transport = _transport.lock())
|
|
{
|
|
control->startMessage((int8)CMD_CREATE_CHANNEL, 2*sizeof(int32)/sizeof(int8));
|
|
buffer->putInt(_cid);
|
|
buffer->putInt(-1);
|
|
transport->getIntrospectionRegistry()->serializeStatus(buffer, control, status);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
void ServerDestroyChannelHandler::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 OK
|
|
ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast<ChannelHostingTransport>(transport);
|
|
|
|
|
|
transport->ensureData(2*sizeof(int32)/sizeof(int8));
|
|
const pvAccessID sid = payloadBuffer->getInt();
|
|
const pvAccessID cid = payloadBuffer->getInt();
|
|
|
|
// get channel by SID
|
|
ServerChannelImpl::shared_pointer channel = static_pointer_cast<ServerChannelImpl>(casTransport->getChannel(sid));
|
|
if (channel.get() == NULL)
|
|
{
|
|
if (!transport->isClosed())
|
|
{
|
|
char host[100];
|
|
sockAddrToA(&responseFrom->sa,host,100);
|
|
LOG(logLevelDebug, "Trying to destroy a channel that no longer exists (SID: %d, CID %d, client: %s).", sid, cid, host);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// destroy
|
|
channel->destroy();
|
|
|
|
// .. and unregister
|
|
casTransport->unregisterChannel(sid);
|
|
|
|
// send response back
|
|
TransportSender::shared_pointer sr(new ServerDestroyChannelHandlerTransportSender(cid, sid));
|
|
transport->enqueueSendRequest(sr);
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
void ServerGetHandler::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<ChannelHostingTransport>(transport);
|
|
|
|
transport->ensureData(2*sizeof(int32)/sizeof(int8)+1);
|
|
const pvAccessID sid = payloadBuffer->getInt();
|
|
const pvAccessID ioid = payloadBuffer->getInt();
|
|
|
|
// mode
|
|
const int8 qosCode = payloadBuffer->getByte();
|
|
|
|
ServerChannelImpl::shared_pointer channel = static_pointer_cast<ServerChannelImpl>(casTransport->getChannel(sid));
|
|
if (channel.get() == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_GET, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus);
|
|
return;
|
|
}
|
|
|
|
const bool init = (QOS_INIT & qosCode) != 0;
|
|
if (init)
|
|
{
|
|
// pvRequest
|
|
PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get()));
|
|
|
|
// create...
|
|
ServerChannelGetRequesterImpl::create(_context, channel, ioid, transport, pvRequest);
|
|
}
|
|
else
|
|
{
|
|
const bool lastRequest = (QOS_DESTROY & qosCode) != 0;
|
|
|
|
ServerChannelGetRequesterImpl::shared_pointer request = static_pointer_cast<ServerChannelGetRequesterImpl>(channel->getRequest(ioid));
|
|
if (request == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_GET, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus);
|
|
return;
|
|
}
|
|
|
|
if (!request->startRequest(qosCode))
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_GET, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus);
|
|
return;
|
|
}
|
|
|
|
request->getChannelGet()->get(lastRequest);
|
|
}
|
|
}
|
|
|
|
#define INIT_EXCEPTION_GUARD(cmd, code) \
|
|
try { \
|
|
code; \
|
|
} \
|
|
catch (std::exception &e) { \
|
|
Status status(Status::STATUSTYPE_FATAL, e.what()); \
|
|
BaseChannelRequester::sendFailureMessage((int8)cmd, _transport, _ioid, (int8)QOS_INIT, status); \
|
|
destroy(); \
|
|
} \
|
|
catch (...) { \
|
|
Status status(Status::STATUSTYPE_FATAL, "unknown exception caught"); \
|
|
BaseChannelRequester::sendFailureMessage((int8)cmd, _transport, _ioid, (int8)QOS_INIT, status); \
|
|
destroy(); \
|
|
}
|
|
|
|
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()
|
|
|
|
{
|
|
}
|
|
|
|
ChannelGetRequester::shared_pointer ServerChannelGetRequesterImpl::create(ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel, const pvAccessID ioid, Transport::shared_pointer const & transport,
|
|
PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
ChannelGetRequester::shared_pointer thisPointer(new ServerChannelGetRequesterImpl(context, channel, ioid, transport));
|
|
static_cast<ServerChannelGetRequesterImpl*>(thisPointer.get())->activate(pvRequest);
|
|
return thisPointer;
|
|
}
|
|
|
|
void ServerChannelGetRequesterImpl::activate(PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
startRequest(QOS_INIT);
|
|
ChannelGetRequester::shared_pointer thisPointer = shared_from_this();
|
|
Destroyable::shared_pointer thisDestroyable = shared_from_this();
|
|
_channel->registerRequest(_ioid, thisDestroyable);
|
|
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)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_bitSet = bitSet;
|
|
_pvStructure = pvStructure;
|
|
_status = status;
|
|
_channelGet = channelGet;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
|
|
// self-destruction
|
|
if (!status.isSuccess())
|
|
{
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
void ServerChannelGetRequesterImpl::getDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelGetRequesterImpl::destroy()
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_channel->unregisterRequest(_ioid);
|
|
if (_channelGet != NULL)
|
|
{
|
|
_channelGet->destroy();
|
|
}
|
|
}
|
|
// TODO not competely safe for when callig getChannelGet() now
|
|
_channelGet.reset();
|
|
}
|
|
|
|
ChannelGet::shared_pointer ServerChannelGetRequesterImpl::getChannelGet()
|
|
{
|
|
return _channelGet;
|
|
}
|
|
|
|
void ServerChannelGetRequesterImpl::lock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelGetRequesterImpl::unlock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelGetRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control)
|
|
{
|
|
const int32 request = getPendingRequest();
|
|
|
|
control->startMessage((int8)CMD_GET, sizeof(int32)/sizeof(int8) + 1);
|
|
buffer->putInt(_ioid);
|
|
buffer->put((int8)request);
|
|
IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry();
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serializeStatus(buffer, control, _status);
|
|
}
|
|
|
|
if (_status.isSuccess())
|
|
{
|
|
if (request & QOS_INIT)
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serialize(_pvStructure != NULL ? _pvStructure->getField() : FieldConstPtr(), buffer, control);
|
|
|
|
}
|
|
else
|
|
{
|
|
// we locked _mutex above, so _channelGet is valid
|
|
ScopedLock lock(_channelGet);
|
|
|
|
_bitSet->serialize(buffer, control);
|
|
_pvStructure->serialize(buffer, control, _bitSet.get());
|
|
}
|
|
}
|
|
|
|
stopRequest();
|
|
|
|
// lastRequest
|
|
if (request & QOS_DESTROY)
|
|
{
|
|
destroy();
|
|
}
|
|
}
|
|
/****************************************************************************************/
|
|
void ServerPutHandler::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<ChannelHostingTransport>(transport);
|
|
|
|
transport->ensureData(2*sizeof(int32)/sizeof(int8)+1);
|
|
const pvAccessID sid = payloadBuffer->getInt();
|
|
const pvAccessID ioid = payloadBuffer->getInt();
|
|
|
|
// mode
|
|
const int8 qosCode = payloadBuffer->getByte();
|
|
|
|
ServerChannelImpl::shared_pointer channel = static_pointer_cast<ServerChannelImpl>(casTransport->getChannel(sid));
|
|
if (channel == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_PUT, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus);
|
|
return;
|
|
}
|
|
|
|
const bool init = (QOS_INIT & qosCode) != 0;
|
|
if (init)
|
|
{
|
|
// pvRequest
|
|
PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get()));
|
|
|
|
// create...
|
|
ServerChannelPutRequesterImpl::create(_context, channel, ioid, transport, pvRequest);
|
|
}
|
|
else
|
|
{
|
|
const bool lastRequest = (QOS_DESTROY & qosCode) != 0;
|
|
const bool get = (QOS_GET & qosCode) != 0;
|
|
|
|
ServerChannelPutRequesterImpl::shared_pointer request = static_pointer_cast<ServerChannelPutRequesterImpl>(channel->getRequest(ioid));
|
|
if (request == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_PUT, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus);
|
|
return;
|
|
}
|
|
|
|
if (!request->startRequest(qosCode))
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_PUT, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus);
|
|
return;
|
|
}
|
|
|
|
if (get)
|
|
{
|
|
// no destroy w/ get
|
|
request->getChannelPut()->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();
|
|
putBitSet->deserialize(payloadBuffer, transport.get());
|
|
request->getPVStructure()->deserialize(payloadBuffer, transport.get(), putBitSet.get());
|
|
}
|
|
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()
|
|
{
|
|
}
|
|
|
|
ChannelPutRequester::shared_pointer ServerChannelPutRequesterImpl::create(ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport, PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
ChannelPutRequester::shared_pointer thisPointer(new ServerChannelPutRequesterImpl(context, channel, ioid, transport));
|
|
static_cast<ServerChannelPutRequesterImpl*>(thisPointer.get())->activate(pvRequest);
|
|
return thisPointer;
|
|
}
|
|
|
|
void ServerChannelPutRequesterImpl::activate(PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
startRequest(QOS_INIT);
|
|
ChannelPutRequester::shared_pointer thisPointer = shared_from_this();
|
|
Destroyable::shared_pointer thisDestroyable = shared_from_this();
|
|
_channel->registerRequest(_ioid, thisDestroyable);
|
|
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)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_bitSet = bitSet;
|
|
_pvStructure = pvStructure;
|
|
_status = status;
|
|
_channelPut = channelPut;
|
|
}
|
|
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
|
|
// self-destruction
|
|
if (!status.isSuccess())
|
|
{
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
void ServerChannelPutRequesterImpl::putDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelPutRequesterImpl::getDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelPutRequesterImpl::lock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelPutRequesterImpl::unlock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelPutRequesterImpl::destroy()
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_channel->unregisterRequest(_ioid);
|
|
if (_channelPut != NULL)
|
|
{
|
|
_channelPut->destroy();
|
|
}
|
|
}
|
|
// TODO
|
|
_channelPut.reset();
|
|
}
|
|
|
|
ChannelPut::shared_pointer ServerChannelPutRequesterImpl::getChannelPut()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _channelPut;
|
|
}
|
|
|
|
BitSet::shared_pointer ServerChannelPutRequesterImpl::getBitSet()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _bitSet;
|
|
}
|
|
|
|
PVStructure::shared_pointer ServerChannelPutRequesterImpl::getPVStructure()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _pvStructure;
|
|
}
|
|
|
|
void ServerChannelPutRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control)
|
|
{
|
|
const int32 request = getPendingRequest();
|
|
|
|
control->startMessage((int32)CMD_PUT, sizeof(int32)/sizeof(int8) + 1);
|
|
buffer->putInt(_ioid);
|
|
buffer->putByte((int8)request);
|
|
IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry();
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serializeStatus(buffer, control, _status);
|
|
}
|
|
|
|
if (_status.isSuccess())
|
|
{
|
|
if ((QOS_INIT & request) != 0)
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serialize(_pvStructure != NULL ? _pvStructure->getField() : FieldConstPtr(), buffer, control);
|
|
}
|
|
else if ((QOS_GET & request) != 0)
|
|
{
|
|
ScopedLock lock(_channelPut); // _channelPut is valid because we required _mutex above
|
|
_pvStructure->serialize(buffer, control);
|
|
}
|
|
}
|
|
|
|
stopRequest();
|
|
|
|
// lastRequest
|
|
if ((QOS_DESTROY & request) != 0)
|
|
destroy();
|
|
}
|
|
|
|
|
|
/****************************************************************************************/
|
|
void ServerPutGetHandler::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<ChannelHostingTransport>(transport);
|
|
|
|
transport->ensureData(2*sizeof(int32)/sizeof(int8)+1);
|
|
const pvAccessID sid = payloadBuffer->getInt();
|
|
const pvAccessID ioid = payloadBuffer->getInt();
|
|
|
|
// mode
|
|
const int8 qosCode = payloadBuffer->getByte();
|
|
|
|
ServerChannelImpl::shared_pointer channel = static_pointer_cast<ServerChannelImpl>(casTransport->getChannel(sid));
|
|
if (channel == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_PUT_GET, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus);
|
|
return;
|
|
}
|
|
|
|
const bool init = (QOS_INIT & qosCode) != 0;
|
|
if (init)
|
|
{
|
|
// pvRequest
|
|
PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get()));
|
|
|
|
// create...
|
|
ServerChannelPutGetRequesterImpl::create(_context, channel, ioid, transport, pvRequest);
|
|
}
|
|
else
|
|
{
|
|
const bool lastRequest = (QOS_DESTROY & qosCode) != 0;
|
|
const bool getGet = (QOS_GET & qosCode) != 0;
|
|
const bool getPut = (QOS_GET_PUT & qosCode) != 0;
|
|
|
|
ServerChannelPutGetRequesterImpl::shared_pointer request = static_pointer_cast<ServerChannelPutGetRequesterImpl>(channel->getRequest(ioid));
|
|
if (request == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_PUT_GET, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus);
|
|
return;
|
|
}
|
|
|
|
if (!request->startRequest(qosCode))
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_PUT_GET, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus);
|
|
return;
|
|
}
|
|
|
|
if (getGet)
|
|
{
|
|
request->getChannelPutGet()->getGet();
|
|
}
|
|
else if(getPut)
|
|
{
|
|
request->getChannelPutGet()->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
|
|
request->getPVPutStructure()->deserialize(payloadBuffer, transport.get());
|
|
}
|
|
channelPutGet->putGet(lastRequest);
|
|
}
|
|
}
|
|
}
|
|
|
|
ServerChannelPutGetRequesterImpl::ServerChannelPutGetRequesterImpl(ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport):
|
|
BaseChannelRequester(context, channel, ioid, transport), _channelPutGet(), _pvPutStructure(), _pvGetStructure()
|
|
{
|
|
}
|
|
|
|
ChannelPutGetRequester::shared_pointer ServerChannelPutGetRequesterImpl::create(ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport,PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
ChannelPutGetRequester::shared_pointer thisPointer(new ServerChannelPutGetRequesterImpl(context, channel, ioid, transport));
|
|
static_cast<ServerChannelPutGetRequesterImpl*>(thisPointer.get())->activate(pvRequest);
|
|
return thisPointer;
|
|
}
|
|
|
|
void ServerChannelPutGetRequesterImpl::activate(PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
startRequest(QOS_INIT);
|
|
ChannelPutGetRequester::shared_pointer thisPointer = shared_from_this();
|
|
Destroyable::shared_pointer thisDestroyable = shared_from_this();
|
|
_channel->registerRequest(_ioid, thisDestroyable);
|
|
INIT_EXCEPTION_GUARD(CMD_PUT_GET, _channelPutGet = _channel->getChannel()->createChannelPutGet(thisPointer, pvRequest));
|
|
}
|
|
|
|
void ServerChannelPutGetRequesterImpl::channelPutGetConnect(const Status& status, ChannelPutGet::shared_pointer const & channelPutGet,
|
|
PVStructure::shared_pointer const & pvPutStructure, PVStructure::shared_pointer const & pvGetStructure)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_pvPutStructure = pvPutStructure;
|
|
_pvGetStructure = pvGetStructure;
|
|
_status = status;
|
|
_channelPutGet = channelPutGet;
|
|
}
|
|
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
|
|
// self-destruction
|
|
if (!status.isSuccess())
|
|
{
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
void ServerChannelPutGetRequesterImpl::getGetDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelPutGetRequesterImpl::getPutDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelPutGetRequesterImpl::putGetDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelPutGetRequesterImpl::lock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelPutGetRequesterImpl::unlock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelPutGetRequesterImpl::destroy()
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_channel->unregisterRequest(_ioid);
|
|
if (_channelPutGet != NULL)
|
|
{
|
|
_channelPutGet->destroy();
|
|
}
|
|
}
|
|
// TODO
|
|
_channelPutGet.reset();
|
|
}
|
|
|
|
ChannelPutGet::shared_pointer ServerChannelPutGetRequesterImpl::getChannelPutGet()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _channelPutGet;
|
|
}
|
|
|
|
PVStructure::shared_pointer ServerChannelPutGetRequesterImpl::getPVPutStructure()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _pvPutStructure;
|
|
}
|
|
|
|
void ServerChannelPutGetRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control)
|
|
{
|
|
const int32 request = getPendingRequest();
|
|
|
|
control->startMessage((int32)12, sizeof(int32)/sizeof(int8) + 1);
|
|
buffer->putInt(_ioid);
|
|
buffer->putByte((int8)request);
|
|
IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry();
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serializeStatus(buffer, control, _status);
|
|
}
|
|
|
|
if (_status.isSuccess())
|
|
{
|
|
if ((QOS_INIT & request) != 0)
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serialize(_pvPutStructure != NULL ? _pvPutStructure->getField() : FieldConstPtr(), buffer, control);
|
|
introspectionRegistry->serialize(_pvGetStructure != NULL ? _pvGetStructure->getField() : FieldConstPtr(), buffer, control);
|
|
}
|
|
else if ((QOS_GET & request) != 0)
|
|
{
|
|
Lock guard(_mutex);
|
|
_pvGetStructure->serialize(buffer, control);
|
|
}
|
|
else if ((QOS_GET_PUT & request) != 0)
|
|
{
|
|
ScopedLock lock(_channelPutGet); // valid due to _mutex lock above
|
|
//Lock guard(_mutex);
|
|
_pvPutStructure->serialize(buffer, control);
|
|
}
|
|
else
|
|
{
|
|
ScopedLock lock(_channelPutGet); // valid due to _mutex lock above
|
|
//Lock guard(_mutex);
|
|
_pvGetStructure->serialize(buffer, control);
|
|
}
|
|
}
|
|
|
|
stopRequest();
|
|
|
|
// lastRequest
|
|
if ((QOS_DESTROY & request) != 0)
|
|
destroy();
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
void ServerMonitorHandler::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<ChannelHostingTransport>(transport);
|
|
|
|
transport->ensureData(2*sizeof(int32)/sizeof(int8)+1);
|
|
const pvAccessID sid = payloadBuffer->getInt();
|
|
const pvAccessID ioid = payloadBuffer->getInt();
|
|
|
|
// mode
|
|
const int8 qosCode = payloadBuffer->getByte();
|
|
|
|
ServerChannelImpl::shared_pointer channel = static_pointer_cast<ServerChannelImpl>(casTransport->getChannel(sid));
|
|
if (channel == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_MONITOR, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus);
|
|
return;
|
|
}
|
|
|
|
const bool init = (QOS_INIT & qosCode) != 0;
|
|
if (init)
|
|
{
|
|
// pvRequest
|
|
PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get()));
|
|
|
|
// create...
|
|
ServerMonitorRequesterImpl::create(_context, channel, ioid, transport, pvRequest);
|
|
}
|
|
else
|
|
{
|
|
const bool lastRequest = (QOS_DESTROY & qosCode) != 0;
|
|
const bool get = (QOS_GET & qosCode) != 0;
|
|
const bool process = (QOS_PROCESS & qosCode) != 0;
|
|
|
|
ServerMonitorRequesterImpl::shared_pointer request = static_pointer_cast<ServerMonitorRequesterImpl>(channel->getRequest(ioid));
|
|
if (request == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_MONITOR, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
if (!request->startRequest(qosCode))
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_MONITOR, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus);
|
|
return;
|
|
}
|
|
*/
|
|
|
|
if (process)
|
|
{
|
|
if (get)
|
|
request->getChannelMonitor()->start();
|
|
else
|
|
request->getChannelMonitor()->stop();
|
|
//request.stopRequest();
|
|
}
|
|
else if (get)
|
|
{
|
|
// not supported
|
|
}
|
|
|
|
if (lastRequest)
|
|
request->destroy();
|
|
}
|
|
}
|
|
|
|
ServerMonitorRequesterImpl::ServerMonitorRequesterImpl(
|
|
ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport):
|
|
BaseChannelRequester(context, channel, ioid, transport), _channelMonitor(), _structure()
|
|
{
|
|
}
|
|
|
|
MonitorRequester::shared_pointer ServerMonitorRequesterImpl::create(
|
|
ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport,PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
MonitorRequester::shared_pointer thisPointer(new ServerMonitorRequesterImpl(context, channel, ioid, transport));
|
|
static_cast<ServerMonitorRequesterImpl*>(thisPointer.get())->activate(pvRequest);
|
|
return thisPointer;
|
|
}
|
|
|
|
void ServerMonitorRequesterImpl::activate(PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
startRequest(QOS_INIT);
|
|
MonitorRequester::shared_pointer thisPointer = shared_from_this();
|
|
Destroyable::shared_pointer thisDestroyable = shared_from_this();
|
|
_channel->registerRequest(_ioid, thisDestroyable);
|
|
INIT_EXCEPTION_GUARD(CMD_MONITOR, _channelMonitor = _channel->getChannel()->createMonitor(thisPointer, pvRequest));
|
|
}
|
|
|
|
void ServerMonitorRequesterImpl::monitorConnect(const Status& status, Monitor::shared_pointer & monitor, epics::pvData::StructureConstPtr const & structure)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
_channelMonitor = monitor;
|
|
_structure = structure;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
|
|
// self-destruction
|
|
if (!status.isSuccess())
|
|
{
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
void ServerMonitorRequesterImpl::unlisten(Monitor::shared_pointer const & monitor)
|
|
{
|
|
//TODO
|
|
}
|
|
|
|
void ServerMonitorRequesterImpl::monitorEvent(Monitor::shared_pointer const & monitor)
|
|
{
|
|
// TODO !!! if queueSize==0, monitor.poll() has to be called and returned NOW (since there is no cache)
|
|
//sendEvent(transport);
|
|
|
|
// TODO implement via TransportSender
|
|
/*
|
|
// initiate submit to dispatcher queue, if necessary
|
|
synchronized (register) {
|
|
if (register.getAndSet(true))
|
|
eventConsumer.consumeEvents(this);
|
|
}*/
|
|
// TODO
|
|
// multiple ((BlockingServerTCPTransport)transport).enqueueMonitorSendRequest(this);
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerMonitorRequesterImpl::lock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerMonitorRequesterImpl::unlock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerMonitorRequesterImpl::destroy()
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_channel->unregisterRequest(_ioid);
|
|
if (_channelMonitor != NULL)
|
|
{
|
|
_channelMonitor->destroy();
|
|
}
|
|
}
|
|
// TODO
|
|
_channelMonitor.reset();
|
|
}
|
|
|
|
Monitor::shared_pointer ServerMonitorRequesterImpl::getChannelMonitor()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _channelMonitor;
|
|
}
|
|
|
|
void ServerMonitorRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control)
|
|
{
|
|
const int32 request = getPendingRequest();
|
|
|
|
if ((QOS_INIT & request) != 0)
|
|
{
|
|
control->startMessage((int32)CMD_MONITOR, sizeof(int32)/sizeof(int8) + 1);
|
|
buffer->putInt(_ioid);
|
|
buffer->putByte((int8)request);
|
|
|
|
IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry();
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serializeStatus(buffer, control, _status);
|
|
}
|
|
|
|
if (_status.isSuccess())
|
|
{
|
|
// valid due to _mutex lock above
|
|
introspectionRegistry->serialize(_structure, buffer, control);
|
|
}
|
|
stopRequest();
|
|
startRequest(QOS_DEFAULT);
|
|
}
|
|
else
|
|
{
|
|
Monitor::shared_pointer monitor = _channelMonitor;
|
|
MonitorElement::shared_pointer element = monitor->poll();
|
|
if (element != NULL)
|
|
{
|
|
control->startMessage((int8)CMD_MONITOR, sizeof(int32)/sizeof(int8) + 1);
|
|
buffer->putInt(_ioid);
|
|
buffer->putByte((int8)request);
|
|
|
|
// changedBitSet and data, if not notify only (i.e. queueSize == -1)
|
|
BitSet::shared_pointer changedBitSet = element->changedBitSet;
|
|
if (changedBitSet != NULL)
|
|
{
|
|
changedBitSet->serialize(buffer, control);
|
|
element->pvStructurePtr->serialize(buffer, control, changedBitSet.get());
|
|
|
|
// overrunBitset
|
|
element->overrunBitSet->serialize(buffer, control);
|
|
}
|
|
|
|
monitor->release(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
void ServerArrayHandler::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<ChannelHostingTransport>(transport);
|
|
|
|
transport->ensureData(2*sizeof(int32)/sizeof(int8)+1);
|
|
const pvAccessID sid = payloadBuffer->getInt();
|
|
const pvAccessID ioid = payloadBuffer->getInt();
|
|
|
|
// mode
|
|
const int8 qosCode = payloadBuffer->getByte();
|
|
|
|
ServerChannelImpl::shared_pointer channel = static_pointer_cast<ServerChannelImpl>(casTransport->getChannel(sid));
|
|
if (channel == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_ARRAY, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus);
|
|
return;
|
|
}
|
|
|
|
const bool init = (QOS_INIT & qosCode) != 0;
|
|
if (init)
|
|
{
|
|
// pvRequest
|
|
PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get()));
|
|
|
|
// create...
|
|
ServerChannelArrayRequesterImpl::create(_context, channel, ioid, transport, pvRequest);
|
|
}
|
|
else
|
|
{
|
|
const bool lastRequest = (QOS_DESTROY & qosCode) != 0;
|
|
const bool get = (QOS_GET & qosCode) != 0;
|
|
const bool setLength = (QOS_GET_PUT & qosCode) != 0;
|
|
|
|
ServerChannelArrayRequesterImpl::shared_pointer request = static_pointer_cast<ServerChannelArrayRequesterImpl>(channel->getRequest(ioid));
|
|
if (request == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_ARRAY, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus);
|
|
return;
|
|
}
|
|
|
|
if (!request->startRequest(qosCode))
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_ARRAY, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus);
|
|
return;
|
|
}
|
|
|
|
|
|
if (get)
|
|
{
|
|
const int32 offset = SerializeHelper::readSize(payloadBuffer, transport.get());
|
|
const int32 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());
|
|
request->getChannelArray()->setLength(lastRequest, length, capacity);
|
|
}
|
|
else
|
|
{
|
|
// deserialize data to put
|
|
int32 offset;
|
|
ChannelArray::shared_pointer channelArray = request->getChannelArray();
|
|
PVArray::shared_pointer array = request->getPVArray();
|
|
{
|
|
ScopedLock lock(channelArray); // TODO not needed if read by the same thread
|
|
offset = SerializeHelper::readSize(payloadBuffer, transport.get());
|
|
array->deserialize(payloadBuffer, transport.get());
|
|
}
|
|
channelArray->putArray(lastRequest, offset, array->getLength());
|
|
}
|
|
}
|
|
}
|
|
|
|
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()
|
|
{
|
|
}
|
|
|
|
ChannelArrayRequester::shared_pointer ServerChannelArrayRequesterImpl::create(
|
|
ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport,PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
ChannelArrayRequester::shared_pointer thisPointer(new ServerChannelArrayRequesterImpl(context, channel, ioid, transport));
|
|
static_cast<ServerChannelArrayRequesterImpl*>(thisPointer.get())->activate(pvRequest);
|
|
return thisPointer;
|
|
}
|
|
|
|
void ServerChannelArrayRequesterImpl::activate(PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
startRequest(QOS_INIT);
|
|
ChannelArrayRequester::shared_pointer thisPointer = shared_from_this();
|
|
Destroyable::shared_pointer thisDestroyable = shared_from_this();
|
|
_channel->registerRequest(_ioid, thisDestroyable);
|
|
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)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
_pvArray = pvArray;
|
|
_channelArray = channelArray;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
|
|
// self-destruction
|
|
if (!status.isSuccess())
|
|
{
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
void ServerChannelArrayRequesterImpl::getArrayDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelArrayRequesterImpl::putArrayDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelArrayRequesterImpl::setLengthDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelArrayRequesterImpl::lock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelArrayRequesterImpl::unlock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelArrayRequesterImpl::destroy()
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_channel->unregisterRequest(_ioid);
|
|
if (_channelArray != NULL)
|
|
{
|
|
_channelArray->destroy();
|
|
}
|
|
}
|
|
// TODO
|
|
_channelArray.reset();
|
|
}
|
|
|
|
ChannelArray::shared_pointer ServerChannelArrayRequesterImpl::getChannelArray()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _channelArray;
|
|
}
|
|
|
|
PVArray::shared_pointer ServerChannelArrayRequesterImpl::getPVArray()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _pvArray;
|
|
}
|
|
|
|
void ServerChannelArrayRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control)
|
|
{
|
|
const int32 request = getPendingRequest();
|
|
|
|
control->startMessage((int32)CMD_ARRAY, sizeof(int32)/sizeof(int8) + 1);
|
|
buffer->putInt(_ioid);
|
|
buffer->putByte((int8)request);
|
|
IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry();
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serializeStatus(buffer, control, _status);
|
|
}
|
|
|
|
if (_status.isSuccess())
|
|
{
|
|
if ((QOS_GET & request) != 0)
|
|
{
|
|
//Lock guard(_mutex);
|
|
ScopedLock lock(_channelArray); // valid due to _mutex lock above
|
|
_pvArray->serialize(buffer, control, 0, _pvArray->getLength());
|
|
}
|
|
else if ((QOS_INIT & request) != 0)
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serialize(_pvArray != NULL ? _pvArray->getField() : FieldConstPtr(), buffer, control);
|
|
}
|
|
}
|
|
|
|
stopRequest();
|
|
|
|
// lastRequest
|
|
if ((QOS_DESTROY & request) != 0)
|
|
destroy();
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
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<ChannelHostingTransport>(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<ServerChannelImpl>(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;
|
|
}
|
|
|
|
// destroy
|
|
request->destroy();
|
|
|
|
// ... and remove from channel
|
|
channel->unregisterRequest(ioid);
|
|
}
|
|
|
|
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,
|
|
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<ChannelHostingTransport>(transport);
|
|
|
|
transport->ensureData(2*sizeof(int32)/sizeof(int8)+1);
|
|
const pvAccessID sid = payloadBuffer->getInt();
|
|
const pvAccessID ioid = payloadBuffer->getInt();
|
|
|
|
// mode
|
|
const int8 qosCode = payloadBuffer->getByte();
|
|
|
|
ServerChannelImpl::shared_pointer channel = static_pointer_cast<ServerChannelImpl>(casTransport->getChannel(sid));
|
|
if (channel == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_PROCESS, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus);
|
|
return;
|
|
}
|
|
|
|
const bool init = (QOS_INIT & qosCode) != 0;
|
|
if (init)
|
|
{
|
|
// pvRequest
|
|
PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get()));
|
|
|
|
// create...
|
|
ServerChannelProcessRequesterImpl::create(_context, channel, ioid, transport, pvRequest);
|
|
}
|
|
else
|
|
{
|
|
const bool lastRequest = (QOS_DESTROY & qosCode) != 0;
|
|
|
|
ServerChannelProcessRequesterImpl::shared_pointer request = static_pointer_cast<ServerChannelProcessRequesterImpl>(channel->getRequest(ioid));
|
|
if (request == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_PROCESS, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus);
|
|
return;
|
|
}
|
|
|
|
if (!request->startRequest(qosCode))
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_PROCESS, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus);
|
|
return;
|
|
}
|
|
|
|
request->getChannelProcess()->process(lastRequest);
|
|
}
|
|
}
|
|
|
|
ServerChannelProcessRequesterImpl::ServerChannelProcessRequesterImpl(
|
|
ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport):
|
|
BaseChannelRequester(context, channel, ioid, transport), _channelProcess()
|
|
{
|
|
}
|
|
|
|
ChannelProcessRequester::shared_pointer ServerChannelProcessRequesterImpl::create(
|
|
ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport,PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
ChannelProcessRequester::shared_pointer thisPointer(new ServerChannelProcessRequesterImpl(context, channel, ioid, transport));
|
|
static_cast<ServerChannelProcessRequesterImpl*>(thisPointer.get())->activate(pvRequest);
|
|
return thisPointer;
|
|
}
|
|
|
|
void ServerChannelProcessRequesterImpl::activate(PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
startRequest(QOS_INIT);
|
|
ChannelProcessRequester::shared_pointer thisPointer = shared_from_this();
|
|
Destroyable::shared_pointer thisDestroyable = shared_from_this();
|
|
_channel->registerRequest(_ioid, thisDestroyable);
|
|
INIT_EXCEPTION_GUARD(CMD_PROCESS, _channelProcess = _channel->getChannel()->createChannelProcess(thisPointer, pvRequest));
|
|
}
|
|
|
|
void ServerChannelProcessRequesterImpl::channelProcessConnect(const Status& status, ChannelProcess::shared_pointer const & channelProcess)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
_channelProcess = channelProcess;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
|
|
// self-destruction
|
|
if (!status.isSuccess())
|
|
{
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
void ServerChannelProcessRequesterImpl::processDone(const Status& status)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelProcessRequesterImpl::lock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelProcessRequesterImpl::unlock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelProcessRequesterImpl::destroy()
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_channel->unregisterRequest(_ioid);
|
|
if (_channelProcess != NULL)
|
|
{
|
|
_channelProcess->destroy();
|
|
}
|
|
}
|
|
// TODO
|
|
_channelProcess.reset();
|
|
}
|
|
|
|
ChannelProcess::shared_pointer ServerChannelProcessRequesterImpl::getChannelProcess()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _channelProcess;
|
|
}
|
|
|
|
void ServerChannelProcessRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control)
|
|
{
|
|
const int32 request = getPendingRequest();
|
|
|
|
control->startMessage((int32)CMD_PROCESS, sizeof(int32)/sizeof(int8) + 1);
|
|
buffer->putInt(_ioid);
|
|
buffer->putByte((int8)request);
|
|
IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry();
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serializeStatus(buffer, control, _status);
|
|
}
|
|
|
|
stopRequest();
|
|
|
|
// lastRequest
|
|
if ((QOS_DESTROY & request) != 0)
|
|
{
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************************/
|
|
void ServerGetFieldHandler::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<ChannelHostingTransport>(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<ServerChannelImpl>(casTransport->getChannel(sid));
|
|
if (channel == NULL)
|
|
{
|
|
getFieldFailureResponse(transport, ioid, BaseChannelRequester::badCIDStatus);
|
|
return;
|
|
}
|
|
|
|
String subField = SerializeHelper::deserializeString(payloadBuffer, transport.get());
|
|
|
|
// issue request
|
|
GetFieldRequester::shared_pointer gfr(new ServerGetFieldRequesterImpl(_context, channel, ioid, transport));
|
|
// TODO exception check
|
|
channel->getChannel()->getField(gfr, subField);
|
|
}
|
|
|
|
void ServerGetFieldHandler::getFieldFailureResponse(Transport::shared_pointer const & transport, const pvAccessID ioid, const Status& errorStatus)
|
|
{
|
|
TransportSender::shared_pointer sender(new ServerGetFieldHandlerTransportSender(ioid,errorStatus,transport));
|
|
transport->enqueueSendRequest(sender);
|
|
}
|
|
|
|
ServerGetFieldRequesterImpl::ServerGetFieldRequesterImpl(
|
|
ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport) :
|
|
BaseChannelRequester(context, channel, ioid, transport), _field()
|
|
{
|
|
}
|
|
|
|
void ServerGetFieldRequesterImpl::getDone(const Status& status, FieldConstPtr const & field)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
_field = field;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerGetFieldRequesterImpl::lock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerGetFieldRequesterImpl::unlock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerGetFieldRequesterImpl::destroy()
|
|
{
|
|
}
|
|
|
|
void ServerGetFieldRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control)
|
|
{
|
|
control->startMessage((int8)CMD_GET_FIELD, sizeof(int32)/sizeof(int8));
|
|
buffer->putInt(_ioid);
|
|
IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry();
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serializeStatus(buffer, control, _status);
|
|
introspectionRegistry->serialize(_field, buffer, control);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
void ServerRPCHandler::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<ChannelHostingTransport>(transport);
|
|
|
|
transport->ensureData(2*sizeof(int32)/sizeof(int8)+1);
|
|
const pvAccessID sid = payloadBuffer->getInt();
|
|
const pvAccessID ioid = payloadBuffer->getInt();
|
|
|
|
// mode
|
|
const int8 qosCode = payloadBuffer->getByte();
|
|
|
|
ServerChannelImpl::shared_pointer channel = static_pointer_cast<ServerChannelImpl>(casTransport->getChannel(sid));
|
|
if (channel == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_RPC, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus);
|
|
return;
|
|
}
|
|
|
|
const bool init = (QOS_INIT & qosCode) != 0;
|
|
if (init)
|
|
{
|
|
// pvRequest
|
|
PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get()));
|
|
|
|
// create...
|
|
ServerChannelRPCRequesterImpl::create(_context, channel, ioid, transport, pvRequest);
|
|
}
|
|
else
|
|
{
|
|
const bool lastRequest = (QOS_DESTROY & qosCode) != 0;
|
|
|
|
ServerChannelRPCRequesterImpl::shared_pointer request = static_pointer_cast<ServerChannelRPCRequesterImpl>(channel->getRequest(ioid));
|
|
if (request == NULL)
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_RPC, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus);
|
|
return;
|
|
}
|
|
|
|
if (!request->startRequest(qosCode))
|
|
{
|
|
BaseChannelRequester::sendFailureMessage((int8)CMD_RPC, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus);
|
|
return;
|
|
}
|
|
|
|
// deserialize put data
|
|
ChannelRPC::shared_pointer channelRPC = request->getChannelRPC();
|
|
// pvArgument
|
|
PVStructure::shared_pointer pvArgument(transport->getIntrospectionRegistry()->deserializeStructure(payloadBuffer, transport.get()));
|
|
channelRPC->request(pvArgument, lastRequest);
|
|
}
|
|
}
|
|
|
|
ServerChannelRPCRequesterImpl::ServerChannelRPCRequesterImpl(
|
|
ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport):
|
|
BaseChannelRequester(context, channel, ioid, transport),
|
|
_channelRPC(), _pvResponse()
|
|
|
|
{
|
|
}
|
|
|
|
ChannelRPCRequester::shared_pointer ServerChannelRPCRequesterImpl::create(
|
|
ServerContextImpl::shared_pointer const & context, ServerChannelImpl::shared_pointer const & channel,
|
|
const pvAccessID ioid, Transport::shared_pointer const & transport, PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
ChannelRPCRequester::shared_pointer thisPointer(new ServerChannelRPCRequesterImpl(context, channel, ioid, transport));
|
|
static_cast<ServerChannelRPCRequesterImpl*>(thisPointer.get())->activate(pvRequest);
|
|
return thisPointer;
|
|
}
|
|
|
|
void ServerChannelRPCRequesterImpl::activate(PVStructure::shared_pointer const & pvRequest)
|
|
{
|
|
startRequest(QOS_INIT);
|
|
ChannelRPCRequester::shared_pointer thisPointer = shared_from_this();
|
|
Destroyable::shared_pointer thisDestroyable = shared_from_this();
|
|
_channel->registerRequest(_ioid, thisDestroyable);
|
|
INIT_EXCEPTION_GUARD(CMD_RPC, _channelRPC = _channel->getChannel()->createChannelRPC(thisPointer, pvRequest));
|
|
}
|
|
|
|
void ServerChannelRPCRequesterImpl::channelRPCConnect(const Status& status, ChannelRPC::shared_pointer const & channelRPC)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
_channelRPC = channelRPC;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
|
|
// self-destruction
|
|
if (!status.isSuccess())
|
|
{
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
void ServerChannelRPCRequesterImpl::requestDone(const Status& status, PVStructure::shared_pointer const & pvResponse)
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_status = status;
|
|
_pvResponse = pvResponse;
|
|
}
|
|
TransportSender::shared_pointer thisSender = shared_from_this();
|
|
_transport->enqueueSendRequest(thisSender);
|
|
}
|
|
|
|
void ServerChannelRPCRequesterImpl::lock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelRPCRequesterImpl::unlock()
|
|
{
|
|
//noop
|
|
}
|
|
|
|
void ServerChannelRPCRequesterImpl::destroy()
|
|
{
|
|
{
|
|
Lock guard(_mutex);
|
|
_channel->unregisterRequest(_ioid);
|
|
if (_channelRPC != NULL)
|
|
{
|
|
_channelRPC->destroy();
|
|
}
|
|
}
|
|
// TODO
|
|
_channelRPC.reset();
|
|
}
|
|
|
|
ChannelRPC::shared_pointer ServerChannelRPCRequesterImpl::getChannelRPC()
|
|
{
|
|
//Lock guard(_mutex);
|
|
return _channelRPC;
|
|
}
|
|
|
|
void ServerChannelRPCRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control)
|
|
{
|
|
const int32 request = getPendingRequest();
|
|
|
|
control->startMessage((int32)CMD_RPC, sizeof(int32)/sizeof(int8) + 1);
|
|
buffer->putInt(_ioid);
|
|
buffer->putByte((int8)request);
|
|
IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry();
|
|
|
|
{
|
|
Lock guard(_mutex);
|
|
introspectionRegistry->serializeStatus(buffer, control, _status);
|
|
|
|
if (_status.isSuccess())
|
|
{
|
|
if ((QOS_INIT & request) != 0)
|
|
{
|
|
// noop
|
|
}
|
|
else
|
|
{
|
|
introspectionRegistry->serializeStructure(buffer, control, _pvResponse);
|
|
}
|
|
}
|
|
}
|
|
|
|
stopRequest();
|
|
|
|
// lastRequest
|
|
if ((QOS_DESTROY & request) != 0)
|
|
destroy();
|
|
}
|
|
|
|
}
|
|
}
|