1) added canRead for access security

2) main documentation moved to https://mrkraimer.github.io/website/developerGuide/pvDatabase/pvDatabaseCPP.html
This commit is contained in:
mrkraimer
2021-03-24 14:35:05 -04:00
parent 333cd44da0
commit b1822f5fbd
4 changed files with 81 additions and 218 deletions

View File

@ -2,6 +2,11 @@
This document summarizes the changes to the module between releases. This document summarizes the changes to the module between releases.
## Release 4.6.0 (EPICS 7.0.5.* March 2021)
* Access Security is now supported.
* Special support has been revised and extended.
## Release 4.5.3 (EPICS 7.0.5 Feb 2021) ## Release 4.5.3 (EPICS 7.0.5 Feb 2021)
* The previously deprecated destroy methods have been removed. * The previously deprecated destroy methods have been removed.

View File

@ -4,72 +4,66 @@
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>pvDatabaseCPP</title> <title>EPICS pvDatabaseCPP</title>
<link rel="stylesheet" type="text/css" <link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" /> href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css" <link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" /> href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css"> <style type="text/css">
/*<![CDATA[*/ /*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em} .about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto } table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 } .diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey } body { margin-right: 10% }
span.nterm { font-style:italic } /*]]>*/</style>
span.term { font-family:courier }
span.user { font-family:courier } <!-- Script that generates the Table of Contents -->
span.user:before { content:"<" } <script type="text/javascript" src="http://epics-pvdata.sourceforge.net/script/tocgen.js"></script>
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head> </head>
<body> <body>
<div class="head"> <div class="head">
<h1>pvDatabaseCPP</h1> <h1>EPICS pvDatabaseCPP</h1>
<h2 class="nocount">Release ? - TBD</h2> <h2 class="nocount">Release 4.6.0 - March 2021</h2>
Latest update 2019.09.11.
<h2 class="nocount">Abstract</h2> <h2 class="nocount">Abstract</h2>
<p>This document describes pvDatabaseCPP, <p><b>pvDatabase</b> is a framework for implementing a network accessible database of smart memory resident
which is a framework for implementing a network accessible database of smart memory resident
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess. pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
The framework can be extended in order to create record instances that implements services. The framework can be extended in order to create record instances that implements services.
The minimum that an extension must provide is a top level PVStructure and a process method. The minimum that an extension must provide is a top level PVStructure and a process method.
</p> </p>
<!-- last para of Abstract is boilerplate reference to EPICS --> <!-- last para of Abstract is boilerplate reference to EPICS -->
<p>For more information about EPICS generally, please refer to the home page of the <a <p>For more information about EPICS generally, please refer to the home page of the <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
Control System</a>.</p> Control System</a>.</p>
</div> </div> <!-- head -->
<div id="toc">
<h2 class="nocount">Table of Contents</h2>
</div>
<div id="contents" class="contents"> <div id="contents" class="contents">
<hr /> <hr />
<h2>Overview</h2> <h2>Overview</h2>
<p> <p>
Documentation for pvDatabaseCPP is available at:
<a
href="https://mrkraimer.github.io/website/developerGuide/pvDatabase/pvDatabaseCPP.html">
pvDatabase
</a>
</p>
<p>
pvDatabaseCPP is one of the components of pvDatabaseCPP is one of the components of
EPICS Version 7 <a href="https://epics-controls.org/resources-and-support/base/epics-7/">
EPICS-7
</a>
</p> </p>
<p>This document is only a guide to help locate code and documentation related to pvDatabaseCPP <p>This document is only a guide to help locate code and documentation related to pvDatabaseCPP
</p>
<p>
It is intended for developers that want to use pvDatabaseCPP. It is intended for developers that want to use pvDatabaseCPP.
</p> </p>
<h2>Developer Guide</h2> <h2>Developer Guide</h2>
@ -79,204 +73,28 @@ href="https://mrkraimer.github.io/website/developerGuide/developerGuide.html">
developerGuide developerGuide
</a> </a>
</p> </p>
<p>This guide discusses all the components that are part of an <b>EPICS V4</b> release. <p>This guide provides an overview of the components that are part of an <b>EPICS V4</b> release.
Some understanding of the components and how they are related is necessary in order to Some understanding of the components and how they are related is necessary in order to
develop code that uses pvDatabaseCPP. develop code that uses pvDatabaseCPP.
In particular read everything related to pvDatabase. In particular read everything related to pvaClient.
</p>
<p>pvDatabase has plugin support, which is implemented in <b>pvCopy</b>.
<b>pvCopy</b> was originally implemented in <b>pvDataCPP</b>,
but pvDatabaseCPP now implements its own version and adds plugin support.
</p>
<p>
See
<a
href="https://mrkraimer.github.io/website/pvRequest/pvRequest.html">
pvRequest
</a>
for details.
</p>
<p>The developerGuide discusses code in a way that applies to both CPP and C++.
For the descriptions of the CPP specific code consult the following sections.
</p> </p>
<h2>doxygen</h2> <h2>doxygen</h2>
<p>doxygen documentation is available at <p>doxygen documentation is available at
<a <a
href="./html/index.html">doxgen</a> href="./html/index.html">doxygen</a>
</p> </p>
<h2>pvDatabaseCPP</h2>
<h3>include/pv</h3>
<p>The header files that describe the various components implemented by pvDatabase.
</p>
<dl>
<dt>pvDatabase.h</dt>
<dd>
This describes PVRecord and PVDatabase.
</dd>
<dt>channelProviderLocal.h </dt>
<dd>
This describes a channel provider for PVDatabase
</dd>
<dt>pvSupport.h</dt>
<dd>
This is the base class for support attached to a field of a record.
</dd>
<dt>controlSupport.h</dt>
<dd>
This is support that implements control limits.
</dd>
<dt>scalarAlarmSupport.h</dt>
<dd>
This is support for a alarm limits for a scalar numeric field.
</dd>
<dt>processRecord.h</dt>
<dd>
This is a PVRecord that periodical processes a set of PVRecords in the local PVDatabase.
</dd>
<dt>addRecord.h</dt>
<dd>
This is a PVRecord that adds a new PVRecord to the local PVDatabase.
</dd>
<dt>removeRecord.h</dt>
<dd>
This is a PVRecord that removes a PVRecord in the local PVDatabase.
</dd>
<dt>traceRecord.h</dt>
<dd>
This is a PVRecord that sets the trace value for another PVRecord in the local PVDatabase.
</dd>
<dt>pvStructureCopy.h</dt>
<dd>
This is a facility that allows a client to access a subfield of the fields in a PVRecord.
It also provides record and field options an plugin support.
</dd>
<dt>pvPlugin.h</dt>
<dd>
This is the base class for a plugin attached to a record or field of PVRecord.
</dd>
<dt>pvArrayPlugin.h</dt>
<dd>
A plugin for accessing a subset of the elements in an array field.
</dd>
<dt>pvDeadbandPlugin.h</dt>
<dd>
A deadband plugin for monitors.
</dd>
<dt>pvTimestampPlugin.h</dt>
<dd>
A plugin for timeStamp.
</dd>
</dl>
<h3>src/database</h3>
<p>This has the code that implements pvDatabase and pvRecord.</p>
<h3>src/pvAccess</h3>
<p>This has the code for the channel provider for pvDatabase.
</p>
<h3>src/support</h3>
<p>This has the pvSupport code.</p>
<h3>src/special</h3>
<p>
This has the code for processRecord, addRecord, removeRecord, and traceRecord.
</p>
<h3>src/copy</h3>
<p>This has the code for pvStructureCopy and all the plugin support.
</p>
<h2>exampleCPP</h2> <h2>exampleCPP</h2>
<p>Example code is available as part of this release. <p>Example code is available at
<a <a
href="https://github.com/epics-base/exampleCPP"> href="https://github.com/epics-base/exampleCPP">
exampleCPP exampleCPP
</a> </a>
</p> </p>
<p>In particular look at the example code mentioned in the following sub-sections. <p>In particular look at database, exampleLink, and helloPutGet.
</p> </p>
<h3>database</h3> </div> <!-- class="contents" -->
<p>This has many examples of how to create both soft records and records that implement
other functionality.</p>
<dl>
<dt>exampleDatabase.cpp</dt>
<dd>
This shows how to create soft records of each pvData type.<br />
In addition shows how to create instances of the following two records.
</dd>
<dt>exampleHelloRecord.cpp</dt>
<dd>
This is a simple "hello world" that is intentended to be used via a channelPutGet request.
</dd>
<dt>exampleHelloRPC.cpp</dt>
<dd>
This is a simple "hello world" that is intentended to be used via a channelRPC request.
</dd>
<dt>exampleDatabaseMain.cpp</dt>
<dd>
This shows how to create a standalone IOC.
</dd>
<dt>ioc and iocBoot</dt>
<dd>
This has code and examples to create a V3 IOC which also has a PVDatabase.
</dd>
</dl>
<h3>exampleLink</h3>
<p>This shows how to implement a record that has a link to another record</p>
<dl>
<dt>exampleMonitorLinkRecord</dt>
<dd>
This creates a monitor link to another record.
</dd>
<dt>exampleGetLinkRecord</dt>
<dd>
This creates a get link to another record.
</dd>
<dt>examplePutLinkRecord</dt>
<dd>
This creates a put link to another record.
</dd>
</dl>
<h3>support</h3>
<p>This creates records that have the following features:</p>
<dl>
<dt>value</dt>
<dd>
Each record has a value field the is a numeric scalar field.
In addition each has the following fields:
alarm,timeStamp,control,scalarAlarm, and display.
</dd>
<dt>support</dt>
<dd>
Each record uses the control and scalarAlarm support provided by pvDatabaseCPP.
</dd>
</dl>
<p>
It also creates records that can be used by clients to show example of the plugin support.
</p>
<h2>iocshell commands</h2>
<p>Shell commands are made available via the standard DBD include mechanism
provided by iocCore.
The following provide EPICS V4 shell commands:</p>
<pre>
pvAccessCPP
qsrv
pvDatabaseCPP
</pre>
<p>pvDatabaseCPP provides the following iocshell command.</p>
<dl>
<dt>registerChannelProviderLocal</dt>
<dd>Including <b>registerChannelProviderLocal.dbd</b> as a dbd file automatically starts provider local
and also creates the pvdbl shell command.
</dd>
<dt>pvdbl</dt>
<dd>Provides a list of all the pvRecords in database <b>master</b>
</dd>
</dl>
<p>In addition any code that implements a PVRecord must implement an ioc command.
Look at the examples in <b>exampleCPP/support</b> to see how to implement shell commands.</p>
</div>
</body> </body>
</html> </html>

View File

@ -362,6 +362,12 @@ public:
* @return true if client can write * @return true if client can write
*/ */
virtual bool canWrite(); virtual bool canWrite();
/**
* @brief determines if client can read
*
* @return true if client can read
*/
virtual bool canRead();
protected: protected:
shared_pointer getPtrSelf() shared_pointer getPtrSelf()
{ {

View File

@ -328,6 +328,13 @@ void ChannelGetLocal::get()
{ {
ChannelGetRequester::shared_pointer requester = channelGetRequester.lock(); ChannelGetRequester::shared_pointer requester = channelGetRequester.lock();
if(!requester) return; if(!requester) return;
ChannelLocalPtr channel(channelLocal.lock());
if(!channel) throw std::logic_error("channel is deleted");
if(!channel->canRead()) {
Status status = Status::error("ChannelGet::get is not allowed");
requester->getDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
return;
}
PVRecordPtr pvr(pvRecord.lock()); PVRecordPtr pvr(pvRecord.lock());
if(!pvr) throw std::logic_error("pvRecord is deleted"); if(!pvr) throw std::logic_error("pvRecord is deleted");
try { try {
@ -489,6 +496,13 @@ void ChannelPutLocal::get()
{ {
ChannelPutRequester::shared_pointer requester = channelPutRequester.lock(); ChannelPutRequester::shared_pointer requester = channelPutRequester.lock();
if(!requester) return; if(!requester) return;
ChannelLocalPtr channel(channelLocal.lock());
if(!channel) throw std::logic_error("channel is deleted");
if(!channel->canRead()) {
Status status = Status::error("ChannelPut::get is not allowed");
requester->getDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
return;
}
PVRecordPtr pvr(pvRecord.lock()); PVRecordPtr pvr(pvRecord.lock());
if(!pvr) throw std::logic_error("pvRecord is deleted"); if(!pvr) throw std::logic_error("pvRecord is deleted");
try { try {
@ -522,7 +536,7 @@ void ChannelPutLocal::put(
ChannelLocalPtr channel(channelLocal.lock()); ChannelLocalPtr channel(channelLocal.lock());
if(!channel) throw std::logic_error("channel is deleted"); if(!channel) throw std::logic_error("channel is deleted");
if(!channel->canWrite()) { if(!channel->canWrite()) {
Status status = Status::error("Channel put is not allowed"); Status status = Status::error("ChannelPut::put is not allowed");
requester->putDone(status,getPtrSelf()); requester->putDone(status,getPtrSelf());
return; return;
} }
@ -689,9 +703,9 @@ void ChannelPutGetLocal::putGet(
if(!requester) return; if(!requester) return;
ChannelLocalPtr channel(channelLocal.lock()); ChannelLocalPtr channel(channelLocal.lock());
if(!channel) throw std::logic_error("channel is deleted"); if(!channel) throw std::logic_error("channel is deleted");
if(!channel->canWrite()) { if(!channel->canWrite()||!channel->canRead() ) {
Status status = Status::error("Channel putGet is not allowed"); Status status = Status::error("ChannelPutGet::putGet is not allowed");
requester->putGetDone(status,getPtrSelf(),pvGetStructure,getBitSet); requester->putGetDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
return; return;
} }
PVRecordPtr pvr(pvRecord.lock()); PVRecordPtr pvr(pvRecord.lock());
@ -722,6 +736,13 @@ void ChannelPutGetLocal::getPut()
{ {
ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock(); ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock();
if(!requester) return; if(!requester) return;
ChannelLocalPtr channel(channelLocal.lock());
if(!channel) throw std::logic_error("channel is deleted");
if(!channel->canRead()) {
Status status = Status::error("ChannelPutGet::getPut is not allowed");
requester->getPutDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
return;
}
PVRecordPtr pvr(pvRecord.lock()); PVRecordPtr pvr(pvRecord.lock());
if(!pvr) throw std::logic_error("pvRecord is deleted"); if(!pvr) throw std::logic_error("pvRecord is deleted");
try { try {
@ -749,6 +770,13 @@ void ChannelPutGetLocal::getGet()
{ {
ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock(); ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock();
if(!requester) return; if(!requester) return;
ChannelLocalPtr channel(channelLocal.lock());
if(!channel) throw std::logic_error("channel is deleted");
if(!channel->canRead()) {
Status status = Status::error("ChannelPutGet::getGet is not allowed");
requester->getPutDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
return;
}
PVRecordPtr pvr(pvRecord.lock()); PVRecordPtr pvr(pvRecord.lock());
if(!pvr) throw std::logic_error("pvRecord is deleted"); if(!pvr) throw std::logic_error("pvRecord is deleted");
try { try {
@ -1325,9 +1353,15 @@ bool ChannelLocal::canWrite()
return false; return false;
} }
bool ChannelLocal::canRead()
{
if(!asActive || (asClientPvt && asCheckGet(asClientPvt))) {
return true;
}
return false;
}
ChannelLocal::~ChannelLocal() ChannelLocal::~ChannelLocal()
{ {
// cout << "~ChannelLocal()" << endl;
if(asMemberPvt) { if(asMemberPvt) {
asRemoveMember(&asMemberPvt); asRemoveMember(&asMemberPvt);
asMemberPvt = 0; asMemberPvt = 0;