diff --git a/src/rpcClient/pv/rpcClient.h b/src/rpcClient/pv/rpcClient.h index a320746..ee1d71a 100644 --- a/src/rpcClient/pv/rpcClient.h +++ b/src/rpcClient/pv/rpcClient.h @@ -14,6 +14,7 @@ # undef epicsExportSharedSymbols #endif #include +#include #ifdef rpcClientEpicsExportSharedSymbols # define epicsExportSharedSymbols # undef rpcClientEpicsExportSharedSymbols diff --git a/src/rpcClient/rpcClient.cpp b/src/rpcClient/rpcClient.cpp index e103919..3d83c75 100644 --- a/src/rpcClient/rpcClient.cpp +++ b/src/rpcClient/rpcClient.cpp @@ -36,7 +36,7 @@ struct RPCClient::RPCRequester : public pva::ChannelRPCRequester POINTER_DEFINITIONS(RPCRequester); pvd::Mutex mutex; - ChannelRPC::weak_pointer op; + ChannelRPC::shared_pointer op; pvd::Status conn_status, resp_status; epics::pvData::PVStructure::shared_pointer next_args, last_data; epicsEvent event; diff --git a/src/rpcService/pv/rpcServer.h b/src/rpcService/pv/rpcServer.h index f552d1c..735e940 100644 --- a/src/rpcService/pv/rpcServer.h +++ b/src/rpcService/pv/rpcServer.h @@ -38,12 +38,10 @@ private: std::tr1::shared_ptr m_serverContext; ChannelProvider::shared_pointer m_channelProviderImpl; - // TODO no thread poll implementation - public: POINTER_DEFINITIONS(RPCServer); - RPCServer(); + explicit RPCServer(const Configuration::const_shared_pointer& conf = Configuration::const_shared_pointer()); virtual ~RPCServer(); @@ -66,6 +64,7 @@ public: */ void printInfo(); + const std::tr1::shared_ptr& getServer() const { return m_serverContext; } }; epicsShareFunc Channel::shared_pointer createRPCChannel(ChannelProvider::shared_pointer const & provider, diff --git a/src/rpcService/pv/rpcService.h b/src/rpcService/pv/rpcService.h index 793dd5c..32eed92 100644 --- a/src/rpcService/pv/rpcService.h +++ b/src/rpcService/pv/rpcService.h @@ -32,10 +32,13 @@ namespace pvAccess { class epicsShareClass RPCRequestException : public std::runtime_error { public: + explicit RPCRequestException(std::string const & message) : + std::runtime_error(message), m_status(epics::pvData::Status::STATUSTYPE_ERROR) + {} + RPCRequestException(epics::pvData::Status::StatusType status, std::string const & message) : std::runtime_error(message), m_status(status) - { - } + {} epics::pvData::Status::StatusType getStatus() const { return m_status; diff --git a/src/rpcService/rpcServer.cpp b/src/rpcService/rpcServer.cpp index f641e31..12d7366 100644 --- a/src/rpcService/rpcServer.cpp +++ b/src/rpcService/rpcServer.cpp @@ -477,11 +477,12 @@ string RPCChannelProvider::PROVIDER_NAME("rpcService"); Status RPCChannelProvider::noSuchChannelStatus(Status::STATUSTYPE_ERROR, "no such channel"); -RPCServer::RPCServer() +RPCServer::RPCServer(const Configuration::const_shared_pointer &conf) :m_channelProviderImpl(new RPCChannelProvider) { ChannelProvider::shared_pointer prov(new RPCChannelProvider); m_serverContext = ServerContext::create(ServerContext::Config() + .config(conf) .provider(m_channelProviderImpl)); } diff --git a/testApp/remote/Makefile b/testApp/remote/Makefile index 9784d3c..8c0de3b 100644 --- a/testApp/remote/Makefile +++ b/testApp/remote/Makefile @@ -12,6 +12,9 @@ testCodec_SRCS = testCodec testHarness_SRCS += testCodec.cpp TESTS += testCodec +TESTPROD_HOST += testRPC +testRPC_SRCS += testRPC.cpp +TESTS += testRPC TESTPROD_HOST += testRemoteClientImpl testRemoteClientImpl_SRCS += testRemoteClientImpl.cpp diff --git a/testApp/remote/testRPC.cpp b/testApp/remote/testRPC.cpp new file mode 100644 index 0000000..ac2dd53 --- /dev/null +++ b/testApp/remote/testRPC.cpp @@ -0,0 +1,104 @@ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace pvd = epics::pvData; +namespace pva = epics::pvAccess; + +namespace { + +pvd::StructureConstPtr reply_type(pvd::getFieldCreate()->createFieldBuilder() + ->add("value", pvd::pvDouble) + ->createStructure()); + +struct SumService : public pva::RPCService +{ + virtual epics::pvData::PVStructure::shared_pointer request( + epics::pvData::PVStructure::shared_pointer const & args + ) OVERRIDE FINAL + { + testDiag("request()"); + pvd::PVScalarPtr lhs(args->getSubField("query.lhs")), + rhs(args->getSubField("query.rhs")); + if(!lhs || !rhs) + throw pva::RPCRequestException("Missing query.lhs and/or query.rhs"); + + double a = lhs->getAs(), + b = rhs->getAs(); + + testDiag("Add %f + %f", a, b); + pvd::PVStructure::shared_pointer reply(pvd::getPVDataCreate()->createPVStructure(reply_type)); + reply->getSubFieldT("value")->put(a+b); + return reply; + } +}; + + +} // namespace + +MAIN(testRPC) +{ + testPlan(2); + try { + pva::Configuration::shared_pointer conf(pva::ConfigurationBuilder() + //.push_env() + //.add("EPICS_PVA_DEBUG", "3") + .add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1") + .add("EPICS_PVA_ADDR_LIST", "127.0.0.1") + .add("EPICS_PVA_AUTO_ADDR_LIST","0") + .add("EPICS_PVA_SERVER_PORT", "0") + .add("EPICS_PVA_BROADCAST_PORT", "0") + .push_map() + .build()); + + testDiag("Server Setup"); + pva::RPCServer serv(conf); + testDiag("TestServer on ports TCP=%u UDP=%u", + serv.getServer()->getServerPort(), + serv.getServer()->getBroadcastPort()); + + std::tr1::shared_ptr service(new SumService); + serv.registerService("sum", service); + + testDiag("Client Setup"); + pva::ClientFactory::start(); + pva::ChannelProvider::shared_pointer cli_prov(pva::ChannelProviderRegistry::clients()->createProvider("pva", + serv.getServer()->getCurrentConfig())); + if(!cli_prov) + testAbort("No pva provider"); + testDiag("Client Ready"); + pva::RPCClient client("sum", pvd::createRequest("field()"), cli_prov); + + pvd::ValueBuilder args("epics:nt/NTURI:1.0"); + args.add("scheme", "pva") + .add("path", "sum"); + + pvd::PVStructurePtr reply; + + testDiag("Request"); + reply = client.request(args.addNested("query") + .add("lhs", 5.0) + .add("rhs", 3.0) + .endNested() + .buildPVStructure()); + + pvd::int32 value = reply->getSubFieldT("value")->getAs(); + testOk(value==8, "Reply value = %d", (unsigned)value); + + testDiag("Wait for connect (already connected)"); + testOk1(client.waitConnect()); + + }catch(std::exception& e){ + PRINT_EXCEPTION(e); + testAbort("Unexpected exception: %s", e.what()); + } + return testDone(); +}