"OPC-UA" modules of "Data acquisition" and "Transport protocols" subsystems
Parameter
Module 1
Module 2
Library
ID:
OPC_UA
OPC_UA
libOPC_UA
Name:
Client OPC-UA
Server OPC-UA
Library of implementing OPC-UA into OpenSCADA
Type:
DAQ
Protocol
Library
Source:
daq_OPC_UA.so
daq_OPC_UA.so
libOPC_UA.{h,cpp}
Version:
1.6
1.8
1.2
Author:
Roman Savochenko, Maxim Lysenko (2010)
Description:
Provides OPC-UA client service implementation.
Provides OPC-UA server service implementation.
Provides the protocol OPC-UA implementing into parts of client and server, as a separated library.
License:
GPL2
GPL2
LGPL3
Introduction
OPC (OLE for Process Control) it is the family of protocols and technologies that provide the single interface to control the objects of automation and technological processes. The creating and support of specifications of OPC coordinates an international nonprofit organization OPC Foundation, established in 1994 by the leading manufacturers of industrial automation.
In view of the fact that a significant influence in the OPC Foundation organization has the Microsoft corporation, OPC protocols, until recently, was single platform and closed, due to binding to the closed technologies of MS Windows. However, more recently, the OPC Foundation organization has created multi-platform solutions such as OPC XML-DA and OPC-UA. Most interesting of them is the OPC-UA, as a solution unifying all the earlier protocols in an open and multi-platform technologies.
This module implements the interface and protocol support for OPC-UA in the form of client service, and as the OPC-UA server. Client service of OPC-UA is implemented by the same name module of the subsystem "Data acquisition", and the server is implemented by the subsystem's "Protocols" module. The OPC-UA protocol's specific implementing code by the module was moved to a separated library under the LGPL3 license, by the users requests.
In the current version of these modules and the library it is implemented the binary part of the protocol and basic services in unsafe mode and safe mode of policies "Base128Rsa15" and "Base256". Later it is planned to extend the module to work via HTTP/SOAP and implementation of other OPC-UA services.
Although the OPC-UA protocol is multi-platform, its specification and SDK are not freely available, but are provided only to members of the OPC Foundation organization. For this reason, the implementation of these modules has faced significant obstacles and problems.
Firstly, the protocol OPC-UA is complex and its realization in general without specification an extremely laborious. For this reason, the work on these modules for a long time was not started, and only thanks to sponsorship by an organization-member of OPC Foundation the OpenSCADA project received documentation of the specification. The SDK and source code ANSIC-API of the OPC-UA protocol have not been received due to their incompatibility with the GPL license and as a consequence, the potential threat of violation of the license when working with the source code, which could lead to subsequent legal problems with the free distribution of these modules.
Secondly, even the presence of the specification does not allow to solve some technical question without an example of implementation and possibility of test the working prototype of the client and server of OPC-UA. For example, it is the technical features of the implementation of symmetric encryption algorithms and the keys for them do not allowed to make the implementation of support for security policy at once.
To debug the operation of the modules the demonstration software of company Unified Automation was used, in consist of the OPC-UA client UAExpert and Server "OPC-UA Demo Server", from the SDK package. In view of the constantly developing process of same "UAExpert" client, as the OPC-UA specification implementing, it's new versions often have problems in work with the OPC-UA server from OpenSCADA. Generically the results of compatibility in work with clients and servers of the different developers you can get in the appendix.
1. The OPC-UA protocol
OPC-UA it is the platform-independent standard by means of which the systems and devices of various types can interact by sending messages between the client and the server through various types of networks. The protocol supports secure communication through the validation of clients and servers, as well as the counteraction to attacks. OPC-UA defines the concept Services that the servers can provide, as well as services that the server supports for the client. Information is transmitted as the data types defined by OPC-UA and it producer, in addition the servers define object model, for which the clients can implement the dynamic review.
OPC-UA provides the combination of integrated address space with service model. This allows the server to integrate data alarms and events, the history in this address space, as well as provide access to them through the integrated services. Services also provide an integrated security model.
OPC-UA allows servers to provide for clients the definitions of types for access to the objects of the address space. OPC-UA supports the provision of data in various formats, including binary structures and XML-documents. Through the address space clients can request the server metadata that describe the data format.
OPC-UA appending the support for multiple connections between nodes instead of a simple hierarchy. Such flexibility in combination with types' definition allows to use OPC-UA for solving problems in the wide problem area.
OPC-UA is designed to provide the reliable output of data. Main feature of all OPC servers the ability to issue the data and events.
OPC-UA is designed to support the wide range of servers, from simple PLC to industrial servers. These servers are characterized by the wide range of sizes, performance, platforms and functional capacity. Consequently, the OPC-UA defines the comprehensive set of possibilities, and the server can implement the subset of these possibilities. To compatibility ensure the OPC-UA defines subsets, named the Profiles that the server can indicate for agreement. Clients may subsequently make the review of server's profiles and make the interaction with the server, based on the profiles.
OPC-UA specification is designed as the core in the layer, isolated from the underlying computer technologies and network transports. This allows for OPC-UA if necessary to expand on the future technologies without excluding the framework of design. Currently, the specification defines two ways to data encode: XML/text and UA Binary. In addition, the two types of transport layer are defined: TCP and HTTP/SOAP.
OPC-UA is designed as the solution for migration from OPC clients and servers, which are based on Microsoft COM technologies. OPC COM servers (DA, HDA and A&E) can be easily reflected in the OPC-UA. Producers can independently make such migration or recommend users to use wrappers and converters between these protocols. OPC-UA unifies the previous models in the single address space with the single set of services.
2. Module of the server implementation
The server module contains an implementation code for the server part of the OPC-UA server services, in part of the OpenSCADA specific, and using the library in part of the OPC-UA specific. To construct the OPC-UA server it is enough to create an incoming transport, for ordinarily it is TCP-transport of module Sockets, and select in it the module of the protocol, and also configure although one endpoint node of the protocol module, about it bellow.
2.1. Service of requests on the OPC-UA protocol
Incoming requests to the module-protocol are processed by the module in accordance with configured endpoint nodes of OPC-UA (EndPoints) (Fig. 1).
Fig.1. Endpoint nodes of the protocol.
The endpoint node of the OPC-UA protocol is actually the server object of OPC-UA. Endpoint nodes in OPC-UA can be either local or remote. The local one is designed to provide resources of OpenSCADA station to protocol OPC-UA, while the remote endpoint nodes are both for the service and review of available OPC-UA units, and to forwarding of the requests to remote stations. In this version of the module is only supported the configuration of the local endpoint nodes.
General configuration of the endpoint node is made on the main tab of the endpoint node's page (Fig. 2) with parameters:
Node status, as follow: Status, "Enable" and the name of the database containing the configuration.
ID, name and description of the node.
State, in which to transfer the node at the start: "Enable".
Type of the protocol encoding. At the moment it is only "Binary".
URL of the endpoint node.
Server certificate in the PEM format.
Private key in the PEM format.
Security Server Policy.
Fig.2. Main tab of the endpoint node's page.
3. Module of the data acquisition
The data acquisition module provides ability of acquisition and writing the value's attributes (13) of points with the "Variable" type.
3.1. Data controller's object
To append the OPC-UA data source the controller's object into the OpenSCADA system is created and configured. An example of the configuration tab of the controller's object is shown in Figure 3.
Fig.3. Controller's object configuration tab.
From this tab you can set:
The state controller, as follow: Status, "Enable", "Run" and the name of the database containing the configuration.
ID, name and description of the controller.
State, in which to transfer the controller at start: "Enable", "Run".
Name of the table to store the configuration of parameters of the controller.
Scheduling policy and priority of the task of the data acquisition.
Period of synchronization of the configuration of attributes of the parameters with the remote station, and try time for the connection restore.
URL of the endpoint node of the remote station OPC-UA server. In begin the address you can point in view "opc.tcp://{IP|name}:{port}", after that, at the controller's object enable and allowing the pointed OPC-UA node will emerge to select the refined address.
Often there meets a situation when the refined address is symbolic which does not resolve into the network by the server incorrect configuration. In this cases you need to keep the original IP-address or the name which resolved to the correct IP.
Security policy and mode of the messaging security.
Client certificate and private key in the PEM format.
User and password to authenticate on the server. Empty value here enable the anonymous access.
Limit to number of attributes into the parameter.
To facilitate the identification of nodes on the remote station, as well as their choice to be inserted in the parameter of the controller in the controller's object it is provided the navigation on the remote station's nodes tab, where you can walk through the tree of objects and familiar with their attributes (Figure 4).
Fig.4. The "Server nodes browser" tab of the controller's object page.
3.2. Parameters
The data acquisition module provides only one type of parameters "Standard". Additional configuration field of the parameter of the module (Fig. 5) is the list of OPC-UA nodes and the field of navigation by OPC-UA nodes in single line, for the selected nodes of type "Variable" insertion to the defined list. Attribute in this list is written as follows: {ns}:{id}.
Where:
ns name space, number; zero value can be omitted; id node identifier by number, string, bytes string and GUID.
Examples:
84 root directory; 3:"BasicDevices2" basic devices node in the name space 3 and the string view; 4:"61626364" node in the names space 4 and the byte string view; 4:{40d95ab0-50d6-46d3-bffd-f55639b853d4} node in the names space 4 and the GUID view.
Fig.5. Configuration tab of the parameter's object.
Nodes in type "Variable" with the value view as a structure are impossible typically to read entirely then you need it's elements insert separately to the reading nodes list.
In accordance with the specified list of nodes performs acquisition and creation of the parameter's attributes (Fig. 6).
Fig.6. The parameter's attributes tab.
4. libOPC_UA library
Grounding on workouts of the module the protocol OPC-UA code was moved to different library and published on the LGPLv3 license. That was done to provide possibility of easy appending of support the OPC-UA protocol by external projects. The library represents by two files libOPC_UA.h, libOPC_UA.cpp; supported and hosted into the module content, then it's last version you can get here: http://oscada.org/svn/trunk/OpenSCADA/src/moduls/daq/OPC_UA/libOPC_UA.
The library, like this module code, wrote on C++ programming language. Statical classes diagram which represents the library architecture shown on Figure 7. According to the classes diagram the library implemented into the name space "OPC" and architecturally it can be divided to client "Client" and server "Server" parts which inherited from common class "UA". Besides the direct classes of the protocol "OPC-UA" the library includes to self a set of functions and classes for processing or storing the protocol data, specialty from which it should be noted class of a node of language XML "XML_N" used for requests to the library API unification.
Fig.7. Statical class diagram of the library libOPC_UA.
The library using at all lies in inheriting of the class "Client" and/or "Server", according to the end-program functions, and next implementing of the virtual function for the client/server properties, into the OPC-UA protocol context and the transport communication part, that is connect/open a TCP-socket and write/read of unstructured data stream. Next requests and the requested data processing (for server) performed through the function call reqService(), request to a service, and/or processing of the virtual function reqData() of a data requesting then in fact there is integration to the data model of the application.
4.1. Service objects, functions and the class UA
Data
Implementations types (enum SerializerType):
ST_Binary = 0 binary.
Open secure channel request's type (enum SC_ReqTP):
SC_ISSUE = 0 issue;
SC_RENEW = 1 renewal.
Security mode of message (enum MessageSecurityMode):
MS_None = 1 without a security;
MS_Sign = 2 sign;
MS_SignAndEncrypt = 3 sign and encrypt;
Type of authentication (enum AuthTp):
A_Anon = 0 anonymous;
A_UserNm = 1 user+password;
A_Cert = 2 certificate.
Node classes (enum NodeClasses):
NC_Object = 1 object;
NC_Variable = 2 variable;
NC_Method = 4 method;
NC_ObjectType = 8 object type;
NC_VariableType = 16 variable type;
NC_ReferenceType = 32 reference type;
NC_DataType = 64 data type;
NC_View = 128 view.
Browse direction (enum BrowseDirection):
BD_FORWARD = 0 forward;
BD_INVERSE = 1 inverse;
BD_BOTH = 2 forward and inverse.
Time stamp to return (enum TimestampsToReturn):
TS_SOURCE = 0 source;
TS_SERVER = 1 server;
TS_BOTH = 2 source and server;
TS_NEITHER = 3 neither.
Access (enum Access):
ACS_Read = 0x01 read;
ACS_Write = 0x02 write;
ACS_HistRead = 0x04 history read;
ACS_HistWrite = 0x08 history write;
ACS_SemChange = 0x10 ?.
References description result mask (enum RefDscrResMask):
RdRm_RefType = 0x01 reference type;
RdRm_IsForward = 0x02 is forward;
RdRm_NodeClass = 0x04 node class;
RdRm_BrowseName = 0x08 browse name;
RdRm_DisplayName = 0x10 display name;
RdRm_TypeDef = 0x20 type of reference.
Identificators of attribute of node (enum AttrIds):
Aid_Error = 0 error;
AId_NodeId = 1 node identifier;
AId_NodeClass = 2 node class;
AId_BrowseName = 3 browse name;
AId_DisplayName = 4 display name;
AId_Descr = 5 description;
AId_WriteMask = 6 write access mask;
AId_UserWriteMask = 7 write access mask of user;
To the library included range of external functions of the object TSYS of OpenSCADA core to make simply and unified of the internal operations range:
int64_t curTime( ); Current time in microseconds from the Unix epoch (01.01.1970).
string int2str( int val ); Conversion of the signed integer to string, into the decimal representing.
string uint2str( unsigned val ); Conversion of the unsigned integer to string, into the decimal representing.
string ll2str( int64_t val ); Conversion of the signed long integer (64bit) to string, into the decimal representing.
string real2str( double val, int prec = 15, char tp = 'g' ); Conversion of the real value in double precision with precision prec of signs and type tp to string.
string strParse( const string &path, int level, const string &sep, int *off = NULL, bool mergeSepSymb = false ); String path parsing to the components, which separated by sep, in single symbols merging mergeSepSymb, starting from the offset off and with control to the item's offset end in self.
string strMess( const char *fmt, ... ); String forming by template fmt and the arguments. Base on "printf" implemented.
Automatic POSIX mutex unlock object for OPC (OPCAlloc)
The mutex management object is a copy of the "MtxAlloc" object of core OpenSCADA.
Public methods:
OPCAlloc( pthread_mutex_t &iM, bool ilock = false ); Initialization of automatic unlock mutex for early allocated one iM. With the lock set at a creation.
int lock( ); The resource lock. Return zero at the success.
int unlock( ); The resource unlock. Return zero at the success.
//int tryLock( ); The resource try lock, without wait for free. Return zero at the success.
Error of OPC (OPCError)
The error object "OPCError" is a trimmed copy of the "TError" object of core OpenSCADA.
Public methods:
OPCError( const char *fmt, ... ); Typical error's constructor, without a code.
OPCError( int cod, const char *fmt, ... ); Typical error's constructor, with the code cod.
Public attributes:
int cod; Error code.
string mess; Error text.
XML-tag (XML_N)
The object "XML_N" is trimmed copy of the object API#h921-2 of OpenSCADA core.
Public methods:
XML_N( const string &name = "" ); Initialization of the tag with the name.
XML_N( const XML_N &nd ); Copy constructor.
XML_N &operator=( const XML_N &prm ); Copying a branch of the XML-tree from prm.
string name( ) const; Tag's name.
XML_N* setName( const string &s ); Setting the tag's name to s.
string text( bool childs = false, bool recursive = false ) const; Tag's text. childs for text getting from special text nodes.
XML_N* setText( const string &s, bool childs = false ); Setting the tag's text to s. childs for set text to special text node.
void attrList( vector<string> & list ) const; List of attributes in the tag.
XML_N* attrDel( const string &name ); Deleting of the attribute name.
void attrClear( ); Clean up the tag's attributes.
XML_N* setAttr( const string &name, const string &val ); Setting/creation of the attribute name with the value val.
XML_N* clear( ); Clear the tag (recursively, including all childs).
bool childEmpty( ) const; Check for empty included tags.
unsigned childSize( ) const; Number of included tags.
void childAdd( XML_N *nd ); XML_N* childAdd( const string &name = "" ); Adding the included tag.
int childIns( unsigned id, XML_N *nd ); Insert of the included tag nd to the position id. Negative id counts from end.
XML_N* childIns( unsigned id, const string &name = "" ); Insert of the included tag with the name name to the position id. Negative id counts from end.
void childDel( const unsigned id ); Deleting of the included tag id. Negative id counts from end.
void childDel( XML_N *nd ); Deleting of the included tag using its address nd.
void childClear( const string &name = "" ); Clean up of the included tag name.
XML_N* childGet( const int, bool noex = false ) const; Getting the included tag by its index number.
XML_N* childGet( const string &name, const int numb = 0, bool noex = false ) const; Getting of the included numb indexed tag by the tag's name name. noex indicates the prohibition of the generation of exception in the case of absence of the tag.
XML_N* childGet( const string &attr, const string &name, bool noex = false ) const; Getting the included numb indexed tag by its value name of the attribute attr. noex indicates the prohibition of the generation of exception in the case of absence of the tag.
XML_N* getElementBy( const string &attr, const string &val ); Included node search by the value val of the attribute attr.
XML_N* parent( ); Parent tag of the tag.
XML_N* root( ); Root tag of the tag.
Node's object of OPC-UA (NodeId)
Data:
Data types (enum NodeId::Type):
NodeId::Numeric number.
NodeId::String string.
NodeId::Guid global unique identifier.
NodeId::Opaque opaque.
Public methods:
NodeId( uint32_t in, uint16_t ins = 0 ); Numerical initial constructor, for number in in the namespace ins.
NodeId( const string &istr, uint16_t ins = 0, Type tp = String ); String initial constructor, for string istr into the namespace ins, with the type tp.
NodeId( const NodeId &node ); The object copy constructor.
virtual uint32_t rcvBufSz( ); receiver buffer size, great for 8192.
virtual uint32_t sndBufSz( ); transmitter buffer size, great for 8192.
virtual uint32_t msgMaxSz( ); maximum message size, 0 for unlimited.
virtual uint32_t chunkMaxCnt( ); maximum chunks counter, 0 for unlimited.
static string iErr( const string &buf, int &off ); error reading from the stream buf by the offset off.
static const char *iVal( const string &buf, int &off, char vSz ); value in size vSz reading, as a data part, from the stream buf by the offset off.
static int64_t iN( const string &rb, int &off, char vSz ); value of signed integer in size vSz (1, 2, 4, 8) reading from the stream rb by the offset off.
static uint64_t iNu( const string &rb, int &off, char vSz ); value of unsigned integer in size vSz (1, 2, 4, 8) reading from the stream rb by the offset off.
static double iR( const string &rb, int &off, char vSz = 4 ); value of real in size vSz (4, 8) reading from the stream rb by the offset off.
static string iS( const string &buf, int &off ); string reading from the stream buf by the offset off.
static string iSl( const string &buf, int &off, string *locale = NULL ); localized locale string reading from the stream buf by the offset off.
static string iSqlf( const string &buf, int &off, uint16_t *nsIdx = NULL ); string with the qualify nsIdx reading from the stream buf by the offset off.
static int64_t iTm( const string &buf, int &off ); time reading, with conversion it to the UNIX epoch, from the stream buf by the offset off.
static NodeId iNodeId( const string &buf, int &off ); node identifier reading from the stream buf by the offset off.
static string iVariant( const string &buf, int &off, uint8_t *tp = NULL ); variant type reading from the stream buf by the offset off. Returns the variant in string representing of type tp.
static void iDataValue( const string &buf, int &off, XML_N &nVal ); complex value (structure DataValue) reading to nVal from the stream buf by the offset off.
static void oN( string &buf, int64_t val, char sz, int off = -1 ); value of signed integer val in size sz (1, 2, 4, 8) writing to the stream buf by the offset off.
static void oNu( string &buf, uint64_t val, char sz, int off = -1 ); value of unsigned integer val in size sz (1, 2, 4, 8) writing to the stream buf by the offset off.
static void oR( string &buf, double val, char sz = 4 ); value of real val in size sz (4, 8) writing to the stream buf by the offset off.
static void oS( string &buf, const string &val, int off = -1 ); string val writing to the stream buf by the offset off.
static void oSl( string &buf, const string &val, const string &locale = "" ); localized locale string val writing to the stream buf by the offset off.
static void oSqlf( string &buf, const string &val, uint16_t nsIdx = 0 ); string val with the qualify nsIdx writing to the stream buf by the offset off.
static void oTm( string &buf, int64_t val ); time val, in the UNIX epoch, writing to the stream buf by the offset off.
static void oNodeId( string &buf, const NodeId &val ); node identifier val writing to the stream buf by the offset off.
static void oRef( string &buf, uint32_t resMask, const NodeId &nodeId, const NodeId &refTypeId, bool isForward, const string &name, uint32_t nodeClass, const NodeId &typeDef ); writing to the stream buf of browsing description (structure ReferenceDescription) for the result mask resMask, the node nodeId, the reference type refTypeId, the forward direction isForward, the name name, the node class nodeClass, the definition type typeDef.
void oDataValue( string &buf, uint8_t eMsk, const string &vl, uint8_t vEMsk = 0, int64_t srcTmStmp = 0 ); complex value (structure DataValue) writing to the stream buf for the encoding mask eMsk, the value vl, the value mask vEMsk, the source time srcTmStmp.
static string randBytes( int num ); random data stream generation in the number num.
static string certPEM2DER( const string &certPem ); certificate conversion from PEM certPem to DER form.
static string certDER2PEM( const string &certDer ); certificate conversion from DER certDer to PEM form.
static string certThumbprint( const string &certPem ); sign getting from the certificate PEM certPem.
static string asymmetricEncrypt( const string &mess, const string &certPem, const string &secPolicy ); asymmetric encryption of the message mess stream by the certificate certPem (by the open key) for the policy secPolicy.
static string asymmetricDecrypt( const string &mess, const string &pvKeyPem, const string &secPolicy ); asymmetric decryption of the message mess stream by the key pvKeyPem for the certificate secPolicy.
static bool asymmetricVerify( const string &mess, const string &sign, const string &certPem ); asymmetric verifying of the sign of the message mess by the certificate certPem.
static string asymmetricSign( const string &mess, const string &pvPem ); asymmetric subscription getting by the private key of the certificate pvPem for the message mess.
static int asymmetricKeyLength( const string &keyCertPem ); key's length of the certificate keyCertPem getting.
static string deriveKey( const string &secret, const string &seed, int keyLen ); key of the length keyLen derive from the secret and the seed.
static string symmetricEncrypt( const string &mess, const string &keySet, const string &secPolicy ); symmetric encryption of the message mess stream by the key keySet for the policy secPolicy.
static string symmetricDecrypt( const string &mess, const string &keySet, const string &secPolicy ); symmetric decryption the message mess stream by the key keySet for the policy secPolicy.
static string symmetricSign( const string &mess, const string &keySet, const string &secPolicy ); symmetric sign by key keySet getting for the message mess and the policy secPolicy.
Security parameters included object (SecuritySetting)
Public data:
string policy security policy;
MessageSecurityMode messageMode message mode;
Public methods:
SecuritySetting( const string &iplc, int8_t imMode ) object constructor for the security policy iplc and the messages mode imMode.
SecuritySetting( ) object constructor with the security policy "None" and the messages mode MS_None.
4.2. Client's main object (Client->UA)
Application: Direct inheritance by a user object OPC-UA client.
virtual void clientRcvBufSzSet( const string &inPrtId, uint32_t vl ) = 0; set taken from client receiver buffer size to vl, for the connection inPrtId.
virtual void clientSndBufSzSet( const string &inPrtId, uint32_t vl ) = 0; set taken from client transmitter buffer size to vl, for the connection inPrtId.
virtual void clientMsgMaxSzSet( const string &inPrtId, uint32_t vl ) = 0; set taken from client maximum message size to vl, for the connection inPrtId.
virtual void clientChunkMaxCntSet( const string &inPrtId, uint32_t vl ) = 0; set taken from client maximum chunks counter to vl, for the connection inPrtId.
int chnlSet( int cid, const string &iEp, int32_t lifeTm = 0, const string& iClCert = "", const string &iSecPolicy = "None", char iSecMessMode = 1, const string &iclAddr = "", uint32_t iseqN = 1 ); security channel setting with the identifier cid (nonzero value for updating) for the endpoint iEp, the lifetime lifeTm, the client certificate iClCert, the security policy iSecPolicy, the messages security mode iSecMessMode, the client address iclAddr, the package's sequence number iseqN.
void chnlClose( int cid ); security channel cid closing.
SecCnl chnlGet( int cid ); SecCnl &chnlGet_( int cid ); security channel's cid access and it's copy getting.
void chnlSecSet( int cid, const string &servKey, const string &clKey ); security channel cid setting to the keys of server servKey and client clKey.
static string mkError( uint32_t errId, const string &err = "" ); error forming for the identifier errId and the message err.
Protected methods:
virtual void epEnList( vector<string> &ls ) = 0; handler of request to list of endpoint nodes.
virtual EP *epEnAt( const string &ep ) = 0; handler of request to the endpoint object.
Security channel included object (SecCnl)
Public methods:
SecCnl( const string &iEp, uint32_t iTokenId, int32_t iLifeTm, const string &iClCert, const string &iSecPolicy, char iSecMessMode, const string &iclAddr, uint32_t isecN ); security channel object constructor for: the endpoint iEp, the security token iTokenId, the lifetime iLifeTm, the client's certificate iClCert, the security policy iSecPolicy, the message's security mode iSecMessMode, the client's address iclAddr, the sequence number isecN of creation the security channel.
Public attributes:
string endPoint; endpoint;
string secPolicy; security policy;
char secMessMode; security mode of message;
int64_t tCreate; creation time;
int32_t tLife; lifetime;
uint32_t TokenId, TokenIdPrev; current and previous the tokens identifiers;
string clCert, clAddr; client's certificate and address;
string servKey, clKey; keys of the server and the client;
uint32_t servSeqN, clSeqN, startClSeqN; current server's, client's and start number of the package's sequence.
Session included object (Sess)
Public methods:
Sess( const string &iName, double iTInact ); the object constructor for name iName and timeout of the activity iTInact.
Browse's continuation point included object (ContPoint)
Public methods:
ContPoint( const string &i_brNode, const string &i_lstNode, uint32_t i_brDir, uint32_t i_refPerN, const string &i_refTypeId, uint32_t i_nClassMask, uint32_t i_resMask ) object of the continuation node's point i_brNode constructor, of the list node i_lstNode, of the direction browsing i_brDir, of the number of references i_refPerN to a node, of the reference identifier i_refTypeId, of the node class mask i_nClassMask and the result mask i_resMask.
bool empty( ) const; the continuation point is empty.
Public attributes:
uint32_t brDir, refPerN, nClassMask, resMask; browsing direction, references number to node, class mask of the node, results mask;
string brNode, lstNode, refTypeId; nodes branch, nodes list and the reference's type identifier.
Subscription included object (Subscr)
Public methods:
Subscr copy( bool noWorkData = true ); copy of the subscription object, without a work data noWorkData.
SubScrSt setState( SubScrSt st = SS_CUR ); state setting to st.
Public attributes:
SubScrSt st; subscription state;
int sess; subscription's session;
bool en; state "Enabled";
double publInterv; publish interval (ms);
uint32_t seqN; sequence number for responds, wrapped through 1, no increments at the KeepAlive messages;
uint32_t cntrLifeTime, wLT; counter at it exhausting and a message miss from client the server needs to the object erase;
uint32_t cntrKeepAlive, wKA; counter at it exhausting the server needs to send an empty publish respond and set the state StatusChangeNotification to Bad_Timeout;
uint32_t maxNotPerPubl; maximum number of the notifications to a single respond of publishing;
uint8_t pr; priority;
vector<MonitItem> mItems; monitoring elements list;
deque<string> retrQueue; retransmission queue, used by a retransmission queue request (Republish); cleaned up to depth accorded to the KeepAlive or a direct request into the acquire set.
Monitored item included object (MonitItem)
Public methods:
MonitoringMode md; monitoring mode;
NodeId nd; target node;
uint32_t aid; node's attribute identifier;
TimestampsToReturn tmToRet; timestamp to return;
double smplItv; sampling interval;
uint32_t qSz; queue size;
bool dO; to drop old;
uint32_t cH; client's handler;
XML_N fltr; filter;
int vTp; value type;
int64_t dtTm; last value time;
deque<Val> vQueue; values queue.
Value element included object (Val)
Public methods:
Val( const string &ivl, int64_t itm ) object constructor of the value ivl for the time tm.
Ļóįėč÷ķūå ąņščįóņū:
string vl; value;
int64_t tm; value time.
Endpoint included object (EP)
Public methods:
EP( Server *serv ); object constructor referred to the server serv.
virtual string id( ) = 0; identifier;
virtual string url( ) = 0; URL;
virtual string cert( ) = 0; certificate, by string in PEM form;
virtual string pvKey( ) = 0; private key, by string in PEM form;
virtual double subscrProcPer( ) = 0; common minimal period of the publishing and the data processing cycle;
virtual uint32_t limSubScr( ); limit to subscriptions number;
virtual uint32_t limMonitItms( ); limit to monitoring elements number;
virtual uint32_t limRetrQueueTm( ); time limit to the retransmission queue depth;
bool enableStat( ); state "Enabled";
virtual bool publishInPool( ) = 0; publish in the pool mode of transport, otherwise that is an external task;
virtual void setEnable( bool vl ); set to "Enabled";
virtual void setPublish( const string &inPrtId ); start a publish task or input request's pool of subScrCycle();
void subScrCycle( unsigned cntr, string *answ = NULL, const string &inPrtId = "" ); function of the subscriptions list processing call cycle in step cntr for answer into answ in the pool mode; inPrtId set to the input transport's (connection) subscriptions process into the pool mode or it is empty for all subscriptions processing into a specified task;
int secSize( ); security policies number;
string secPolicy( int isec ); getting of the security policy isec description;
MessageSecurityMode secMessageMode( int isec ); messages security mode for the security policy isec;
int sessCreate( const string &iName, double iTInact ); session creation with the name iName and the inactivity timeout iTInact, returns the session identifier;
void sessServNonceSet( int sid, const string &servNonce ); session's sid of the server the security sequence setting to servNonce;
virtual uint32_t sessActivate( int sid, uint32_t secCnl, bool check = false, const string &inPrtId = "", const XML_N &identTkn = XML_N() ); session sid activation for link to the security channel secCnl, with the checking check to possibility-need for reassigning, after closing of the previous security channel, returns error (0 - no an error);
void sessClose( int sid ); session sid close;
Sess sessGet( int sid ); getting of the session's sid object copy;
Sess::ContPoint sessCpGet( int sid, const string &cpId ); continuation point cpId of browsing getting for the session sid;
void sessCpSet( int sid, const string &cpId, const Sess::ContPoint &cp = Sess::ContPoint() ); continuation point cp of browsing setting for the session sid and the identifier cpId;
uint32_t subscrSet( uint32_t ssId, SubScrSt st, bool en = false, int sess = -1, double publInterv = 0, uint32_t cntrLifeTime = 0, uint32_t cntrKeepAlive = 0, uint32_t maxNotePerPubl = OpcUa_NPosID, int pr = -1 ); subscription ssId creation/setting for: the state st, the enabling en, the session sess, the publication interval publInterv, the counter of lifetime cntrLifeTime, the counter of keep "alive" cntrKeepAlive, the maximum number of notifications into single publication maxNotePerPubl, the priority pr;
Subscr subscrGet( uint32_t ssId, bool noWorkData = true ); subscription ssId copy getting, without a working data noWorkData;
uint32_t mItSet( uint32_t ssId, uint32_t mItId, MonitoringMode md = MM_CUR, const NodeId &nd = NodeId(), uint32_t aid = OpcUa_NPosID, TimestampsToReturn tmToRet = TimestampsToReturn(-1), double smplItv = -2, uint32_t qSz = OpcUa_NPosID, int8_t dO = -1, uint32_t cH = OpcUa_NPosID, XML_N *fltr = NULL ); element of monitoring item mItId creation/setting of the session ssId for: the mode md, the node nd, the attribute aid, the timestamp profile tmToRet, the sampling interval smplItv, the queue size qSz, the old dropping dO, the client handler cH, the filter fltr;
Subscr::MonitItem mItGet( uint32_t ssId, uint32_t mItId ); getting of copy of element of the monitoring item mItId for the session ssId;
virtual uint32_t reqData( int reqTp, XML_N &req ); data requests handler, the requests to the nodes tree of the server.
Protected methods:
XML_N *nodeReg( const NodeId &parent, const NodeId &ndId, const string &name, int ndClass, const NodeId &refTypeId, const NodeId &typeDef = 0 ); node ndId register into the nodes of the server tree for: of the parent parent, of the node class ndClass, of the reference type identifier refTypeId and the definition type typeDef;
Sess *sessGet_( int sid ); link to the session object sid getting, the access is not protected by a resource locking.
Protected attributes:
char mEn; state "Enabled";
uint64_t cntReq; requests counter;
vector<SecuritySetting> mSec; list of security politics of the endpoint node;
vector<Sess> mSess; list of the opened sessions;
vector<Subscr> mSubScr; list of subscriptions;
XML_N objTree; tree of nodes of the server;
map<string, XML_N*> ndMap; references map to nodes of the tree;
pthread_mutex_t> mtxData; mutex for multithreads access lock;
Server *serv; reference to the server, container of the endpoint's object.
5. Private keys and certificates
For the client and server parts of OPC-UA working you need to create and to place the private key and the certificate into configuration of client or server object. In general be enough to create an ordinal selfsigned certificate and a private key without password, but for exclude warning messages you need to add range of service fields to to the certificate. That you can do taking the file of configuration of the certificate creation and executing next procedure:
6. Notes
During implementation of the modules of supporting OPC-UA was detected several inconsistencies with the official SDK specification OPC-UA:
OPC-UA Part 6 on page 27 contains an image of a handshake to establish a secure channel. The creation message of session signed by a symmetric key of the client and encrypted by server's. In fact, both signature and encryption of the server key made.
OPC-UA Part 4 on page 141 contains a description of the data structure signatures, where first goes the data signature, and then the string algorithm. In fact, the reverse order is implemented here.
7. Appending: Table of compatibility of implementations of OPC-UA from other developers
Software
Core
Browse
Read
Write
Publish
Notes
OpenSCADA parts
OpenSCADA OPC-UA Client (libOPC_UA client part)
+
+
+
+
-
IO requests by XML implemented: HEL (HELLO), OPN (OpenSecureChannel), CLO (CloseSecureChannel), FindServers, GetEndpoints, CreateSession, ActivateSession, CloseSession, Read, Write, Browse
Result mask processing fix into the service "Browse" for nodes of OpenSCADA data model. ...
Kepware
Pass
Pass
Pass
Pass
Pass
Specific value types OpcUa_IntAuto and OpcUa_UIntAuto was added for adaptive integer type selection, mostly for provide integer not fixed as int64. Time stamp was removed from "Write" package but the client tell 0x80730000(OpcUa_BadWriteNotSupported)
UAExpert 1.4
Pass
Pass
Pass
Pass
Pass
Packages sequence number split from it's request and set self managing.
Servers
IgnitionOPC_UA
Pass
Pass
Pass
Not tested
NA
B&R Embedded OPC-UA Server
Pass
Pass
Pass
Not tested
NA
The authenticate process fixed by the server provides self specific identifiers to its. The string of bytes wrong interpretation fixed.