#ifndef UA_PUBSUB_INTERNAL_H_
#define UA_PUBSUB_INTERNAL_H_
#define UA_INTERNAL
#include <open62541/server.h>
#include <open62541/server_pubsub.h>
#include "mp_printf.h"
#include "ua_pubsub_networkmessage.h"
#include "../server/ua_server_internal.h"
_UA_BEGIN_DECLS
#ifdef UA_ENABLE_PUBSUB
#define UA_PUBSUB_MAXCHANNELS 8
#define UA_PUBSUB_PROFILES_SIZE 4
struct UA_WriterGroup;
typedef struct UA_WriterGroup UA_WriterGroup;
struct UA_ReaderGroup;
typedef struct UA_ReaderGroup UA_ReaderGroup;
struct UA_SecurityGroup;
typedef struct UA_SecurityGroup UA_SecurityGroup;
struct UA_DataSetReader;
typedef struct UA_DataSetReader UA_DataSetReader;
struct UA_PubSubManager;
typedef struct UA_PubSubManager UA_PubSubManager;
struct UA_PubSubKeyStorage;
typedef struct UA_PubSubKeyStorage UA_PubSubKeyStorage;
UA_ConnectionManager *
getCM(UA_EventLoop *el, UA_String protocol);
const char *
UA_PubSubState_name(UA_PubSubState state);
static UA_INLINE UA_Boolean
UA_PubSubState_isEnabled(UA_PubSubState state) {
return (state != UA_PUBSUBSTATE_DISABLED &&
state != UA_PUBSUBSTATE_ERROR);
}
typedef struct {
UA_NodeId identifier;
UA_PubSubComponentType componentType;
UA_PubSubState state;
UA_String logIdString;
UA_Boolean transientState;
} UA_PubSubComponentHead;
#define UA_LOG_PUBSUB_INTERNAL(LOGGER, LEVEL, COMPONENT, MSG, ...) \
if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) { \
UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_PUBSUB, "%S" MSG "%.0s", \
(COMPONENT)->head.logIdString, __VA_ARGS__); \
}
#define UA_LOG_TRACE_PUBSUB(LOGGER, COMPONENT, ...) \
UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, TRACE, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_PUBSUB(LOGGER, COMPONENT, ...) \
UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, DEBUG, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_INFO_PUBSUB(LOGGER, COMPONENT, ...) \
UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, INFO, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_WARNING_PUBSUB(LOGGER, COMPONENT, ...) \
UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, WARNING, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_ERROR_PUBSUB(LOGGER, COMPONENT, ...) \
UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, ERROR, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_FATAL_PUBSUB(LOGGER, COMPONENT, ...) \
UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, FATAL, COMPONENT, __VA_ARGS__, ""))
void
UA_PubSubComponentHead_clear(UA_PubSubComponentHead *psch);
typedef struct UA_PublishedDataSet {
UA_PubSubComponentHead head;
TAILQ_ENTRY(UA_PublishedDataSet) listEntry;
TAILQ_HEAD(, UA_DataSetField) fields;
UA_PublishedDataSetConfig config;
UA_DataSetMetaDataType dataSetMetaData;
UA_UInt16 fieldSize;
UA_UInt16 promotedFieldsCount;
UA_UInt16 configurationFreezeCounter;
} UA_PublishedDataSet;
UA_StatusCode
UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src,
UA_PublishedDataSetConfig *dst);
UA_PublishedDataSet *
UA_PublishedDataSet_find(UA_PubSubManager *psm, const UA_NodeId id);
UA_PublishedDataSet *
UA_PublishedDataSet_findByName(UA_PubSubManager *psm, const UA_String name);
UA_AddPublishedDataSetResult
UA_PublishedDataSet_create(UA_PubSubManager *psm,
const UA_PublishedDataSetConfig *publishedDataSetConfig,
UA_NodeId *pdsIdentifier);
UA_StatusCode
UA_PublishedDataSet_remove(UA_PubSubManager *psm, UA_PublishedDataSet *pds);
typedef struct UA_SubscribedDataSet {
UA_PubSubComponentHead head;
TAILQ_ENTRY(UA_SubscribedDataSet) listEntry;
UA_SubscribedDataSetConfig config;
UA_DataSetReader *connectedReader;
} UA_SubscribedDataSet;
UA_StatusCode
UA_SubscribedDataSetConfig_copy(const UA_SubscribedDataSetConfig *src,
UA_SubscribedDataSetConfig *dst);
UA_SubscribedDataSet *
UA_SubscribedDataSet_find(UA_PubSubManager *psm, const UA_NodeId id);
UA_SubscribedDataSet *
UA_SubscribedDataSet_findByName(UA_PubSubManager *psm, const UA_String name);
void
UA_SubscribedDataSet_remove(UA_PubSubManager *psm, UA_SubscribedDataSet *sds);
typedef struct UA_PubSubConnection {
UA_PubSubComponentHead head;
TAILQ_ENTRY(UA_PubSubConnection) listEntry;
UA_PubSubConnectionConfig config;
UA_Boolean json;
UA_ConnectionManager *cm;
uintptr_t recvChannels[UA_PUBSUB_MAXCHANNELS];
size_t recvChannelsSize;
uintptr_t sendChannel;
size_t writerGroupsSize;
LIST_HEAD(, UA_WriterGroup) writerGroups;
size_t readerGroupsSize;
LIST_HEAD(, UA_ReaderGroup) readerGroups;
UA_DateTime silenceErrorUntil;
UA_Boolean deleteFlag;
UA_DelayedCallback dc;
} UA_PubSubConnection;
UA_PubSubConnection *
UA_PubSubConnection_find(UA_PubSubManager *psm, const UA_NodeId id);
UA_StatusCode
UA_PubSubConnection_create(UA_PubSubManager *psm,
const UA_PubSubConnectionConfig *connectionConfig,
UA_NodeId *connectionIdentifier);
UA_StatusCode
UA_PubSubConnection_delete(UA_PubSubManager *psm, UA_PubSubConnection *c);
UA_StatusCode
UA_PubSubConnection_setPubSubState(UA_PubSubManager *psm, UA_PubSubConnection *c,
UA_PubSubState targetState);
typedef struct UA_DataSetWriterSample {
UA_Boolean valueChanged;
UA_DataValue value;
} UA_DataSetWriterSample;
typedef struct UA_DataSetWriter {
UA_PubSubComponentHead head;
LIST_ENTRY(UA_DataSetWriter) listEntry;
UA_DataSetWriterConfig config;
UA_WriterGroup *linkedWriterGroup;
UA_PublishedDataSet *connectedDataSet;
UA_ConfigurationVersionDataType connectedDataSetVersion;
UA_UInt16 deltaFrameCounter;
size_t lastSamplesCount;
UA_DataSetWriterSample *lastSamples;
UA_UInt16 actualDataSetMessageSequenceCount;
UA_Boolean configurationFrozen;
UA_UInt64 pubSubStateTimerId;
} UA_DataSetWriter;
UA_StatusCode
UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src,
UA_DataSetWriterConfig *dst);
UA_DataSetWriter *
UA_DataSetWriter_find(UA_PubSubManager *psm, const UA_NodeId id);
UA_StatusCode
UA_DataSetWriter_setPubSubState(UA_PubSubManager *psm, UA_DataSetWriter *dsw,
UA_PubSubState targetState);
UA_StatusCode
UA_DataSetWriter_generateDataSetMessage(UA_PubSubManager *psm,
UA_DataSetWriter *dsw,
UA_DataSetMessage *dsm);
UA_StatusCode
UA_DataSetWriter_create(UA_PubSubManager *psm,
const UA_NodeId writerGroup, const UA_NodeId dataSet,
const UA_DataSetWriterConfig *dataSetWriterConfig,
UA_NodeId *writerIdentifier);
UA_StatusCode
UA_DataSetWriter_remove(UA_PubSubManager *psm, UA_DataSetWriter *dsw);
struct UA_WriterGroup {
UA_PubSubComponentHead head;
LIST_ENTRY(UA_WriterGroup) listEntry;
UA_WriterGroupConfig config;
LIST_HEAD(, UA_DataSetWriter) writers;
UA_UInt32 writersCount;
UA_UInt64 publishCallbackId;
UA_UInt16 sequenceNumber;
UA_DateTime lastPublishTimeStamp;
UA_PubSubConnection *linkedConnection;
uintptr_t sendChannel;
UA_Boolean deleteFlag;
UA_UInt32 securityTokenId;
UA_UInt32 nonceSequenceNumber;
void *securityPolicyContext;
#ifdef UA_ENABLE_PUBSUB_SKS
UA_PubSubKeyStorage *keyStorage;
#endif
};
UA_StatusCode
UA_WriterGroup_create(UA_PubSubManager *psm, const UA_NodeId connection,
const UA_WriterGroupConfig *writerGroupConfig,
UA_NodeId *writerGroupIdentifier);
UA_StatusCode
UA_WriterGroup_remove(UA_PubSubManager *psm, UA_WriterGroup *wg);
UA_StatusCode
UA_WriterGroup_addPublishCallback(UA_PubSubManager *psm, UA_WriterGroup *wg);
void
UA_WriterGroup_removePublishCallback(UA_PubSubManager *psm, UA_WriterGroup *wg);
UA_StatusCode
UA_WriterGroup_setEncryptionKeys(UA_PubSubManager *psm, UA_WriterGroup *wg,
UA_UInt32 securityTokenId,
const UA_ByteString signingKey,
const UA_ByteString encryptingKey,
const UA_ByteString keyNonce);
UA_StatusCode
UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src,
UA_WriterGroupConfig *dst);
UA_WriterGroup *
UA_WriterGroup_find(UA_PubSubManager *psm, const UA_NodeId id);
UA_StatusCode
UA_WriterGroup_setPubSubState(UA_PubSubManager *psm, UA_WriterGroup *wg,
UA_PubSubState targetState);
void
UA_WriterGroup_publishCallback(UA_PubSubManager *psm, UA_WriterGroup *wg);
typedef struct UA_DataSetField {
UA_DataSetFieldConfig config;
TAILQ_ENTRY(UA_DataSetField) listEntry;
UA_NodeId identifier;
UA_NodeId publishedDataSet;
UA_FieldMetaData fieldMetaData;
UA_UInt64 sampleCallbackId;
UA_Boolean sampleCallbackIsRegistered;
} UA_DataSetField;
UA_StatusCode
UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src,
UA_DataSetFieldConfig *dst);
UA_DataSetField *
UA_DataSetField_find(UA_PubSubManager *psm, const UA_NodeId id);
UA_DataSetFieldResult
UA_DataSetField_remove(UA_PubSubManager *psm, UA_DataSetField *currentField);
UA_DataSetFieldResult
UA_DataSetField_create(UA_PubSubManager *psm, const UA_NodeId publishedDataSet,
const UA_DataSetFieldConfig *fieldConfig,
UA_NodeId *fieldIdentifier);
void
UA_PubSubDataSetField_sampleValue(UA_PubSubManager *psm,
UA_DataSetField *field,
UA_DataValue *value);
struct UA_DataSetReader {
UA_PubSubComponentHead head;
LIST_ENTRY(UA_DataSetReader) listEntry;
UA_DataSetReaderConfig config;
UA_ReaderGroup *linkedReaderGroup;
UA_UInt64 msgRcvTimeoutTimerId;
};
UA_DataSetReader *
UA_DataSetReader_find(UA_PubSubManager *psm, const UA_NodeId id);
void
UA_DataSetReader_process(UA_PubSubManager *psm,
UA_DataSetReader *dataSetReader,
UA_DataSetMessage *dataSetMsg);
UA_StatusCode
UA_DataSetReader_generateDataSetMessage(UA_Server *server,
UA_DataSetMessage *dsm,
UA_DataSetReader *dsr);
UA_StatusCode
UA_DataSetReader_checkIdentifier(UA_PubSubManager *psm, UA_DataSetReader *dsr,
UA_NetworkMessage *msg);
UA_StatusCode
UA_DataSetReader_create(UA_PubSubManager *psm, UA_NodeId readerGroupIdentifier,
const UA_DataSetReaderConfig *dataSetReaderConfig,
UA_NodeId *readerIdentifier);
UA_StatusCode
UA_DataSetReader_remove(UA_PubSubManager *psm, UA_DataSetReader *dsr);
UA_StatusCode
DataSetReader_createTargetVariables(UA_PubSubManager *psm, UA_DataSetReader *dsr,
size_t targetsSize, const UA_FieldTargetDataType *targets);
UA_StatusCode
UA_DataSetReader_setPubSubState(UA_PubSubManager *psm, UA_DataSetReader *dsr,
UA_PubSubState targetState, UA_StatusCode errorReason);
struct UA_ReaderGroup {
UA_PubSubComponentHead head;
LIST_ENTRY(UA_ReaderGroup) listEntry;
UA_ReaderGroupConfig config;
LIST_HEAD(, UA_DataSetReader) readers;
UA_UInt32 readersCount;
UA_Boolean hasReceived;
UA_PubSubConnection *linkedConnection;
uintptr_t recvChannels[UA_PUBSUB_MAXCHANNELS];
size_t recvChannelsSize;
UA_Boolean deleteFlag;
UA_UInt32 securityTokenId;
UA_UInt32 nonceSequenceNumber;
void *securityPolicyContext;
#ifdef UA_ENABLE_PUBSUB_SKS
UA_PubSubKeyStorage *keyStorage;
#endif
};
UA_StatusCode
UA_ReaderGroup_create(UA_PubSubManager *psm, UA_NodeId connectionId,
const UA_ReaderGroupConfig *rgc,
UA_NodeId *readerGroupId);
UA_StatusCode
UA_ReaderGroup_remove(UA_PubSubManager *psm, UA_ReaderGroup *rg);
UA_StatusCode
UA_ReaderGroup_connect(UA_PubSubManager *psm, UA_ReaderGroup *rg,
UA_Boolean validate);
UA_Boolean
UA_ReaderGroup_canConnect(UA_ReaderGroup *rg);
void
UA_ReaderGroup_disconnect(UA_ReaderGroup *rg);
UA_StatusCode
UA_ReaderGroup_setEncryptionKeys(UA_PubSubManager *psm, UA_ReaderGroup *rg,
UA_UInt32 securityTokenId,
const UA_ByteString signingKey,
const UA_ByteString encryptingKey,
const UA_ByteString keyNonce);
UA_StatusCode
UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src,
UA_ReaderGroupConfig *dst);
UA_ReaderGroup *
UA_ReaderGroup_find(UA_PubSubManager *psm, const UA_NodeId id);
UA_StatusCode
UA_ReaderGroup_setPubSubState(UA_PubSubManager *psm, UA_ReaderGroup *rg,
UA_PubSubState targetState);
UA_Boolean
UA_ReaderGroup_process(UA_PubSubManager *psm, UA_ReaderGroup *rg,
UA_NetworkMessage *nm);
UA_StatusCode
verifyAndDecryptNetworkMessage(const UA_Logger *logger, UA_ByteString buffer,
Ctx *ctx, UA_NetworkMessage *nm,
UA_ReaderGroup *rg);
UA_StatusCode
UA_ReaderGroup_decodeNetworkMessage(UA_PubSubManager *psm,
UA_ReaderGroup *rg,
UA_ByteString buffer,
UA_NetworkMessage *nm);
#ifdef UA_ENABLE_JSON_ENCODING
UA_StatusCode
UA_ReaderGroup_decodeNetworkMessageJSON(UA_PubSubManager *psm,
UA_ReaderGroup *rg,
UA_ByteString buffer,
UA_NetworkMessage *nm);
#endif
#ifdef UA_ENABLE_PUBSUB_SKS
struct UA_SecurityGroup {
UA_String securityGroupId;
UA_SecurityGroupConfig config;
UA_PubSubKeyStorage *keyStorage;
UA_NodeId securityGroupNodeId;
UA_UInt64 callbackId;
UA_DateTime baseTime;
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
UA_NodeId securityGroupFolderId;
#endif
TAILQ_ENTRY(UA_SecurityGroup) listEntry;
};
UA_StatusCode
UA_SecurityGroupConfig_copy(const UA_SecurityGroupConfig *src,
UA_SecurityGroupConfig *dst);
UA_SecurityGroup *
UA_SecurityGroup_findByName(UA_PubSubManager *psm, const UA_String name);
UA_SecurityGroup *
UA_SecurityGroup_find(UA_PubSubManager *psm, const UA_NodeId id);
void
UA_SecurityGroup_remove(UA_PubSubManager *psm, UA_SecurityGroup *sg);
#endif
typedef enum {
UA_WRITER_GROUP = 0,
UA_DATA_SET_WRITER = 1,
} UA_ReserveIdType;
typedef struct UA_ReserveId {
UA_UInt16 id;
UA_ReserveIdType reserveIdType;
UA_String transportProfileUri;
UA_NodeId sessionId;
ZIP_ENTRY(UA_ReserveId) treeEntry;
} UA_ReserveId;
typedef ZIP_HEAD(UA_ReserveIdTree, UA_ReserveId) UA_ReserveIdTree;
struct UA_PubSubManager {
UA_ServerComponent sc;
UA_Logger *logging;
UA_UInt64 defaultPublisherId;
size_t connectionsSize;
TAILQ_HEAD(, UA_PubSubConnection) connections;
size_t publishedDataSetsSize;
TAILQ_HEAD(, UA_PublishedDataSet) publishedDataSets;
size_t subscribedDataSetsSize;
TAILQ_HEAD(, UA_SubscribedDataSet) subscribedDataSets;
size_t reserveIdsSize;
UA_ReserveIdTree reserveIds;
UA_Boolean pubSubInitialSetupMode;
#ifdef UA_ENABLE_PUBSUB_SKS
LIST_HEAD(, UA_PubSubKeyStorage) pubSubKeyList;
size_t securityGroupsSize;
TAILQ_HEAD(, UA_SecurityGroup) securityGroups;
#endif
#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL
UA_UInt32 uniqueIdCount;
#endif
};
static UA_INLINE UA_PubSubManager *
getPSM(UA_Server *server) {
return (UA_PubSubManager*)getServerComponentByName(server, UA_STRING("pubsub"));
}
UA_StatusCode
UA_PubSubManager_clear(UA_PubSubManager *psm);
void
UA_PubSubManager_setState(UA_PubSubManager *psm,
UA_LifecycleState state);
UA_StatusCode
UA_PubSubManager_reserveIds(UA_PubSubManager *psm, UA_NodeId sessionId,
UA_UInt16 numRegWriterGroupIds,
UA_UInt16 numRegDataSetWriterIds,
UA_String transportProfileUri, UA_UInt16 **writerGroupIds,
UA_UInt16 **dataSetWriterIds);
void
UA_PubSubManager_freeIds(UA_PubSubManager *psm);
#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL
void
UA_PubSubManager_generateUniqueNodeId(UA_PubSubManager *psm, UA_NodeId *nodeId);
#endif
UA_Guid
UA_PubSubManager_generateUniqueGuid(UA_PubSubManager *psm);
UA_UInt32
UA_PubSubConfigurationVersionTimeDifference(UA_DateTime now);
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
UA_StatusCode
initPubSubNS0(UA_Server *server);
#ifdef UA_ENABLE_PUBSUB_SKS
UA_StatusCode
initPubSubNS0_SKS(UA_Server *server);
#endif
UA_StatusCode
addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection);
UA_StatusCode
addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup);
UA_StatusCode
addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup);
UA_StatusCode
addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter);
UA_StatusCode
addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet);
UA_StatusCode
addSubscribedDataSetRepresentation(UA_Server *server, UA_SubscribedDataSet *subscribedDataSet);
UA_StatusCode
addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader);
UA_StatusCode
connectDataSetReaderToDataSet(UA_Server *server, UA_NodeId dsrId, UA_NodeId sdsId);
void
disconnectDataSetReaderToDataSet(UA_Server *server, UA_NodeId dsrId);
#ifdef UA_ENABLE_PUBSUB_SKS
UA_StatusCode
addSecurityGroupRepresentation(UA_Server *server, UA_SecurityGroup *securityGroup);
#endif
#endif
static UA_INLINE UA_Boolean
typeContainsString(const UA_DataType *type, size_t depth) {
if(!type || depth > 10)
return false;
if(type->typeKind == UA_DATATYPEKIND_STRING ||
type->typeKind == UA_DATATYPEKIND_BYTESTRING)
return true;
if(type->typeKind != UA_DATATYPEKIND_STRUCTURE &&
type->typeKind != UA_DATATYPEKIND_OPTSTRUCT &&
type->typeKind != UA_DATATYPEKIND_UNION)
return false;
if(type->pointerFree)
return false;
for(size_t i = 0; i < type->membersSize; i++) {
if(typeContainsString(type->members[i].memberType, depth + 1))
return true;
}
return false;
}
#endif
void
UA_PubSubComponent_freeWithoutLifecycleCallback(UA_PubSubManager *psm,
void *component,
UA_PubSubComponentType type);
_UA_END_DECLS
#endif