blob: 340ddeb240e00e27dad25c0fda9e5c4b7eef7c88 [file] [log] [blame]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
* Copyright 2015-2016 (c) Sten GrĂ¼ner
* Copyright 2014-2015, 2017 (c) Florian Palm
* Copyright 2015-2016 (c) Chris Iatrou
* Copyright 2015-2016 (c) Oleksiy Vasylyev
* Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
*/
#ifndef UA_SERVER_H_
#define UA_SERVER_H_
#include <open62541/nodeids.h>
#include <open62541/types.h>
#include <open62541/types_generated.h>
#include <open62541/types_generated_handling.h>
_UA_BEGIN_DECLS
/* Forward declarations */
struct UA_ServerConfig;
typedef struct UA_ServerConfig UA_ServerConfig;
struct UA_Server;
typedef struct UA_Server UA_Server;
struct UA_Client;
/**
* .. _server:
*
* Server
* ======
*
* .. include:: server_config.rst
*
* .. _server-lifecycle:
*
* Server Lifecycle
* ---------------- */
UA_Server UA_EXPORT * UA_Server_new(void);
/* Makes a (shallow) copy of the config into the server object.
* The config content is cleared together with the server. */
UA_Server UA_EXPORT *
UA_Server_newWithConfig(const UA_ServerConfig *config);
void UA_EXPORT UA_Server_delete(UA_Server *server);
UA_ServerConfig UA_EXPORT *
UA_Server_getConfig(UA_Server *server);
/* Runs the main loop of the server. In each iteration, this calls into the
* networklayers to see if messages have arrived.
*
* @param server The server object.
* @param running The loop is run as long as *running is true.
* Otherwise, the server shuts down.
* @return Returns the statuscode of the UA_Server_run_shutdown method */
UA_StatusCode UA_EXPORT
UA_Server_run(UA_Server *server, const volatile UA_Boolean *running);
/* The prologue part of UA_Server_run (no need to use if you call
* UA_Server_run) */
UA_StatusCode UA_EXPORT
UA_Server_run_startup(UA_Server *server);
/* Executes a single iteration of the server's main loop.
*
* @param server The server object.
* @param waitInternal Should we wait for messages in the networklayer?
* Otherwise, the timouts for the networklayers are set to zero.
* The default max wait time is 50millisec.
* @return Returns how long we can wait until the next scheduled
* callback (in ms) */
UA_UInt16 UA_EXPORT
UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal);
/* The epilogue part of UA_Server_run (no need to use if you call
* UA_Server_run) */
UA_StatusCode UA_EXPORT
UA_Server_run_shutdown(UA_Server *server);
/**
* Timed Callbacks
* --------------- */
typedef void (*UA_ServerCallback)(UA_Server *server, void *data);
/* Add a callback for execution at a specified time. If the indicated time lies
* in the past, then the callback is executed at the next iteration of the
* server's main loop.
*
* @param server The server object.
* @param callback The callback that shall be added.
* @param data Data that is forwarded to the callback.
* @param date The timestamp for the execution time.
* @param callbackId Set to the identifier of the repeated callback . This can
* be used to cancel the callback later on. If the pointer is null, the
* identifier is not set.
* @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
* otherwise. */
UA_StatusCode UA_EXPORT
UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback,
void *data, UA_DateTime date, UA_UInt64 *callbackId);
/* Add a callback for cyclic repetition to the server.
*
* @param server The server object.
* @param callback The callback that shall be added.
* @param data Data that is forwarded to the callback.
* @param interval_ms The callback shall be repeatedly executed with the given
* interval (in ms). The interval must be positive. The first execution
* occurs at now() + interval at the latest.
* @param callbackId Set to the identifier of the repeated callback . This can
* be used to cancel the callback later on. If the pointer is null, the
* identifier is not set.
* @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
* otherwise. */
UA_StatusCode UA_EXPORT
UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
void *data, UA_Double interval_ms, UA_UInt64 *callbackId);
UA_StatusCode UA_EXPORT
UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
UA_Double interval_ms);
/* Remove a repeated callback. Does nothing if the callback is not found.
*
* @param server The server object.
* @param callbackId The id of the callback */
void UA_EXPORT
UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId);
#define UA_Server_removeRepeatedCallback(server, callbackId) \
UA_Server_removeCallback(server, callbackId);
/**
* Reading and Writing Node Attributes
* -----------------------------------
* The functions for reading and writing node attributes call the regular read
* and write service in the background that are also used over the network.
*
* The following attributes cannot be read, since the local "admin" user always
* has full rights.
*
* - UserWriteMask
* - UserAccessLevel
* - UserExecutable */
/* Read an attribute of a node. The specialized functions below provide a more
* concise syntax.
*
* @param server The server object.
* @param item ReadValueIds contain the NodeId of the target node, the id of the
* attribute to read and (optionally) an index range to read parts
* of an array only. See the section on NumericRange for the format
* used for array ranges.
* @param timestamps Which timestamps to return for the attribute.
* @return Returns a DataValue that contains either an error code, or a variant
* with the attribute value and the timestamps. */
UA_DataValue UA_EXPORT UA_THREADSAFE
UA_Server_read(UA_Server *server, const UA_ReadValueId *item,
UA_TimestampsToReturn timestamps);
/* Don't use this function. There are typed versions for every supported
* attribute. */
UA_StatusCode UA_EXPORT UA_THREADSAFE
__UA_Server_read(UA_Server *server, const UA_NodeId *nodeId,
UA_AttributeId attributeId, void *v);
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readNodeId(UA_Server *server, const UA_NodeId nodeId,
UA_NodeId *outNodeId) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODEID, outNodeId);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readNodeClass(UA_Server *server, const UA_NodeId nodeId,
UA_NodeClass *outNodeClass) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODECLASS,
outNodeClass);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readBrowseName(UA_Server *server, const UA_NodeId nodeId,
UA_QualifiedName *outBrowseName) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
outBrowseName);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readDisplayName(UA_Server *server, const UA_NodeId nodeId,
UA_LocalizedText *outDisplayName) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
outDisplayName);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readDescription(UA_Server *server, const UA_NodeId nodeId,
UA_LocalizedText *outDescription) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
outDescription);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readWriteMask(UA_Server *server, const UA_NodeId nodeId,
UA_UInt32 *outWriteMask) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
outWriteMask);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readIsAbstract(UA_Server *server, const UA_NodeId nodeId,
UA_Boolean *outIsAbstract) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
outIsAbstract);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readSymmetric(UA_Server *server, const UA_NodeId nodeId,
UA_Boolean *outSymmetric) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,
outSymmetric);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readInverseName(UA_Server *server, const UA_NodeId nodeId,
UA_LocalizedText *outInverseName) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
outInverseName);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readContainsNoLoop(UA_Server *server, const UA_NodeId nodeId,
UA_Boolean *outContainsNoLoops) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS,
outContainsNoLoops);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readEventNotifier(UA_Server *server, const UA_NodeId nodeId,
UA_Byte *outEventNotifier) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
outEventNotifier);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readValue(UA_Server *server, const UA_NodeId nodeId,
UA_Variant *outValue) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUE, outValue);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readDataType(UA_Server *server, const UA_NodeId nodeId,
UA_NodeId *outDataType) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DATATYPE,
outDataType);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readValueRank(UA_Server *server, const UA_NodeId nodeId,
UA_Int32 *outValueRank) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUERANK,
outValueRank);
}
/* Returns a variant with an int32 array */
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readArrayDimensions(UA_Server *server, const UA_NodeId nodeId,
UA_Variant *outArrayDimensions) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS,
outArrayDimensions);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readAccessLevel(UA_Server *server, const UA_NodeId nodeId,
UA_Byte *outAccessLevel) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
outAccessLevel);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId,
UA_Double *outMinimumSamplingInterval) {
return __UA_Server_read(server, &nodeId,
UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
outMinimumSamplingInterval);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readHistorizing(UA_Server *server, const UA_NodeId nodeId,
UA_Boolean *outHistorizing) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_HISTORIZING,
outHistorizing);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId,
UA_Boolean *outExecutable) {
return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
outExecutable);
}
/**
* The following node attributes cannot be changed once a node has been created:
*
* - NodeClass
* - NodeId
* - Symmetric
* - ContainsNoLoop
*
* The following attributes cannot be written from the server, as they are
* specific to the different users and set by the access control callback:
*
* - UserWriteMask
* - UserAccessLevel
* - UserExecutable
*/
/* Overwrite an attribute of a node. The specialized functions below provide a
* more concise syntax.
*
* @param server The server object.
* @param value WriteValues contain the NodeId of the target node, the id of the
* attribute to overwritten, the actual value and (optionally) an
* index range to replace parts of an array only. of an array only.
* See the section on NumericRange for the format used for array
* ranges.
* @return Returns a status code. */
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_write(UA_Server *server, const UA_WriteValue *value);
/* Don't use this function. There are typed versions with no additional
* overhead. */
UA_StatusCode UA_EXPORT UA_THREADSAFE
__UA_Server_write(UA_Server *server, const UA_NodeId *nodeId,
const UA_AttributeId attributeId,
const UA_DataType *attr_type, const void *attr);
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeBrowseName(UA_Server *server, const UA_NodeId nodeId,
const UA_QualifiedName browseName) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
&UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeDisplayName(UA_Server *server, const UA_NodeId nodeId,
const UA_LocalizedText displayName) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
&UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeDescription(UA_Server *server, const UA_NodeId nodeId,
const UA_LocalizedText description) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
&UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeWriteMask(UA_Server *server, const UA_NodeId nodeId,
const UA_UInt32 writeMask) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
&UA_TYPES[UA_TYPES_UINT32], &writeMask);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeIsAbstract(UA_Server *server, const UA_NodeId nodeId,
const UA_Boolean isAbstract) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
&UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeInverseName(UA_Server *server, const UA_NodeId nodeId,
const UA_LocalizedText inverseName) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
&UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeEventNotifier(UA_Server *server, const UA_NodeId nodeId,
const UA_Byte eventNotifier) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
&UA_TYPES[UA_TYPES_BYTE], &eventNotifier);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeValue(UA_Server *server, const UA_NodeId nodeId,
const UA_Variant value) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE,
&UA_TYPES[UA_TYPES_VARIANT], &value);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeDataType(UA_Server *server, const UA_NodeId nodeId,
const UA_NodeId dataType) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DATATYPE,
&UA_TYPES[UA_TYPES_NODEID], &dataType);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeValueRank(UA_Server *server, const UA_NodeId nodeId,
const UA_Int32 valueRank) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUERANK,
&UA_TYPES[UA_TYPES_INT32], &valueRank);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeArrayDimensions(UA_Server *server, const UA_NodeId nodeId,
const UA_Variant arrayDimensions) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS,
&UA_TYPES[UA_TYPES_VARIANT], &arrayDimensions);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeAccessLevel(UA_Server *server, const UA_NodeId nodeId,
const UA_Byte accessLevel) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
&UA_TYPES[UA_TYPES_BYTE], &accessLevel);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId,
const UA_Double miniumSamplingInterval) {
return __UA_Server_write(server, &nodeId,
UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
&UA_TYPES[UA_TYPES_DOUBLE],
&miniumSamplingInterval);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeHistorizing(UA_Server *server, const UA_NodeId nodeId,
const UA_Boolean historizing) {
return __UA_Server_write(server, &nodeId,
UA_ATTRIBUTEID_HISTORIZING,
&UA_TYPES[UA_TYPES_BOOLEAN],
&historizing);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_writeExecutable(UA_Server *server, const UA_NodeId nodeId,
const UA_Boolean executable) {
return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
&UA_TYPES[UA_TYPES_BOOLEAN], &executable); }
/**
* Browsing
* -------- */
/* Browse the references of a particular node. See the definition of
* BrowseDescription structure for details. */
UA_BrowseResult UA_EXPORT
UA_Server_browse(UA_Server *server, UA_UInt32 maxReferences,
const UA_BrowseDescription *bd);
UA_BrowseResult UA_EXPORT
UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
const UA_ByteString *continuationPoint);
/* Nonstandard version of the browse service that recurses into child nodes.
* Possible loops (that can occur for non-hierarchical references) are handled
* by adding every target node at most once to the results array. */
UA_StatusCode UA_EXPORT
UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd,
size_t *resultsSize, UA_ExpandedNodeId **results);
UA_BrowsePathResult UA_EXPORT UA_THREADSAFE
UA_Server_translateBrowsePathToNodeIds(UA_Server *server,
const UA_BrowsePath *browsePath);
/* A simplified TranslateBrowsePathsToNodeIds based on the
* SimpleAttributeOperand type (Part 4, 7.4.4.5).
*
* This specifies a relative path using a list of BrowseNames instead of the
* RelativePath structure. The list of BrowseNames is equivalent to a
* RelativePath that specifies forward references which are subtypes of the
* HierarchicalReferences ReferenceType. All Nodes followed by the browsePath
* shall be of the NodeClass Object or Variable. */
UA_BrowsePathResult UA_EXPORT
UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
size_t browsePathSize,
const UA_QualifiedName *browsePath);
#ifndef HAVE_NODEITER_CALLBACK
#define HAVE_NODEITER_CALLBACK
/* Iterate over all nodes referenced by parentNodeId by calling the callback
* function for each child node (in ifdef because GCC/CLANG handle include order
* differently) */
typedef UA_StatusCode
(*UA_NodeIteratorCallback)(UA_NodeId childId, UA_Boolean isInverse,
UA_NodeId referenceTypeId, void *handle);
#endif
UA_StatusCode UA_EXPORT
UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
UA_NodeIteratorCallback callback, void *handle);
#ifdef UA_ENABLE_DISCOVERY
/**
* Discovery
* --------- */
/* Register the given server instance at the discovery server.
* This should be called periodically.
* The semaphoreFilePath is optional. If the given file is deleted,
* the server will automatically be unregistered. This could be
* for example a pid file which is deleted if the server crashes.
*
* When the server shuts down you need to call unregister.
*
* @param server
* @param client the client which is used to call the RegisterServer. It must
* already be connected to the correct endpoint
* @param semaphoreFilePath optional parameter pointing to semaphore file. */
UA_StatusCode UA_EXPORT
UA_Server_register_discovery(UA_Server *server, struct UA_Client *client,
const char* semaphoreFilePath);
/* Unregister the given server instance from the discovery server.
* This should only be called when the server is shutting down.
* @param server
* @param client the client which is used to call the RegisterServer. It must
* already be connected to the correct endpoint */
UA_StatusCode UA_EXPORT
UA_Server_unregister_discovery(UA_Server *server, struct UA_Client *client);
/* Adds a periodic callback to register the server with the LDS (local discovery server)
* periodically. The interval between each register call is given as second parameter.
* It should be 10 minutes by default (= 10*60*1000).
*
* The delayFirstRegisterMs parameter indicates the delay for the first register call.
* If it is 0, the first register call will be after intervalMs milliseconds,
* otherwise the server's first register will be after delayFirstRegisterMs.
*
* When you manually unregister the server, you also need to cancel the
* periodic callback, otherwise it will be automatically be registered again.
*
* If you call this method multiple times for the same discoveryServerUrl, the older
* periodic callback will be removed.
*
* @param server
* @param client the client which is used to call the RegisterServer.
* It must not yet be connected and will be connected for every register call
* to the given discoveryServerUrl.
* @param discoveryServerUrl where this server should register itself.
* The string will be copied internally. Therefore you can free it after calling this method.
* @param intervalMs
* @param delayFirstRegisterMs
* @param periodicCallbackId */
UA_StatusCode UA_EXPORT
UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, struct UA_Client *client,
const char* discoveryServerUrl,
UA_Double intervalMs,
UA_Double delayFirstRegisterMs,
UA_UInt64 *periodicCallbackId);
/* Callback for RegisterServer. Data is passed from the register call */
typedef void (*UA_Server_registerServerCallback)(const UA_RegisteredServer *registeredServer,
void* data);
/* Set the callback which is called if another server registeres or unregisters
* with this instance. This callback is called every time the server gets a register
* call. This especially means that for every periodic server register the callback will
* be called.
*
* @param server
* @param cb the callback
* @param data data passed to the callback
* @return UA_STATUSCODE_SUCCESS on success */
void UA_EXPORT
UA_Server_setRegisterServerCallback(UA_Server *server, UA_Server_registerServerCallback cb,
void* data);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
/* Callback for server detected through mDNS. Data is passed from the register
* call
*
* @param isServerAnnounce indicates if the server has just been detected. If
* set to false, this means the server is shutting down.
* @param isTxtReceived indicates if we already received the corresponding TXT
* record with the path and caps data */
typedef void (*UA_Server_serverOnNetworkCallback)(const UA_ServerOnNetwork *serverOnNetwork,
UA_Boolean isServerAnnounce,
UA_Boolean isTxtReceived, void* data);
/* Set the callback which is called if another server is found through mDNS or
* deleted. It will be called for any mDNS message from the remote server, thus
* it may be called multiple times for the same instance. Also the SRV and TXT
* records may arrive later, therefore for the first call the server
* capabilities may not be set yet. If called multiple times, previous data will
* be overwritten.
*
* @param server
* @param cb the callback
* @param data data passed to the callback
* @return UA_STATUSCODE_SUCCESS on success */
void UA_EXPORT
UA_Server_setServerOnNetworkCallback(UA_Server *server,
UA_Server_serverOnNetworkCallback cb,
void* data);
#endif /* UA_ENABLE_DISCOVERY_MULTICAST */
#endif /* UA_ENABLE_DISCOVERY */
/**
* Information Model Callbacks
* ---------------------------
*
* There are three places where a callback from an information model to
* user-defined code can happen.
*
* - Custom node constructors and destructors
* - Linking VariableNodes with an external data source
* - MethodNode callbacks
*
* .. _node-lifecycle:
*
* Node Lifecycle: Constructors, Destructors and Node Contexts
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
* To finalize the instantiation of a node, a (user-defined) constructor
* callback is executed. There can be both a global constructor for all nodes
* and node-type constructor specific to the TypeDefinition of the new node
* (attached to an ObjectTypeNode or VariableTypeNode).
*
* In the hierarchy of ObjectTypes and VariableTypes, only the constructor of
* the (lowest) type defined for the new node is executed. Note that every
* Object and Variable can have only one ``isTypeOf`` reference. But type-nodes
* can technically have several ``hasSubType`` references to implement multiple
* inheritance. Issues of (multiple) inheritance in the constructor need to be
* solved by the user.
*
* When a node is destroyed, the node-type destructor is called before the
* global destructor. So the overall node lifecycle is as follows:
*
* 1. Global Constructor (set in the server config)
* 2. Node-Type Constructor (for VariableType or ObjectTypes)
* 3. (Usage-period of the Node)
* 4. Node-Type Destructor
* 5. Global Destructor
*
* The constructor and destructor callbacks can be set to ``NULL`` and are not
* used in that case. If the node-type constructor fails, the global destructor
* will be called before removing the node. The destructors are assumed to never
* fail.
*
* Every node carries a user-context and a constructor-context pointer. The
* user-context is used to attach custom data to a node. But the (user-defined)
* constructors and destructors may replace the user-context pointer if they
* wish to do so. The initial value for the constructor-context is ``NULL``.
* When the ``AddNodes`` service is used over the network, the user-context
* pointer of the new node is also initially set to ``NULL``. */
/* To be set in the server config. */
typedef struct {
/* Can be NULL. May replace the nodeContext */
UA_StatusCode (*constructor)(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void **nodeContext);
/* Can be NULL. The context cannot be replaced since the node is destroyed
* immediately afterwards anyway. */
void (*destructor)(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext);
/* Can be NULL. Called during recursive node instantiation. While mandatory
* child nodes are automatically created if not already present, optional child
* nodes are not. This callback can be used to define whether an optional child
* node should be created.
*
* @param server The server executing the callback
* @param sessionId The identifier of the session
* @param sessionContext Additional data attached to the session in the
* access control layer
* @param sourceNodeId Source node from the type definition. If the new node
* shall be created, it will be a copy of this node.
* @param targetParentNodeId Parent of the potential new child node
* @param referenceTypeId Identifies the reference type which that the parent
* node has to the new node.
* @return Return UA_TRUE if the child node shall be instantiatet,
* UA_FALSE otherwise. */
UA_Boolean (*createOptionalChild)(UA_Server *server,
const UA_NodeId *sessionId,
void *sessionContext,
const UA_NodeId *sourceNodeId,
const UA_NodeId *targetParentNodeId,
const UA_NodeId *referenceTypeId);
/* Can be NULL. Called when a node is to be copied during recursive
* node instantiation. Allows definition of the NodeId for the new node.
* If the callback is set to NULL or the resulting NodeId is UA_NODEID_NULL,
* then a random NodeId will be generated.
*
* @param server The server executing the callback
* @param sessionId The identifier of the session
* @param sessionContext Additional data attached to the session in the
* access control layer
* @param sourceNodeId Source node of the copy operation
* @param targetParentNodeId Parent node of the new node
* @param referenceTypeId Identifies the reference type which that the parent
* node has to the new node. */
UA_StatusCode (*generateChildNodeId)(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *sourceNodeId,
const UA_NodeId *targetParentNodeId,
const UA_NodeId *referenceTypeId,
UA_NodeId *targetNodeId);
} UA_GlobalNodeLifecycle;
typedef struct {
/* Can be NULL. May replace the nodeContext */
UA_StatusCode (*constructor)(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *typeNodeId, void *typeNodeContext,
const UA_NodeId *nodeId, void **nodeContext);
/* Can be NULL. May replace the nodeContext. */
void (*destructor)(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *typeNodeId, void *typeNodeContext,
const UA_NodeId *nodeId, void **nodeContext);
} UA_NodeTypeLifecycle;
UA_StatusCode UA_EXPORT
UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
UA_NodeTypeLifecycle lifecycle);
UA_StatusCode UA_EXPORT
UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
void **nodeContext);
/* Careful! The user has to ensure that the destructor callbacks still work. */
UA_StatusCode UA_EXPORT
UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
void *nodeContext);
/**
* .. _datasource:
*
* Data Source Callback
* ^^^^^^^^^^^^^^^^^^^^
*
* The server has a unique way of dealing with the content of variables. Instead
* of storing a variant attached to the variable node, the node can point to a
* function with a local data provider. Whenever the value attribute is read,
* the function will be called and asked to provide a UA_DataValue return value
* that contains the value content and additional timestamps.
*
* It is expected that the read callback is implemented. The write callback can
* be set to a null-pointer. */
typedef struct {
/* Copies the data from the source into the provided value.
*
* !! ZERO-COPY OPERATIONS POSSIBLE !!
* It is not required to return a copy of the actual content data. You can
* return a pointer to memory owned by the user. Memory can be reused
* between read callbacks of a DataSource, as the result is already encoded
* on the network buffer between each read operation.
*
* To use zero-copy reads, set the value of the `value->value` Variant
* without copying, e.g. with `UA_Variant_setScalar`. Then, also set
* `value->value.storageType` to `UA_VARIANT_DATA_NODELETE` to prevent the
* memory being cleaned up. Don't forget to also set `value->hasValue` to
* true to indicate the presence of a value.
*
* @param server The server executing the callback
* @param sessionId The identifier of the session
* @param sessionContext Additional data attached to the session in the
* access control layer
* @param nodeId The identifier of the node being read from
* @param nodeContext Additional data attached to the node by the user
* @param includeSourceTimeStamp If true, then the datasource is expected to
* set the source timestamp in the returned value
* @param range If not null, then the datasource shall return only a
* selection of the (nonscalar) data. Set
* UA_STATUSCODE_BADINDEXRANGEINVALID in the value if this does not
* apply
* @param value The (non-null) DataValue that is returned to the client. The
* data source sets the read data, the result status and optionally a
* sourcetimestamp.
* @return Returns a status code for logging. Error codes intended for the
* original caller are set in the value. If an error is returned,
* then no releasing of the value is done
*/
UA_StatusCode (*read)(UA_Server *server, const UA_NodeId *sessionId,
void *sessionContext, const UA_NodeId *nodeId,
void *nodeContext, UA_Boolean includeSourceTimeStamp,
const UA_NumericRange *range, UA_DataValue *value);
/* Write into a data source. This method pointer can be NULL if the
* operation is unsupported.
*
* @param server The server executing the callback
* @param sessionId The identifier of the session
* @param sessionContext Additional data attached to the session in the
* access control layer
* @param nodeId The identifier of the node being written to
* @param nodeContext Additional data attached to the node by the user
* @param range If not NULL, then the datasource shall return only a
* selection of the (nonscalar) data. Set
* UA_STATUSCODE_BADINDEXRANGEINVALID in the value if this does not
* apply
* @param value The (non-NULL) DataValue that has been written by the client.
* The data source contains the written data, the result status and
* optionally a sourcetimestamp
* @return Returns a status code for logging. Error codes intended for the
* original caller are set in the value. If an error is returned,
* then no releasing of the value is done
*/
UA_StatusCode (*write)(UA_Server *server, const UA_NodeId *sessionId,
void *sessionContext, const UA_NodeId *nodeId,
void *nodeContext, const UA_NumericRange *range,
const UA_DataValue *value);
} UA_DataSource;
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
const UA_DataSource dataSource);
/**
* .. _value-callback:
*
* Value Callback
* ^^^^^^^^^^^^^^
* Value Callbacks can be attached to variable and variable type nodes. If
* not ``NULL``, they are called before reading and after writing respectively. */
typedef struct {
/* Called before the value attribute is read. It is possible to write into the
* value attribute during onRead (using the write service). The node is
* re-opened afterwards so that changes are considered in the following read
* operation.
*
* @param handle Points to user-provided data for the callback.
* @param nodeid The identifier of the node.
* @param data Points to the current node value.
* @param range Points to the numeric range the client wants to read from
* (or NULL). */
void (*onRead)(UA_Server *server, const UA_NodeId *sessionId,
void *sessionContext, const UA_NodeId *nodeid,
void *nodeContext, const UA_NumericRange *range,
const UA_DataValue *value);
/* Called after writing the value attribute. The node is re-opened after
* writing so that the new value is visible in the callback.
*
* @param server The server executing the callback
* @sessionId The identifier of the session
* @sessionContext Additional data attached to the session
* in the access control layer
* @param nodeid The identifier of the node.
* @param nodeUserContext Additional data attached to the node by
* the user.
* @param nodeConstructorContext Additional data attached to the node
* by the type constructor(s).
* @param range Points to the numeric range the client wants to write to (or
* NULL). */
void (*onWrite)(UA_Server *server, const UA_NodeId *sessionId,
void *sessionContext, const UA_NodeId *nodeId,
void *nodeContext, const UA_NumericRange *range,
const UA_DataValue *data);
} UA_ValueCallback;
UA_StatusCode UA_EXPORT
UA_Server_setVariableNode_valueCallback(UA_Server *server,
const UA_NodeId nodeId,
const UA_ValueCallback callback);
/**
* .. _local-monitoreditems:
*
* Local MonitoredItems
* ^^^^^^^^^^^^^^^^^^^^
*
* MonitoredItems are used with the Subscription mechanism of OPC UA to
* transported notifications for data changes and events. MonitoredItems can
* also be registered locally. Notifications are then forwarded to a
* user-defined callback instead of a remote client. */
#ifdef UA_ENABLE_SUBSCRIPTIONS
typedef void (*UA_Server_DataChangeNotificationCallback)
(UA_Server *server, UA_UInt32 monitoredItemId, void *monitoredItemContext,
const UA_NodeId *nodeId, void *nodeContext, UA_UInt32 attributeId,
const UA_DataValue *value);
typedef void (*UA_Server_EventNotificationCallback)
(UA_Server *server, UA_UInt32 monId, void *monContext,
size_t nEventFields, const UA_Variant *eventFields);
/* Create a local MonitoredItem with a sampling interval that detects data
* changes.
*
* @param server The server executing the MonitoredItem
* @timestampsToReturn Shall timestamps be added to the value for the callback?
* @item The parameters of the new MonitoredItem. Note that the attribute of the
* ReadValueId (the node that is monitored) can not be
* ``UA_ATTRIBUTEID_EVENTNOTIFIER``. A different callback type needs to be
* registered for event notifications.
* @monitoredItemContext A pointer that is forwarded with the callback
* @callback The callback that is executed on detected data changes
*
* @return Returns a description of the created MonitoredItem. The structure
* also contains a StatusCode (in case of an error) and the identifier of the
* new MonitoredItem. */
UA_MonitoredItemCreateResult UA_EXPORT UA_THREADSAFE
UA_Server_createDataChangeMonitoredItem(UA_Server *server,
UA_TimestampsToReturn timestampsToReturn,
const UA_MonitoredItemCreateRequest item,
void *monitoredItemContext,
UA_Server_DataChangeNotificationCallback callback);
/* UA_MonitoredItemCreateResult UA_EXPORT */
/* UA_Server_createEventMonitoredItem(UA_Server *server, */
/* UA_TimestampsToReturn timestampsToReturn, */
/* const UA_MonitoredItemCreateRequest item, void *context, */
/* UA_Server_EventNotificationCallback callback); */
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId);
#endif
/**
* Method Callbacks
* ^^^^^^^^^^^^^^^^
* Method callbacks are set to `NULL` (not executable) when a method node is
* added over the network. In theory, it is possible to add a callback via
* ``UA_Server_setMethodNode_callback`` within the global constructor when
* adding methods over the network is really wanted. See the Section
* :ref:`object-interaction` for calling methods on an object. */
typedef UA_StatusCode
(*UA_MethodCallback)(UA_Server *server, const UA_NodeId *sessionId,
void *sessionContext, const UA_NodeId *methodId,
void *methodContext, const UA_NodeId *objectId,
void *objectContext, size_t inputSize,
const UA_Variant *input, size_t outputSize,
UA_Variant *output);
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_setMethodNode_callback(UA_Server *server,
const UA_NodeId methodNodeId,
UA_MethodCallback methodCallback);
#endif
/**
* .. _object-interaction:
*
* Interacting with Objects
* ------------------------
* Objects in the information model are represented as ObjectNodes. Some
* convenience functions are provided to simplify the interaction with objects.
*/
/* Write an object property. The property is represented as a VariableNode with
* a ``HasProperty`` reference from the ObjectNode. The VariableNode is
* identified by its BrowseName. Writing the property sets the value attribute
* of the VariableNode.
*
* @param server The server object
* @param objectId The identifier of the object (node)
* @param propertyName The name of the property
* @param value The value to be set for the event attribute
* @return The StatusCode for setting the event attribute */
UA_StatusCode UA_EXPORT
UA_Server_writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
const UA_QualifiedName propertyName,
const UA_Variant value);
/* Directly point to the scalar value instead of a variant */
UA_StatusCode UA_EXPORT
UA_Server_writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId,
const UA_QualifiedName propertyName,
const void *value, const UA_DataType *type);
/* Read an object property.
*
* @param server The server object
* @param objectId The identifier of the object (node)
* @param propertyName The name of the property
* @param value Contains the property value after reading. Must not be NULL.
* @return The StatusCode for setting the event attribute */
UA_StatusCode UA_EXPORT
UA_Server_readObjectProperty(UA_Server *server, const UA_NodeId objectId,
const UA_QualifiedName propertyName,
UA_Variant *value);
#ifdef UA_ENABLE_METHODCALLS
UA_CallMethodResult UA_EXPORT UA_THREADSAFE
UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
#endif
/**
* .. _addnodes:
*
* Node Addition and Deletion
* --------------------------
* When creating dynamic node instances at runtime, chances are that you will
* not care about the specific NodeId of the new node, as long as you can
* reference it later. When passing numeric NodeIds with a numeric identifier 0,
* the stack evaluates this as "select a random unassigned numeric NodeId in
* that namespace". To find out which NodeId was actually assigned to the new
* node, you may pass a pointer `outNewNodeId`, which will (after a successful
* node insertion) contain the nodeId of the new node. You may also pass a
* ``NULL`` pointer if this result is not needed.
*
* See the Section :ref:`node-lifecycle` on constructors and on attaching
* user-defined data to nodes.
*
* The methods for node addition and deletion take mostly const arguments that
* are not modified. When creating a node, a deep copy of the node identifier,
* node attributes, etc. is created. Therefore, it is possible to call for
* example ``UA_Server_addVariablenode`` with a value attribute (a
* :ref:`variant`) pointing to a memory location on the stack. If you need
* changes to a variable value to manifest at a specific memory location, please
* use a :ref:`datasource` or a :ref:`value-callback`. */
/* Protect against redundant definitions for server/client */
#ifndef UA_DEFAULT_ATTRIBUTES_DEFINED
#define UA_DEFAULT_ATTRIBUTES_DEFINED
/* The default for variables is "BaseDataType" for the datatype, -2 for the
* valuerank and a read-accesslevel. */
UA_EXPORT extern const UA_VariableAttributes UA_VariableAttributes_default;
UA_EXPORT extern const UA_VariableTypeAttributes UA_VariableTypeAttributes_default;
/* Methods are executable by default */
UA_EXPORT extern const UA_MethodAttributes UA_MethodAttributes_default;
/* The remaining attribute definitions are currently all zeroed out */
UA_EXPORT extern const UA_ObjectAttributes UA_ObjectAttributes_default;
UA_EXPORT extern const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default;
UA_EXPORT extern const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default;
UA_EXPORT extern const UA_DataTypeAttributes UA_DataTypeAttributes_default;
UA_EXPORT extern const UA_ViewAttributes UA_ViewAttributes_default;
#endif
/* Don't use this function. There are typed versions as inline functions. */
UA_StatusCode UA_EXPORT UA_THREADSAFE
__UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
const UA_NodeId *requestedNewNodeId,
const UA_NodeId *parentNodeId,
const UA_NodeId *referenceTypeId,
const UA_QualifiedName browseName,
const UA_NodeId *typeDefinition,
const UA_NodeAttributes *attr,
const UA_DataType *attributeType,
void *nodeContext, UA_NodeId *outNewNodeId);
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_NodeId typeDefinition,
const UA_VariableAttributes attr,
void *nodeContext, UA_NodeId *outNewNodeId) {
return __UA_Server_addNode(server, UA_NODECLASS_VARIABLE, &requestedNewNodeId,
&parentNodeId, &referenceTypeId, browseName,
&typeDefinition, (const UA_NodeAttributes*)&attr,
&UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
nodeContext, outNewNodeId);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_addVariableTypeNode(UA_Server *server,
const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_NodeId typeDefinition,
const UA_VariableTypeAttributes attr,
void *nodeContext, UA_NodeId *outNewNodeId) {
return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE,
&requestedNewNodeId, &parentNodeId, &referenceTypeId,
browseName, &typeDefinition,
(const UA_NodeAttributes*)&attr,
&UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
nodeContext, outNewNodeId);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_NodeId typeDefinition,
const UA_ObjectAttributes attr,
void *nodeContext, UA_NodeId *outNewNodeId) {
return __UA_Server_addNode(server, UA_NODECLASS_OBJECT, &requestedNewNodeId,
&parentNodeId, &referenceTypeId, browseName,
&typeDefinition, (const UA_NodeAttributes*)&attr,
&UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
nodeContext, outNewNodeId);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_ObjectTypeAttributes attr,
void *nodeContext, UA_NodeId *outNewNodeId) {
return __UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, &requestedNewNodeId,
&parentNodeId, &referenceTypeId, browseName,
&UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
&UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],
nodeContext, outNewNodeId);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_ViewAttributes attr,
void *nodeContext, UA_NodeId *outNewNodeId) {
return __UA_Server_addNode(server, UA_NODECLASS_VIEW, &requestedNewNodeId,
&parentNodeId, &referenceTypeId, browseName,
&UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
&UA_TYPES[UA_TYPES_VIEWATTRIBUTES],
nodeContext, outNewNodeId);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_addReferenceTypeNode(UA_Server *server,
const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_ReferenceTypeAttributes attr,
void *nodeContext, UA_NodeId *outNewNodeId) {
return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE,
&requestedNewNodeId, &parentNodeId, &referenceTypeId,
browseName, &UA_NODEID_NULL,
(const UA_NodeAttributes*)&attr,
&UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
nodeContext, outNewNodeId);
}
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_addDataTypeNode(UA_Server *server,
const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_DataTypeAttributes attr,
void *nodeContext, UA_NodeId *outNewNodeId) {
return __UA_Server_addNode(server, UA_NODECLASS_DATATYPE, &requestedNewNodeId,
&parentNodeId, &referenceTypeId, browseName,
&UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
&UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],
nodeContext, outNewNodeId);
}
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_addDataSourceVariableNode(UA_Server *server,
const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_NodeId typeDefinition,
const UA_VariableAttributes attr,
const UA_DataSource dataSource,
void *nodeContext, UA_NodeId *outNewNodeId);
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_MethodAttributes attr, UA_MethodCallback method,
size_t inputArgumentsSize, const UA_Argument *inputArguments,
const UA_NodeId inputArgumentsRequestedNewNodeId,
UA_NodeId *inputArgumentsOutNewNodeId,
size_t outputArgumentsSize, const UA_Argument *outputArguments,
const UA_NodeId outputArgumentsRequestedNewNodeId,
UA_NodeId *outputArgumentsOutNewNodeId,
void *nodeContext, UA_NodeId *outNewNodeId);
static UA_INLINE UA_THREADSAFE UA_StatusCode
UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName, const UA_MethodAttributes attr,
UA_MethodCallback method,
size_t inputArgumentsSize, const UA_Argument *inputArguments,
size_t outputArgumentsSize, const UA_Argument *outputArguments,
void *nodeContext, UA_NodeId *outNewNodeId) {
return UA_Server_addMethodNodeEx(server, requestedNewNodeId, parentNodeId,
referenceTypeId, browseName, attr, method,
inputArgumentsSize, inputArguments, UA_NODEID_NULL, NULL,
outputArgumentsSize, outputArguments, UA_NODEID_NULL, NULL,
nodeContext, outNewNodeId);
}
#endif
/**
* The method pair UA_Server_addNode_begin and _finish splits the AddNodes
* service in two parts. This is useful if the node shall be modified before
* finish the instantiation. For example to add children with specific NodeIds.
* Otherwise, mandatory children (e.g. of an ObjectType) are added with
* pseudo-random unique NodeIds. Existing children are detected during the
* _finish part via their matching BrowseName.
*
* The _begin method:
* - prepares the node and adds it to the nodestore
* - copies some unassigned attributes from the TypeDefinition node internally
* - adds the references to the parent (and the TypeDefinition if applicable)
* - performs type-checking of variables.
*
* You can add an object node without a parent if you set the parentNodeId and
* referenceTypeId to UA_NODE_ID_NULL. Then you need to add the parent reference
* and hasTypeDef reference yourself before calling the _finish method.
* Not that this is only allowed for object nodes.
*
* The _finish method:
* - copies mandatory children
* - calls the node constructor(s) at the end
* - may remove the node if it encounters an error.
*
* The special UA_Server_addMethodNode_finish method needs to be used for
* method nodes, since there you need to explicitly specifiy the input
* and output arguments which are added in the finish step (if not yet already there)
**/
/* The ``attr`` argument must have a type according to the NodeClass.
* ``VariableAttributes`` for variables, ``ObjectAttributes`` for objects, and
* so on. Missing attributes are taken from the TypeDefinition node if
* applicable. */
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
const UA_NodeId requestedNewNodeId,
const UA_NodeId parentNodeId,
const UA_NodeId referenceTypeId,
const UA_QualifiedName browseName,
const UA_NodeId typeDefinition,
const void *attr, const UA_DataType *attributeType,
void *nodeContext, UA_NodeId *outNewNodeId);
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId);
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
UA_MethodCallback method,
size_t inputArgumentsSize, const UA_Argument* inputArguments,
size_t outputArgumentsSize, const UA_Argument* outputArguments);
#endif
/* Deletes a node and optionally all references leading to the node. */
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
UA_Boolean deleteReferences);
/**
* Reference Management
* -------------------- */
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
const UA_NodeId refTypeId,
const UA_ExpandedNodeId targetId, UA_Boolean isForward);
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
const UA_NodeId referenceTypeId, UA_Boolean isForward,
const UA_ExpandedNodeId targetNodeId,
UA_Boolean deleteBidirectional);
/**
* .. _events:
*
* Events
* ------
* The method ``UA_Server_createEvent`` creates an event and represents it as node. The node receives a unique `EventId`
* which is automatically added to the node.
* The method returns a `NodeId` to the object node which represents the event through ``outNodeId``. The `NodeId` can
* be used to set the attributes of the event. The generated `NodeId` is always numeric. ``outNodeId`` cannot be
* ``NULL``.
*
* Note: In order to see an event in UAExpert, the field `Time` must be given a value!
*
* The method ``UA_Server_triggerEvent`` "triggers" an event by adding it to all monitored items of the specified
* origin node and those of all its parents. Any filters specified by the monitored items are automatically applied.
* Using this method deletes the node generated by ``UA_Server_createEvent``. The `EventId` for the new event is
* generated automatically and is returned through ``outEventId``. ``NULL`` can be passed if the `EventId` is not
* needed. ``deleteEventNode`` specifies whether the node representation of the event should be deleted after invoking
* the method. This can be useful if events with the similar attributes are triggered frequently. ``UA_TRUE`` would
* cause the node to be deleted. */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
/* The EventQueueOverflowEventType is defined as abstract, therefore we can not
* create an instance of that type directly, but need to create a subtype. The
* following is an arbitrary number which shall refer to our internal overflow
* type. This is already posted on the OPC Foundation bug tracker under the
* following link for clarification:
* https://opcfoundation-onlineapplications.org/mantis/view.php?id=4206 */
# define UA_NS0ID_SIMPLEOVERFLOWEVENTTYPE 4035
/* Creates a node representation of an event
*
* @param server The server object
* @param eventType The type of the event for which a node should be created
* @param outNodeId The NodeId of the newly created node for the event
* @return The StatusCode of the UA_Server_createEvent method */
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
UA_NodeId *outNodeId);
/* Triggers a node representation of an event by applying EventFilters and
adding the event to the appropriate queues.
* @param server The server object
* @param eventNodeId The NodeId of the node representation of the event which should be triggered
* @param outEvent the EventId of the new event
* @param deleteEventNode Specifies whether the node representation of the event should be deleted
* @return The StatusCode of the UA_Server_triggerEvent method */
UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_NodeId originId,
UA_ByteString *outEventId, const UA_Boolean deleteEventNode);
#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */
UA_StatusCode UA_EXPORT
UA_Server_updateCertificate(UA_Server *server,
const UA_ByteString *oldCertificate,
const UA_ByteString *newCertificate,
const UA_ByteString *newPrivateKey,
UA_Boolean closeSessions,
UA_Boolean closeSecureChannels);
/**
* Utility Functions
* ----------------- */
/* Add a new namespace to the server. Returns the index of the new namespace */
UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
/* Get namespace by name from the server. */
UA_StatusCode UA_EXPORT
UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
size_t* foundIndex);
#ifdef UA_ENABLE_HISTORIZING
UA_Boolean UA_EXPORT
UA_Server_AccessControl_allowHistoryUpdateUpdateData(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId,
UA_PerformUpdateType performInsertReplace,
const UA_DataValue *value);
UA_Boolean UA_EXPORT
UA_Server_AccessControl_allowHistoryUpdateDeleteRawModified(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId,
UA_DateTime startTimestamp,
UA_DateTime endTimestamp,
bool isDeleteModified);
#endif // UA_ENABLE_HISTORIZING
_UA_END_DECLS
#endif /* UA_SERVER_H_ */