12 #include <epicsStdlib.h>
13 #include <epicsGetopt.h>
15 #include <epicsTimer.h>
16 #include <libComRegister.h>
20 #include <pv/pvAccess.h>
21 #include <pv/clientFactory.h>
22 #include <pv/configuration.h>
23 #include <pv/serverContext.h>
24 #include <pv/reftrack.h>
25 #include <pv/iocreftrack.h>
26 #include <pv/iocshelper.h>
27 #include <pv/logger.h>
32 namespace pvd = epics::pvData;
33 namespace pva = epics::pvAccess;
35 extern int p2pReadOnly;
39 pvd::StructureConstPtr schema(pvd::getFieldCreate()->createFieldBuilder()
40 ->add(
"version", pvd::pvUInt)
41 ->add(
"readOnly", pvd::pvBoolean)
42 ->addNestedStructureArray(
"clients")
43 ->add(
"name", pvd::pvString)
44 ->add(
"provider", pvd::pvString)
45 ->add(
"addrlist", pvd::pvString)
46 ->add(
"autoaddrlist", pvd::pvBoolean)
47 ->add(
"serverport", pvd::pvUShort)
48 ->add(
"bcastport", pvd::pvUShort)
50 ->addNestedStructureArray(
"servers")
51 ->add(
"name", pvd::pvString)
52 ->addArray(
"clients", pvd::pvString)
53 ->add(
"interface", pvd::pvString)
54 ->add(
"addrlist", pvd::pvString)
55 ->add(
"autoaddrlist", pvd::pvBoolean)
56 ->add(
"serverport", pvd::pvUShort)
57 ->add(
"bcastport", pvd::pvUShort)
58 ->add(
"control_prefix", pvd::pvString)
63 void usage(
const char *me)
65 std::cerr<<
"Usage: "<<me<<
" [-vhiIC] <config file>\n";
71 bool checkonly =
false;
73 while( (opt=getopt(argc, argv,
"qvhiIC"))!=-1)
83 arg.interactive =
true;
86 arg.interactive =
false;
92 std::cerr<<
"Unknown argument -"<<char(opt)<<
"\n";
100 std::cerr<<
"Exactly one positional argument expected\n";
105 arg.conf = pvd::getPVDataCreate()->createPVStructure(schema);
106 std::ifstream strm(argv[optind]);
107 pvd::parseJSON(strm, arg.conf);
109 p2pReadOnly = arg.conf->getSubFieldT<pvd::PVScalar>(
"readOnly")->getAs<pvd::boolean>();
111 unsigned version = arg.conf->getSubFieldT<pvd::PVUInt>(
"version")->
get();
113 std::cerr<<
"Warning: config file missing \"version\" key. Assuming 1\n";
114 }
else if(version!=1) {
115 std::cerr<<
"config file version mis-match. expect 1 found "<<version<<
"\n";
118 if(arg.conf->getSubFieldT<pvd::PVStructureArray>(
"clients")->view().empty()) {
119 std::cerr<<
"No clients configured\n";
122 if(arg.conf->getSubFieldT<pvd::PVStructureArray>(
"servers")->view().empty()) {
123 std::cerr<<
"No servers configured\n";
128 std::cerr<<
"Config file OK\n";
133 GWServerChannelProvider::shared_pointer configure_client(
ServerConfig& arg,
const pvd::PVStructurePtr& conf)
135 std::string name(conf->getSubFieldT<pvd::PVString>(
"name")->get());
136 std::string provider(conf->getSubFieldT<pvd::PVString>(
"provider")->get());
138 LOG(pva::logLevelInfo,
"Configure client '%s' with provider '%s'", name.c_str(), provider.c_str());
140 pva::Configuration::shared_pointer C(pva::ConfigurationBuilder()
141 .add(
"EPICS_PVA_ADDR_LIST", conf->getSubFieldT<pvd::PVString>(
"addrlist")->get())
142 .add(
"EPICS_PVA_AUTO_ADDR_LIST", conf->getSubFieldT<pvd::PVScalar>(
"autoaddrlist")->getAs<std::string>())
143 .add(
"EPICS_PVA_SERVER_PORT", conf->getSubFieldT<pvd::PVScalar>(
"serverport")->getAs<pvd::uint16>())
144 .add(
"EPICS_PVA_BROADCAST_PORT", conf->getSubFieldT<pvd::PVScalar>(
"bcastport")->getAs<pvd::uint16>())
145 .add(
"EPICS_PVA_DEBUG", arg.debug>=5 ? 5 : 0)
149 pva::ChannelProvider::shared_pointer base(pva::ChannelProviderRegistry::clients()->createProvider(provider, C));
151 throw std::runtime_error(
"Can't create ChannelProvider");
157 pva::ServerContext::shared_pointer configure_server(
ServerConfig& arg,
const pvd::PVStructurePtr& conf)
159 std::string name(conf->getSubFieldT<pvd::PVString>(
"name")->get());
161 LOG(pva::logLevelInfo,
"Configure server '%s'", name.c_str());
163 pva::Configuration::shared_pointer C(pva::ConfigurationBuilder()
164 .add(
"EPICS_PVAS_INTF_ADDR_LIST", conf->getSubFieldT<pvd::PVString>(
"interface")->get())
165 .add(
"EPICS_PVAS_BEACON_ADDR_LIST", conf->getSubFieldT<pvd::PVString>(
"addrlist")->get())
166 .add(
"EPICS_PVAS_AUTO_BEACON_ADDR_LIST", conf->getSubFieldT<pvd::PVScalar>(
"autoaddrlist")->getAs<std::string>())
167 .add(
"EPICS_PVAS_SERVER_PORT", conf->getSubFieldT<pvd::PVScalar>(
"serverport")->getAs<pvd::uint16>())
168 .add(
"EPICS_PVAS_BROADCAST_PORT", conf->getSubFieldT<pvd::PVScalar>(
"bcastport")->getAs<pvd::uint16>())
169 .add(
"EPICS_PVA_DEBUG", arg.debug>=5 ? 5 : 0)
173 pvd::PVStringArray::shared_pointer clients(conf->getSubFieldT<pvd::PVStringArray>(
"clients"));
174 pvd::PVStringArray::const_svector names(clients->view());
175 std::vector<pva::ChannelProvider::shared_pointer> providers;
177 for(pvd::PVStringArray::const_svector::const_iterator it(names.begin()), end(names.end()); it!=end; ++it)
179 ServerConfig::clients_t::const_iterator it2(arg.clients.find(*it));
180 if(it2==arg.clients.end())
181 throw std::runtime_error(
"Server references non-existant client");
182 providers.push_back(it2->second);
185 pva::ServerContext::shared_pointer ret(pva::ServerContext::create(pva::ServerContext::Config()
187 .providers(providers)));
195 void sigdone(
int num)
205 void iocsh_drop(
const char *client,
const char *channel)
210 theserver->drop(client, channel);
211 }
catch(std::exception& e){
212 std::cout<<
"Error: "<<e.what()<<
"\n";
216 void gwsr(
int lvl,
const char *server)
221 theserver->status_server(lvl, server);
222 }
catch(std::exception& e){
223 std::cout<<
"Error: "<<e.what()<<
"\n";
227 void gwcr(
int lvl,
const char *client,
const char *channel)
232 theserver->status_client(lvl, client, channel);
233 }
catch(std::exception& e){
234 std::cout<<
"Error: "<<e.what()<<
"\n";
240 int main(
int argc,
char *argv[])
243 pva::refTrackRegistrar();
245 epics::iocshRegister<const char*, const char*, &iocsh_drop>(
"drop",
"client",
"channel");
246 epics::iocshRegister<int, const char*, &gwsr>(
"gwsr",
"level",
"channel");
247 epics::iocshRegister<int, const char*, const char*, &gwcr>(
"gwcr",
"level",
"client",
"channel");
251 epics::registerRefCounter(
"ChannelCacheEntry", &ChannelCacheEntry::num_instances);
252 epics::registerRefCounter(
"ChannelCacheEntry::CRequester", &ChannelCacheEntry::CRequester::num_instances);
253 epics::registerRefCounter(
"GWChannel", &GWChannel::num_instances);
254 epics::registerRefCounter(
"MonitorCacheEntry", &MonitorCacheEntry::num_instances);
255 epics::registerRefCounter(
"MonitorUser", &MonitorUser::num_instances);
259 getargs(arg, argc, argv);
262 std::cout<<
"Notice: This p2p gateway prototype has been superceded by the p4p.gw gateway\n"
263 " which has exciting new features including granular access control,\n"
264 " and status PVs including bandwidth usage reports.\n"
265 " p2p is considered deprecated by its author, and will receive\n"
266 " minimal maintainance effort going forward.\n"
267 " Users are encouraged to migrate to p4p.gw.\n"
269 " https://mdavidsaver.github.io/p4p/gw.html\n"
272 pva::pvAccessLogLevel lvl;
274 lvl = pva::logLevelError;
275 else if(arg.debug==0)
276 lvl = pva::logLevelWarn;
277 else if(arg.debug==1)
278 lvl = pva::logLevelInfo;
279 else if(arg.debug==2)
280 lvl = pva::logLevelDebug;
281 else if(arg.debug==3)
282 lvl = pva::logLevelTrace;
283 else if(arg.debug>=4)
284 lvl = pva::logLevelAll;
287 pva::ClientFactory::start();
289 pvd::PVStructureArray::const_svector arr;
291 arr = arg.conf->getSubFieldT<pvd::PVStructureArray>(
"clients")->view();
293 for(
size_t i=0; i<arr.size(); i++) {
294 if(!arr[i])
continue;
295 const pvd::PVStructurePtr& client = arr[i];
297 std::string name(client->getSubFieldT<pvd::PVString>(
"name")->get());
299 throw std::runtime_error(
"Client with empty name not allowed");
301 ServerConfig::clients_t::const_iterator it(arg.clients.find(name));
302 if(it!=arg.clients.end())
303 throw std::runtime_error(std::string(
"Duplicate client name not allowed : ")+name);
305 arg.clients[name] = configure_client(arg, client);
308 arr = arg.conf->getSubFieldT<pvd::PVStructureArray>(
"servers")->view();
310 for(
size_t i=0; i<arr.size(); i++) {
311 if(!arr[i])
continue;
312 const pvd::PVStructurePtr& server = arr[i];
314 std::string name(server->getSubFieldT<pvd::PVString>(
"name")->get());
316 throw std::runtime_error(
"Server with empty name not allowed");
318 ServerConfig::servers_t::const_iterator it(arg.servers.find(name));
319 if(it!=arg.servers.end())
320 throw std::runtime_error(std::string(
"Duplicate server name not allowed : ")+name);
322 arg.servers[name] = configure_server(arg, server);
326 if(arg.interactive) {
330 signal(SIGINT, sigdone);
331 signal(SIGTERM, sigdone);
332 signal(SIGQUIT, sigdone);
343 }
catch(std::exception& e){
344 std::cerr<<
"Fatal Error : "<<e.what()<<
"\n";