refactor(pubsub): Add explicit Metadata handling to the NetworkMessage encoding

This commit is contained in:
Julius Pfrommer 2025-04-18 14:12:48 +02:00 committed by Julius Pfrommer
parent bf0c326911
commit 699d89f834
10 changed files with 1736 additions and 1602 deletions

View File

@ -76,36 +76,22 @@ typedef struct {
} UA_DataSetMessageHeader;
typedef struct {
UA_UInt16 fieldCount;
UA_DataValue* dataSetFields;
UA_ByteString rawFields;
/* Json keys for the dataSetFields: TODO: own dataSetMessageType for json? */
UA_String* fieldNames;
/* This information is for proper en- and decoding needed */
UA_DataSetMetaDataType *dataSetMetaDataType;
} UA_DataSetMessage_DataKeyFrameData;
typedef struct {
UA_UInt16 fieldIndex;
UA_DataValue fieldValue;
UA_UInt16 index;
UA_DataValue value;
} UA_DataSetMessage_DeltaFrameField;
typedef struct {
UA_UInt16 fieldCount;
UA_DataSetMessage_DeltaFrameField* deltaFrameFields;
} UA_DataSetMessage_DataDeltaFrameData;
typedef struct {
UA_UInt16 dataSetWriterId; /* Goes into the payload header */
UA_DataSetMessageHeader header;
union {
UA_DataSetMessage_DataKeyFrameData keyFrameData;
UA_DataSetMessage_DataDeltaFrameData deltaFrameData;
UA_UInt16 fieldCount;
union { /* Array of fields (cf. header->dataSetMessageType) */
UA_DataValue *keyFrameFields;
UA_DataSetMessage_DeltaFrameField *deltaFrameFields;
} data;
size_t configuredSize;
} UA_DataSetMessage;
void UA_DataSetMessage_clear(UA_DataSetMessage *p);
/**
* Network Message
* ~~~~~~~~~~~~~~~ */
@ -188,10 +174,10 @@ typedef struct {
union {
struct {
UA_DataSetMessage *dataSetMessages;
size_t dataSetMessagesSize; /* Goes into the payload header */
UA_DataSetMessage *dataSetMessages;
} dataSetPayload;
/* Extended with other payload types in the future */
/* TODO: Add support for Discovery Messages */
} payload;
UA_ByteString securityFooter;
@ -202,46 +188,74 @@ UA_NetworkMessage_clear(UA_NetworkMessage* p);
/**
* NetworkMessage Encoding
* ~~~~~~~~~~~~~~~~~~~~~~~ */
* ~~~~~~~~~~~~~~~~~~~~~~~
* The en/decoding translates the NetworkMessage structure to/from a binary or
* JSON encoding. The en/decoding of PubSub NetworkMessages can require
* additional metadata. For example, during decoding, the DataType of raw
* encoded fields must be already known. As an example for encoding, the
* ``configuredSize`` may define zero-padding after a DataSetMessage.
*
* In the below methods, the different encoding options can be a NULL pointer
* and will then be ignored. */
typedef struct {
/* The WriterId is used to find the matching encoding metadata. If the
* NetworkMessage/DataSetMessage does not transmit the identifier, then the
* encoding metadata is used in-order for the received fields. */
UA_UInt16 dataSetWriterId;
/* FieldMetaData for JSON and RAW encoding */
size_t fieldsSize;
UA_FieldMetaData *fields;
/* Zero-padding if the DataSetMessage is shorter (UADP) */
UA_UInt16 configuredSize;
} UA_DataSetMessage_EncodingMetaData;
typedef struct {
size_t metaDataSize;
UA_DataSetMessage_EncodingMetaData *metaData;
} UA_NetworkMessage_EncodingOptions;
/* The output buffer is allocated to the required size if initially empty.
* Otherwise, upon success, the length is adjusted. */
UA_EXPORT UA_StatusCode
UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src,
UA_ByteString *outBuf);
UA_ByteString *outBuf,
const UA_NetworkMessage_EncodingOptions *eo);
UA_EXPORT size_t
UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage *p);
UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage *p,
const UA_NetworkMessage_EncodingOptions *eo);
/* The customTypes can be NULL */
UA_EXPORT UA_StatusCode
UA_NetworkMessage_decodeBinary(const UA_ByteString *src,
UA_NetworkMessage* dst,
const UA_DecodeBinaryOptions *options);
const UA_NetworkMessage_EncodingOptions *eo,
const UA_DecodeBinaryOptions *bo);
#ifdef UA_ENABLE_JSON_ENCODING
/* The output buffer is allocated to the required size if initially empty.
* Otherwise, upon success, the length is adjusted.
* The encoding options can be NULL. */
* Otherwise, upon success, the length is adjusted. */
UA_EXPORT UA_StatusCode
UA_NetworkMessage_encodeJson(const UA_NetworkMessage *src,
UA_ByteString *outBuf,
const UA_EncodeJsonOptions *options);
const UA_NetworkMessage_EncodingOptions *eo,
const UA_EncodeJsonOptions *jo);
/* The encoding options can be NULL */
UA_EXPORT size_t
UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage *src,
const UA_EncodeJsonOptions *options);
const UA_NetworkMessage_EncodingOptions *eo,
const UA_EncodeJsonOptions *jo);
/* The encoding options can be NULL */
UA_EXPORT UA_StatusCode
UA_NetworkMessage_decodeJson(const UA_ByteString *src,
UA_NetworkMessage *dst,
const UA_DecodeJsonOptions *options);
#endif
const UA_NetworkMessage_EncodingOptions *eo,
const UA_DecodeJsonOptions *jo);
#endif /* UA_ENABLE_JSON_ENCODING */
#endif /* UA_ENABLE_PUBSUB */
_UA_END_DECLS

View File

@ -2,8 +2,9 @@
* 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 (c) 2017 - 2018 Fraunhofer IOSB (Author: Tino Bischoff)
* Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Tino Bischoff)
* Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
* Copyright (c) 2025 Fraunhofer IOSB (Author: Julius Pfrommer)
*/
#ifndef UA_PUBSUB_NETWORKMESSAGE_H_
@ -13,95 +14,121 @@
#include <open62541/types_generated.h>
#include <open62541/plugin/securitypolicy.h>
#include <open62541/pubsub.h>
#include <open62541/server_pubsub.h>
#include "../ua_types_encoding_binary.h"
#include "../ua_types_encoding_json.h"
#ifdef UA_ENABLE_PUBSUB
_UA_BEGIN_DECLS
/**
* DataSetMessage
* ^^^^^^^^^^^^^^ */
typedef struct {
Ctx ctx;
UA_NetworkMessage_EncodingOptions eo;
UA_PubSubOffsetTable *ot;
} PubSubEncodeCtx;
typedef struct {
Ctx ctx;
UA_NetworkMessage_EncodingOptions eo;
} PubSubDecodeCtx;
typedef struct {
CtxJson ctx;
UA_NetworkMessage_EncodingOptions eo;
} PubSubEncodeJsonCtx;
typedef struct {
ParseCtx ctx;
UA_NetworkMessage_EncodingOptions eo;
} PubSubDecodeJsonCtx;
const UA_FieldMetaData *
getFieldMetaData(const UA_DataSetMessage_EncodingMetaData *emd,
size_t index);
const UA_DataSetMessage_EncodingMetaData *
findEncodingMetaData(const UA_NetworkMessage_EncodingOptions *eo,
const UA_DataSetMessage *dsm);
/******************/
/* DataSetMessage */
/******************/
UA_StatusCode
UA_DataSetMessageHeader_encodeBinary(const UA_DataSetMessageHeader *src,
UA_Byte **bufPos, const UA_Byte *bufEnd);
UA_DataSetMessageHeader_encodeBinary(PubSubEncodeCtx *ctx,
const UA_DataSetMessageHeader *src);
UA_StatusCode
UA_DataSetMessageHeader_decodeBinary(Ctx *ctx, UA_DataSetMessageHeader *dst);
UA_DataSetMessageHeader_decodeBinary(PubSubDecodeCtx *ctx,
UA_DataSetMessageHeader *dst);
UA_StatusCode
UA_DataSetMessage_encodeBinary(const UA_DataSetMessage *src, UA_Byte **bufPos,
const UA_Byte *bufEnd);
UA_DataSetMessage_encodeBinary(PubSubEncodeCtx *ctx,
const UA_DataSetMessage_EncodingMetaData *emd,
const UA_DataSetMessage *src);
UA_StatusCode
UA_DataSetMessage_decodeBinary(Ctx *ctx, UA_DataSetMessage *dst, UA_UInt16 dsmSize);
UA_DataSetMessage_decodeBinary(PubSubDecodeCtx *ctx,
UA_DataSetMessage *dsm,
size_t dsmSize);
size_t
UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage *p, UA_PubSubOffsetTable *ot,
UA_DataSetMessage_calcSizeBinary(PubSubEncodeCtx *ctx,
const UA_DataSetMessage_EncodingMetaData *em,
UA_DataSetMessage *src,
size_t currentOffset);
void UA_DataSetMessage_clear(UA_DataSetMessage *p);
/**
* NetworkMessage Encoding
* ^^^^^^^^^^^^^^^^^^^^^^^ */
/******************/
/* NetworkMessage */
/******************/
size_t
UA_NetworkMessage_calcSizeBinaryWithOffsetTable(const UA_NetworkMessage *p,
UA_PubSubOffsetTable *ot);
UA_NetworkMessage_calcSizeBinaryInternal(PubSubEncodeCtx *ctx,
const UA_NetworkMessage *src);
UA_StatusCode
UA_NetworkMessage_encodeHeaders(const UA_NetworkMessage *src,
UA_Byte **bufPos, const UA_Byte *bufEnd);
UA_NetworkMessage_encodeHeaders(PubSubEncodeCtx *ctx,
const UA_NetworkMessage *src);
UA_StatusCode
UA_NetworkMessage_encodePayload(const UA_NetworkMessage *src,
UA_Byte **bufPos, const UA_Byte *bufEnd);
UA_NetworkMessage_encodePayload(PubSubEncodeCtx *ctx,
const UA_NetworkMessage *src);
UA_StatusCode
UA_NetworkMessage_encodeFooters(const UA_NetworkMessage *src,
UA_Byte **bufPos, const UA_Byte *bufEnd);
/**
* NetworkMessage Decoding
* ^^^^^^^^^^^^^^^^^^^^^^^ */
UA_NetworkMessage_encodeFooters(PubSubEncodeCtx *ctx,
const UA_NetworkMessage *src);
UA_StatusCode
UA_NetworkMessage_decodeHeaders(Ctx *ctx, UA_NetworkMessage *dst);
UA_NetworkMessage_decodeHeaders(PubSubDecodeCtx *ctx,
UA_NetworkMessage *dst);
UA_StatusCode
UA_NetworkMessage_decodePayload(Ctx *ctx, UA_NetworkMessage *dst);
UA_NetworkMessage_decodePayload(PubSubDecodeCtx *ctx,
UA_NetworkMessage *dst);
UA_StatusCode
UA_NetworkMessage_decodeFooters(Ctx *ctx, UA_NetworkMessage *dst);
UA_StatusCode
UA_NetworkMessage_encodeJsonInternal(const UA_NetworkMessage *src,
UA_Byte **bufPos, const UA_Byte **bufEnd,
UA_NamespaceMapping *namespaceMapping,
UA_String *serverUris, size_t serverUriSize,
UA_Boolean useReversible);
size_t
UA_NetworkMessage_calcSizeJsonInternal(const UA_NetworkMessage *src,
UA_NamespaceMapping *namespaceMapping,
UA_String *serverUris, size_t serverUriSize,
UA_Boolean useReversible);
UA_NetworkMessage_decodeFooters(PubSubDecodeCtx *ctx,
UA_NetworkMessage *dst);
UA_StatusCode
UA_NetworkMessage_encodeBinaryWithEncryptStart(const UA_NetworkMessage* src,
UA_Byte **bufPos, const UA_Byte *bufEnd,
UA_NetworkMessage_encodeBinaryWithEncryptStart(PubSubEncodeCtx *ctx,
const UA_NetworkMessage *src,
UA_Byte **dataToEncryptStart);
UA_StatusCode
UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm, UA_MessageSecurityMode securityMode,
UA_PubSubSecurityPolicy *policy, void *policyContext,
UA_Byte *messageStart, UA_Byte *encryptStart,
UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm,
UA_MessageSecurityMode securityMode,
UA_PubSubSecurityPolicy *policy,
void *policyContext,
UA_Byte *messageStart,
UA_Byte *encryptStart,
UA_Byte *sigStart);
UA_StatusCode
UA_NetworkMessage_encodeJsonInternal(PubSubEncodeJsonCtx *ctx,
const UA_NetworkMessage *src);
_UA_END_DECLS
#endif /* UA_ENABLE_PUBSUB */

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@ const char * UA_DECODEKEY_PAYLOAD = "Payload";
const char * UA_DECODEKEY_DS_TYPE = "Type";
/* -- json encoding/decoding -- */
static UA_StatusCode writeJsonKey_UA_String(CtxJson *ctx, UA_String *in) {
static UA_StatusCode writeJsonKey_UA_String(CtxJson *ctx, const UA_String *in) {
UA_STACKARRAY(char, out, in->length + 1);
memcpy(out, in->data, in->length);
out[in->length] = 0;
@ -36,8 +36,9 @@ static UA_StatusCode writeJsonKey_UA_String(CtxJson *ctx, UA_String *in) {
}
static UA_StatusCode
UA_DataSetMessage_encodeJson_internal(const UA_DataSetMessage* src,
CtxJson *ctx) {
UA_DataSetMessage_encodeJson_internal(CtxJson *ctx,
const UA_DataSetMessage_EncodingMetaData *emd,
const UA_DataSetMessage *src) {
status rv = writeJsonObjStart(ctx);
/* DataSetWriterId */
@ -106,25 +107,27 @@ UA_DataSetMessage_encodeJson_internal(const UA_DataSetMessage* src,
if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
/* Variant */
for(UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
if(src->data.keyFrameData.fieldNames)
rv |= writeJsonKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i]);
for(UA_UInt16 i = 0; i < src->fieldCount; i++) {
const UA_FieldMetaData *fmd = getFieldMetaData(emd, i);
if(fmd)
rv |= writeJsonKey_UA_String(ctx, &fmd->name);
else
rv |= writeJsonKey(ctx, "");
rv |= encodeJsonJumpTable[UA_DATATYPEKIND_VARIANT]
(ctx, &src->data.keyFrameData.dataSetFields[i].value, NULL);
(ctx, &src->data.keyFrameFields[i].value, NULL);
if(rv != UA_STATUSCODE_GOOD)
return rv;
}
} else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
/* DataValue */
for(UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
if(src->data.keyFrameData.fieldNames)
rv |= writeJsonKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i]);
for(UA_UInt16 i = 0; i < src->fieldCount; i++) {
const UA_FieldMetaData *fmd = getFieldMetaData(emd, i);
if(fmd)
rv |= writeJsonKey_UA_String(ctx, &fmd->name);
else
rv |= writeJsonKey(ctx, "");
rv |= encodeJsonJumpTable[UA_DATATYPEKIND_DATAVALUE]
(ctx, &src->data.keyFrameData.dataSetFields[i], NULL);
(ctx, &src->data.keyFrameFields[i], NULL);
if(rv != UA_STATUSCODE_GOOD)
return rv;
}
@ -137,24 +140,25 @@ UA_DataSetMessage_encodeJson_internal(const UA_DataSetMessage* src,
return rv;
}
static UA_StatusCode
UA_NetworkMessage_encodeJson_internal(const UA_NetworkMessage* src, CtxJson *ctx) {
UA_StatusCode
UA_NetworkMessage_encodeJsonInternal(PubSubEncodeJsonCtx *ctx,
const UA_NetworkMessage *src) {
/* currently only ua-data is supported, no discovery message implemented */
if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET)
return UA_STATUSCODE_BADNOTIMPLEMENTED;
status rv = writeJsonObjStart(ctx);
status rv = writeJsonObjStart(&ctx->ctx);
/* Table 91 JSON NetworkMessage Definition
* MessageId | String | A globally unique identifier for the message.
* This value is mandatory. But we don't check uniqueness in the
* encoding layer. */
rv |= writeJsonObjElm(ctx, UA_DECODEKEY_MESSAGEID,
rv |= writeJsonObjElm(&ctx->ctx, UA_DECODEKEY_MESSAGEID,
&src->messageId, &UA_TYPES[UA_TYPES_STRING]);
/* MessageType */
UA_String s = UA_STRING("ua-data");
rv |= writeJsonObjElm(ctx, UA_DECODEKEY_MESSAGETYPE,
rv |= writeJsonObjElm(&ctx->ctx, UA_DECODEKEY_MESSAGETYPE,
&s, &UA_TYPES[UA_TYPES_STRING]);
/* PublisherId, always encode as a JSON string */
@ -166,8 +170,8 @@ UA_NetworkMessage_encodeJson_internal(const UA_NetworkMessage* src, CtxJson *ctx
rv |= UA_encodeJson(v.data, v.type, &bs, NULL);
if(rv != UA_STATUSCODE_GOOD)
return rv;
rv |= writeJsonKey(ctx, UA_DECODEKEY_PUBLISHERID);
rv |= encodeJsonJumpTable[UA_DATATYPEKIND_STRING](ctx, &bs, NULL);
rv |= writeJsonKey(&ctx->ctx, UA_DECODEKEY_PUBLISHERID);
rv |= encodeJsonJumpTable[UA_DATATYPEKIND_STRING](&ctx->ctx, &bs, NULL);
}
if(rv != UA_STATUSCODE_GOOD)
return rv;
@ -176,7 +180,7 @@ UA_NetworkMessage_encodeJson_internal(const UA_NetworkMessage* src, CtxJson *ctx
/* DataSetClassId */
if(src->dataSetClassIdEnabled) {
rv |= writeJsonObjElm(ctx, UA_DECODEKEY_DATASETCLASSID,
rv |= writeJsonObjElm(&ctx->ctx, UA_DECODEKEY_DATASETCLASSID,
&src->dataSetClassId, &UA_TYPES[UA_TYPES_GUID]);
if(rv != UA_STATUSCODE_GOOD)
return rv;
@ -185,60 +189,36 @@ UA_NetworkMessage_encodeJson_internal(const UA_NetworkMessage* src, CtxJson *ctx
/* Payload: DataSetMessages */
size_t count = src->payload.dataSetPayload.dataSetMessagesSize;
if(count > 0) {
rv |= writeJsonKey(ctx, UA_DECODEKEY_MESSAGES);
rv |= writeJsonArrStart(ctx); /* start array */
const UA_DataSetMessage *dataSetMessages =
src->payload.dataSetPayload.dataSetMessages;
rv |= writeJsonKey(&ctx->ctx, UA_DECODEKEY_MESSAGES);
rv |= writeJsonArrStart(&ctx->ctx); /* start array */
const UA_DataSetMessage *dsm = src->payload.dataSetPayload.dataSetMessages;
for(size_t i = 0; i < count; i++) {
rv |= writeJsonBeforeElement(ctx, true);
rv |= UA_DataSetMessage_encodeJson_internal(&dataSetMessages[i], ctx);
const UA_DataSetMessage_EncodingMetaData *emd =
findEncodingMetaData(&ctx->eo, &dsm[i]);
rv |= writeJsonBeforeElement(&ctx->ctx, true);
rv |= UA_DataSetMessage_encodeJson_internal(&ctx->ctx, emd, &dsm[i]);
if(rv != UA_STATUSCODE_GOOD)
return rv;
/* comma is needed if more dsm are present */
ctx->commaNeeded[ctx->depth] = true;
ctx->ctx.commaNeeded[ctx->ctx.depth] = true;
}
rv |= writeJsonArrEnd(ctx, NULL); /* end array */
rv |= writeJsonArrEnd(&ctx->ctx, NULL); /* end array */
}
rv |= writeJsonObjEnd(ctx);
rv |= writeJsonObjEnd(&ctx->ctx);
return rv;
}
UA_StatusCode
UA_NetworkMessage_encodeJsonInternal(const UA_NetworkMessage *src,
UA_Byte **bufPos, const UA_Byte **bufEnd,
UA_NamespaceMapping *namespaceMapping,
UA_String *serverUris, size_t serverUriSize,
UA_Boolean useReversible) {
/* Set up the context */
CtxJson ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.pos = *bufPos;
ctx.end = *bufEnd;
ctx.depth = 0;
ctx.namespaceMapping = namespaceMapping;
ctx.serverUris = serverUris;
ctx.serverUrisSize = serverUriSize;
ctx.useReversible = useReversible;
ctx.calcOnly = false;
status ret = UA_NetworkMessage_encodeJson_internal(src, &ctx);
*bufPos = ctx.pos;
*bufEnd = ctx.end;
return ret;
}
UA_StatusCode
UA_NetworkMessage_encodeJson(const UA_NetworkMessage *src,
UA_ByteString *outBuf,
const UA_EncodeJsonOptions *options) {
const UA_NetworkMessage_EncodingOptions *eo,
const UA_EncodeJsonOptions *jo) {
UA_Boolean alloced = (outBuf->length == 0);
UA_StatusCode ret = UA_STATUSCODE_GOOD;
if(alloced) {
size_t length = UA_NetworkMessage_calcSizeJson(src, options);
size_t length = UA_NetworkMessage_calcSizeJson(src, eo, jo);
if(length == 0)
return UA_STATUSCODE_BADENCODINGERROR;
ret = UA_ByteString_allocBuffer(outBuf, length);
@ -247,139 +227,131 @@ UA_NetworkMessage_encodeJson(const UA_NetworkMessage *src,
}
/* Set up the context */
CtxJson ctx;
PubSubEncodeJsonCtx ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.pos = outBuf->data;
ctx.end = ctx.pos + outBuf->length;
ctx.calcOnly = false;
if(options) {
ctx.useReversible = options->useReversible;
ctx.namespaceMapping = options->namespaceMapping;
ctx.serverUrisSize = options->serverUrisSize;
ctx.serverUris = options->serverUris;
ctx.prettyPrint = options->prettyPrint;
ctx.unquotedKeys = options->unquotedKeys;
ctx.stringNodeIds = options->stringNodeIds;
ctx.ctx.pos = outBuf->data;
ctx.ctx.end = outBuf->data + outBuf->length;
ctx.ctx.calcOnly = false;
if(eo)
ctx.eo = *eo;
if(jo) {
ctx.ctx.useReversible = jo->useReversible;
ctx.ctx.namespaceMapping = jo->namespaceMapping;
ctx.ctx.serverUrisSize = jo->serverUrisSize;
ctx.ctx.serverUris = jo->serverUris;
ctx.ctx.prettyPrint = jo->prettyPrint;
ctx.ctx.unquotedKeys = jo->unquotedKeys;
ctx.ctx.stringNodeIds = jo->stringNodeIds;
}
ret = UA_NetworkMessage_encodeJson_internal(src, &ctx);
ret = UA_NetworkMessage_encodeJsonInternal(&ctx, src);
/* In case the buffer was supplied externally and is longer than the encoded
* string */
if(UA_LIKELY(ret == UA_STATUSCODE_GOOD))
outBuf->length = (size_t)((uintptr_t)ctx.pos - (uintptr_t)outBuf->data);
outBuf->length = (size_t)((uintptr_t)ctx.ctx.pos - (uintptr_t)outBuf->data);
if(alloced && ret != UA_STATUSCODE_GOOD)
UA_String_clear(outBuf);
return ret;
}
size_t
UA_NetworkMessage_calcSizeJsonInternal(const UA_NetworkMessage *src,
UA_NamespaceMapping *namespaceMapping,
UA_String *serverUris, size_t serverUriSize,
UA_Boolean useReversible) {
/* Set up the context */
CtxJson ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.pos = 0;
ctx.end = (const UA_Byte*)(uintptr_t)SIZE_MAX;
ctx.depth = 0;
ctx.namespaceMapping = namespaceMapping;
ctx.serverUris = serverUris;
ctx.serverUrisSize = serverUriSize;
ctx.useReversible = useReversible;
ctx.calcOnly = true;
status ret = UA_NetworkMessage_encodeJson_internal(src, &ctx);
if(ret != UA_STATUSCODE_GOOD)
return 0;
return (size_t)ctx.pos;
}
size_t
UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage *src,
const UA_EncodeJsonOptions *options) {
const UA_NetworkMessage_EncodingOptions *eo,
const UA_EncodeJsonOptions *jo) {
/* Set up the context */
CtxJson ctx;
PubSubEncodeJsonCtx ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.end = (const UA_Byte*)(uintptr_t)SIZE_MAX;
ctx.calcOnly = true;
if(options) {
ctx.useReversible = options->useReversible;
ctx.namespaceMapping = options->namespaceMapping;
ctx.serverUrisSize = options->serverUrisSize;
ctx.serverUris = options->serverUris;
ctx.prettyPrint = options->prettyPrint;
ctx.unquotedKeys = options->unquotedKeys;
ctx.stringNodeIds = options->stringNodeIds;
ctx.ctx.end = (const UA_Byte*)(uintptr_t)SIZE_MAX;
ctx.ctx.calcOnly = true;
if(eo)
ctx.eo = *eo;
if(jo) {
ctx.ctx.useReversible = jo->useReversible;
ctx.ctx.namespaceMapping = jo->namespaceMapping;
ctx.ctx.serverUrisSize = jo->serverUrisSize;
ctx.ctx.serverUris = jo->serverUris;
ctx.ctx.prettyPrint = jo->prettyPrint;
ctx.ctx.unquotedKeys = jo->unquotedKeys;
ctx.ctx.stringNodeIds = jo->stringNodeIds;
}
status ret = UA_NetworkMessage_encodeJson_internal(src, &ctx);
status ret = UA_NetworkMessage_encodeJsonInternal(&ctx, src);
if(ret != UA_STATUSCODE_GOOD)
return 0;
return (size_t)ctx.pos;
return (size_t)ctx.ctx.pos;
}
/* decode json */
static status
MetaDataVersion_decodeJsonInternal(ParseCtx *ctx, void* cvd, const UA_DataType *type) {
MetaDataVersion_decodeJsonInternal(ParseCtx *ctx, void* cvd, const UA_DataType *_) {
return decodeJsonJumpTable[UA_DATATYPEKIND_STRUCTURE]
(ctx, cvd, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
}
static size_t
decodingFieldIndex(const UA_DataSetMessage_EncodingMetaData *emd,
UA_String name, size_t origIndex) {
if(!emd)
return origIndex;
for(size_t i = 0; i < emd->fieldsSize; i++) {
if(UA_String_equal(&name, &emd->fields[i].name))
return i;
}
return origIndex;
}
static status
DataSetPayload_decodeJsonInternal(ParseCtx *ctx, void* dsmP, const UA_DataType *type) {
UA_DataSetMessage* dsm = (UA_DataSetMessage*)dsmP;
DataSetPayload_decodeJsonInternal(PubSubDecodeJsonCtx *ctx,
UA_DataSetMessage *dsm,
const UA_DataType *_) {
dsm->header.dataSetMessageValid = true;
if(currentTokenType(ctx) == CJ5_TOKEN_NULL) {
ctx->index++;
if(currentTokenType(&ctx->ctx) == CJ5_TOKEN_NULL) {
ctx->ctx.index++;
return UA_STATUSCODE_GOOD;
}
if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT)
if(currentTokenType(&ctx->ctx) != CJ5_TOKEN_OBJECT)
return UA_STATUSCODE_BADDECODINGERROR;
/* The number of key-value pairs */
UA_assert(ctx->tokens[ctx->index].size % 2 == 0);
size_t length = (size_t)(ctx->tokens[ctx->index].size) / 2;
UA_assert(ctx->ctx.tokens[ctx->ctx.index].size % 2 == 0);
size_t length = (size_t)(ctx->ctx.tokens[ctx->ctx.index].size) / 2;
UA_String *fieldNames = (UA_String*)UA_calloc(length, sizeof(UA_String));
if(!fieldNames)
dsm->data.keyFrameFields = (UA_DataValue *)
UA_Array_new(length, &UA_TYPES[UA_TYPES_DATAVALUE]);
if(!dsm->data.keyFrameFields)
return UA_STATUSCODE_BADOUTOFMEMORY;
dsm->data.keyFrameData.fieldNames = fieldNames;
dsm->data.keyFrameData.fieldCount = (UA_UInt16)length;
dsm->fieldCount = (UA_UInt16)length;
dsm->data.keyFrameData.dataSetFields = (UA_DataValue *)
UA_Array_new(dsm->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]);
if(!dsm->data.keyFrameData.dataSetFields)
return UA_STATUSCODE_BADOUTOFMEMORY;
dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
ctx->index++; /* Go to the first key */
const UA_DataSetMessage_EncodingMetaData *emd = findEncodingMetaData(&ctx->eo, dsm);
/* Iterate over the key/value pairs in the object. Keys are stored in fieldnames. */
ctx->ctx.index++; /* Go to the first key */
status ret = UA_STATUSCODE_GOOD;
dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
for(size_t i = 0; i < length; ++i) {
UA_assert(currentTokenType(ctx) == CJ5_TOKEN_STRING);
ret = decodeJsonJumpTable[UA_DATATYPEKIND_STRING](ctx, &fieldNames[i], type);
if(ret != UA_STATUSCODE_GOOD)
return ret;
UA_assert(currentTokenType(&ctx->ctx) == CJ5_TOKEN_STRING);
UA_String fieldName = UA_STRING_NULL;
ret = decodeJsonJumpTable[UA_DATATYPEKIND_STRING](&ctx->ctx, &fieldName, NULL);
UA_CHECK_STATUS(ret, return ret);
/* TODO: Is field value a variant or datavalue? */
size_t index = decodingFieldIndex(emd, fieldName, i);
UA_DataValue_clear(&dsm->data.keyFrameFields[index]);
UA_String_clear(&fieldName);
ret = decodeJsonJumpTable[UA_DATATYPEKIND_DATAVALUE]
(ctx, &dsm->data.keyFrameData.dataSetFields[i], NULL);
if(ret != UA_STATUSCODE_GOOD)
return ret;
(&ctx->ctx, &dsm->data.keyFrameFields[index], NULL);
UA_CHECK_STATUS(ret, return ret);
}
return ret;
}
static status
DatasetMessage_Payload_decodeJsonInternal(ParseCtx *ctx, UA_DataSetMessage* dsm,
DatasetMessage_Payload_decodeJsonInternal(PubSubDecodeJsonCtx *ctx, UA_DataSetMessage* dsm,
const UA_DataType *type) {
UA_ConfigurationVersionDataType cvd;
DecodeEntry entries[7] = {
@ -389,14 +361,15 @@ DatasetMessage_Payload_decodeJsonInternal(ParseCtx *ctx, UA_DataSetMessage* dsm,
{UA_DECODEKEY_TIMESTAMP, &dsm->header.timestamp, NULL, false, &UA_TYPES[UA_TYPES_DATETIME]},
{UA_DECODEKEY_DSM_STATUS, &dsm->header.status, NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
{UA_DECODEKEY_MESSAGETYPE, NULL, NULL, false, NULL},
{UA_DECODEKEY_PAYLOAD, dsm, &DataSetPayload_decodeJsonInternal, false, NULL}
{UA_DECODEKEY_PAYLOAD, dsm, (decodeJsonSignature)DataSetPayload_decodeJsonInternal, false, NULL}
};
status ret = decodeFields(ctx, entries, 7);
status ret = decodeFields(&ctx->ctx, entries, 7);
/* Error or no DatasetWriterId found or no payload found */
if(ret != UA_STATUSCODE_GOOD || !entries[0].found || !entries[6].found)
return UA_STATUSCODE_BADDECODINGERROR;
/* TODO: Check FieldEncoding1 and FieldEncoding2 to determine the field encoding */
dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
dsm->header.dataSetMessageSequenceNrEnabled = entries[1].found;
dsm->header.configVersionMajorVersion = cvd.majorVersion;
@ -414,20 +387,20 @@ DatasetMessage_Payload_decodeJsonInternal(ParseCtx *ctx, UA_DataSetMessage* dsm,
}
static status
DatasetMessage_Array_decodeJsonInternal(ParseCtx *ctx, void *UA_RESTRICT dst,
DatasetMessage_Array_decodeJsonInternal(PubSubDecodeJsonCtx *ctx, void *UA_RESTRICT dst,
const UA_DataType *type) {
/* Array or object */
size_t length = 1;
if(currentTokenType(ctx) == CJ5_TOKEN_ARRAY) {
length = (size_t)ctx->tokens[ctx->index].size;
if(currentTokenType(&ctx->ctx) == CJ5_TOKEN_ARRAY) {
length = (size_t)ctx->ctx.tokens[ctx->ctx.index].size;
/* Go to the first array member */
ctx->index++;
ctx->ctx.index++;
/* Return early for empty arrays */
if(length == 0)
return UA_STATUSCODE_GOOD;
} else if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT) {
} else if(currentTokenType(&ctx->ctx) != CJ5_TOKEN_OBJECT) {
return UA_STATUSCODE_BADDECODINGERROR;
}
@ -460,7 +433,8 @@ decodePublisherIdJsonInternal(ParseCtx *ctx, void *UA_RESTRICT dst,
}
static status
NetworkMessage_decodeJsonInternal(ParseCtx *ctx, UA_NetworkMessage *dst) {
NetworkMessage_decodeJsonInternal(PubSubDecodeJsonCtx *ctx,
UA_NetworkMessage *dst) {
memset(dst, 0, sizeof(UA_NetworkMessage));
dst->chunkMessage = false;
dst->groupHeaderEnabled = false;
@ -470,10 +444,10 @@ NetworkMessage_decodeJsonInternal(ParseCtx *ctx, UA_NetworkMessage *dst) {
/* Is Messages an Array? How big? */
size_t searchResultMessages = 0;
status found = lookAheadForKey(ctx, UA_DECODEKEY_MESSAGES, &searchResultMessages);
status found = lookAheadForKey(&ctx->ctx, UA_DECODEKEY_MESSAGES, &searchResultMessages);
if(found != UA_STATUSCODE_GOOD)
return UA_STATUSCODE_BADNOTIMPLEMENTED;
const cj5_token *bodyToken = &ctx->tokens[searchResultMessages];
const cj5_token *bodyToken = &ctx->ctx.tokens[searchResultMessages];
size_t messageCount = 1;
if(bodyToken->type == CJ5_TOKEN_ARRAY)
messageCount = (size_t)bodyToken->size;
@ -481,11 +455,11 @@ NetworkMessage_decodeJsonInternal(ParseCtx *ctx, UA_NetworkMessage *dst) {
/* MessageType */
UA_Boolean isUaData = true;
size_t searchResultMessageType = 0;
found = lookAheadForKey(ctx, UA_DECODEKEY_MESSAGETYPE, &searchResultMessageType);
found = lookAheadForKey(&ctx->ctx, UA_DECODEKEY_MESSAGETYPE, &searchResultMessageType);
if(found != UA_STATUSCODE_GOOD)
return UA_STATUSCODE_BADDECODINGERROR;
size_t size = getTokenLength(&ctx->tokens[searchResultMessageType]);
const char* msgType = &ctx->json5[ctx->tokens[searchResultMessageType].start];
size_t size = getTokenLength(&ctx->ctx.tokens[searchResultMessageType]);
const char* msgType = &ctx->ctx.json5[ctx->ctx.tokens[searchResultMessageType].start];
if(size == 7) { //ua-data
if(strncmp(msgType, "ua-data", size) != 0)
return UA_STATUSCODE_BADDECODINGERROR;
@ -516,10 +490,10 @@ NetworkMessage_decodeJsonInternal(ParseCtx *ctx, UA_NetworkMessage *dst) {
{UA_DECODEKEY_PUBLISHERID, &dst->publisherId, decodePublisherIdJsonInternal, false, NULL},
{UA_DECODEKEY_DATASETCLASSID, &dst->dataSetClassId, NULL, false, &UA_TYPES[UA_TYPES_GUID]},
{UA_DECODEKEY_MESSAGES, dst->payload.dataSetPayload.dataSetMessages,
&DatasetMessage_Array_decodeJsonInternal, false, NULL}
(decodeJsonSignature)DatasetMessage_Array_decodeJsonInternal, false, NULL}
};
status ret = decodeFields(ctx, entries, 5);
status ret = decodeFields(&ctx->ctx, entries, 5);
if(ret != UA_STATUSCODE_GOOD)
return ret;
@ -534,20 +508,23 @@ NetworkMessage_decodeJsonInternal(ParseCtx *ctx, UA_NetworkMessage *dst) {
UA_StatusCode
UA_NetworkMessage_decodeJson(const UA_ByteString *src,
UA_NetworkMessage *dst,
const UA_DecodeJsonOptions *options) {
const UA_NetworkMessage_EncodingOptions *eo,
const UA_DecodeJsonOptions *jo) {
/* Set up the context */
cj5_token tokens[UA_JSON_MAXTOKENCOUNT];
ParseCtx ctx;
memset(&ctx, 0, sizeof(ParseCtx));
ctx.tokens = tokens;
if(options) {
ctx.namespaceMapping = options->namespaceMapping;
ctx.serverUrisSize = options->serverUrisSize;
ctx.serverUris = options->serverUris;
ctx.customTypes = options->customTypes;
PubSubDecodeJsonCtx ctx;
memset(&ctx, 0, sizeof(PubSubDecodeJsonCtx));
ctx.ctx.tokens = tokens;
if(eo)
ctx.eo = *eo;
if(jo) {
ctx.ctx.namespaceMapping = jo->namespaceMapping;
ctx.ctx.serverUrisSize = jo->serverUrisSize;
ctx.ctx.serverUris = jo->serverUris;
ctx.ctx.customTypes = jo->customTypes;
}
status ret = tokenize(&ctx, src, UA_JSON_MAXTOKENCOUNT, NULL);
status ret = tokenize(&ctx.ctx, src, UA_JSON_MAXTOKENCOUNT, NULL);
if(ret != UA_STATUSCODE_GOOD)
goto cleanup;
@ -557,7 +534,7 @@ UA_NetworkMessage_decodeJson(const UA_ByteString *src,
cleanup:
/* Free token array on the heap */
if(ctx.tokens != tokens)
UA_free((void*)(uintptr_t)ctx.tokens);
if(ctx.ctx.tokens != tokens)
UA_free((void*)(uintptr_t)ctx.ctx.tokens);
return ret;
}

View File

@ -356,34 +356,18 @@ UA_PubSubDataSetWriter_generateKeyFrameMessage(UA_PubSubManager *psm,
/* Prepare DataSetMessageContent */
dataSetMessage->header.dataSetMessageValid = true;
dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
dataSetMessage->data.keyFrameData.fieldCount = pds->fieldSize;
dataSetMessage->data.keyFrameData.dataSetFields = (UA_DataValue *)
dataSetMessage->fieldCount = pds->fieldSize;
dataSetMessage->data.keyFrameFields = (UA_DataValue *)
UA_Array_new(pds->fieldSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
dataSetMessage->data.keyFrameData.dataSetMetaDataType = &pds->dataSetMetaData;
if(!dataSetMessage->data.keyFrameData.dataSetFields)
if(!dataSetMessage->data.keyFrameFields)
return UA_STATUSCODE_BADOUTOFMEMORY;
#ifdef UA_ENABLE_JSON_ENCODING
dataSetMessage->data.keyFrameData.fieldNames = (UA_String *)
UA_Array_new(pds->fieldSize, &UA_TYPES[UA_TYPES_STRING]);
if(!dataSetMessage->data.keyFrameData.fieldNames) {
UA_DataSetMessage_clear(dataSetMessage);
return UA_STATUSCODE_BADOUTOFMEMORY;
}
#endif
/* Loop over the fields */
size_t counter = 0;
UA_DataSetField *dsf;
TAILQ_FOREACH(dsf, &pds->fields, listEntry) {
#ifdef UA_ENABLE_JSON_ENCODING
/* Set the field name alias */
UA_String_copy(&dsf->config.field.variable.fieldNameAlias,
&dataSetMessage->data.keyFrameData.fieldNames[counter]);
#endif
/* Sample the value */
UA_DataValue *dfv = &dataSetMessage->data.keyFrameData.dataSetFields[counter];
UA_DataValue *dfv = &dataSetMessage->data.keyFrameFields[counter];
UA_PubSubDataSetField_sampleValue(psm, dsf, dfv);
/* Deactivate statuscode? */
@ -443,7 +427,7 @@ UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_PubSubManager *psm,
UA_DataSetWriterSample *ls = &dsw->lastSamples[counter];
if(!UA_Variant_equal(&ls->value.value, &value.value)) {
/* increase fieldCount for current delta message */
dsm->data.deltaFrameData.fieldCount++;
dsm->fieldCount++;
ls->valueChanged = true;
/* Update last stored sample */
@ -463,8 +447,8 @@ UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_PubSubManager *psm,
if(!deltaFields)
return UA_STATUSCODE_BADOUTOFMEMORY;
dsm->data.deltaFrameData.deltaFrameFields = deltaFields;
dsm->data.deltaFrameData.fieldCount = counter;
dsm->fieldCount = counter;
dsm->data.deltaFrameFields = deltaFields;
size_t currentDeltaField = 0;
for(size_t i = 0; i < pds->fieldSize; i++) {
@ -473,8 +457,8 @@ UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_PubSubManager *psm,
UA_DataSetMessage_DeltaFrameField *dff = &deltaFields[currentDeltaField];
dff->fieldIndex = (UA_UInt16) i;
UA_DataValue_copy(&dsw->lastSamples[i].value, &dff->fieldValue);
dff->index = (UA_UInt16)i;
UA_DataValue_copy(&dsw->lastSamples[i].value, &dff->value);
/* Reset the changed flag */
dsw->lastSamples[i].valueChanged = false;
@ -482,21 +466,21 @@ UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_PubSubManager *psm,
/* Deactivate statuscode? */
if(((u64)dsw->config.dataSetFieldContentMask &
(u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
dff->fieldValue.hasStatus = false;
dff->value.hasStatus = false;
/* Deactivate timestamps? */
if(((u64)dsw->config.dataSetFieldContentMask &
(u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
dff->fieldValue.hasSourceTimestamp = false;
dff->value.hasSourceTimestamp = false;
if(((u64)dsw->config.dataSetFieldContentMask &
(u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
dff->fieldValue.hasServerPicoseconds = false;
dff->value.hasServerPicoseconds = false;
if(((u64)dsw->config.dataSetFieldContentMask &
(u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
dff->fieldValue.hasServerTimestamp = false;
dff->value.hasServerTimestamp = false;
if(((u64)dsw->config.dataSetFieldContentMask &
(u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
dff->fieldValue.hasServerPicoseconds = false;
dff->value.hasServerPicoseconds = false;
currentDeltaField++;
}
@ -562,9 +546,6 @@ UA_DataSetWriter_generateDataSetMessage(UA_PubSubManager *psm,
// dsm->configuredSize = 0;
}
/* setting configured size in the dataSetMessage to add padding later on */
dataSetMessage->configuredSize = dsm->configuredSize;
/* Std: 'The DataSetMessageContentMask defines the flags for the content
* of the DataSetMessage header.' */
if((u64)dsm->dataSetMessageContentMask &
@ -658,7 +639,7 @@ UA_DataSetWriter_generateDataSetMessage(UA_PubSubManager *psm,
/* Prepare DataSetMessageContent for the heartbeat message */
dataSetMessage->header.dataSetMessageValid = true;
dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
dataSetMessage->data.keyFrameData.fieldCount = 0;
dataSetMessage->fieldCount = 0;
return UA_STATUSCODE_GOOD;
}

View File

@ -574,24 +574,21 @@ encryptAndSign(UA_WriterGroup *wg, const UA_NetworkMessage *nm,
}
static UA_StatusCode
encodeNetworkMessage(UA_WriterGroup *wg, UA_NetworkMessage *nm,
UA_ByteString *buf) {
UA_Byte *bufPos = buf->data;
UA_Byte *bufEnd = &buf->data[buf->length];
UA_Byte *networkMessageStart = bufPos;
UA_StatusCode rv = UA_NetworkMessage_encodeHeaders(nm, &bufPos, bufEnd);
encodeNetworkMessage(UA_WriterGroup *wg, PubSubEncodeCtx *ctx,
UA_NetworkMessage *nm, UA_ByteString *buf) {
UA_Byte *networkMessageStart = buf->data;
UA_StatusCode rv = UA_NetworkMessage_encodeHeaders(ctx, nm);
UA_CHECK_STATUS(rv, return rv);
UA_Byte *payloadStart = bufPos;
rv = UA_NetworkMessage_encodePayload(nm, &bufPos, bufEnd);
UA_Byte *payloadStart = ctx->ctx.pos;
rv = UA_NetworkMessage_encodePayload(ctx, nm);
UA_CHECK_STATUS(rv, return rv);
rv = UA_NetworkMessage_encodeFooters(nm, &bufPos, bufEnd);
rv = UA_NetworkMessage_encodeFooters(ctx, nm);
UA_CHECK_STATUS(rv, return rv);
/* Encrypt and Sign the message */
UA_Byte *footerEnd = bufPos;
UA_Byte *footerEnd = ctx->ctx.pos;
return encryptAndSign(wg, nm, networkMessageStart, payloadStart, footerEnd);
}
@ -634,8 +631,28 @@ sendNetworkMessageJson(UA_PubSubManager *psm, UA_PubSubConnection *connection, U
for(size_t i = 0; i < dsmCount; i++)
nm.payload.dataSetPayload.dataSetMessages[i].dataSetWriterId = writerIds[i];
PubSubEncodeJsonCtx ctx;
memset(&ctx, 0, sizeof(PubSubEncodeJsonCtx));
/* Prepare the metadata to encode the DataSetMessages */
size_t i = 0;
UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, wg->writersCount);
memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * wg->writersCount);
ctx.eo.metaData = emd;
ctx.eo.metaDataSize = wg->writersCount;
UA_DataSetWriter *dsw;
LIST_FOREACH(dsw, &wg->writers, listEntry) {
emd[i].dataSetWriterId = dsw->config.dataSetWriterId;
UA_PublishedDataSet *pds = dsw->connectedDataSet;
if(pds) {
emd[i].fields = pds->dataSetMetaData.fields;
emd[i].fieldsSize = pds->dataSetMetaData.fieldsSize;
}
i++;
}
/* Compute the message length */
size_t msgSize = UA_NetworkMessage_calcSizeJsonInternal(&nm, NULL, NULL, 0, true);
size_t msgSize = UA_NetworkMessage_calcSizeJson(&nm, &ctx.eo, NULL);
UA_ConnectionManager *cm = connection->cm;
if(!cm)
@ -656,14 +673,14 @@ sendNetworkMessageJson(UA_PubSubManager *psm, UA_PubSubConnection *connection, U
UA_CHECK_STATUS(res, return res);
/* Encode the message */
UA_Byte *bufPos = buf.data;
const UA_Byte *bufEnd = &buf.data[msgSize];
res = UA_NetworkMessage_encodeJsonInternal(&nm, &bufPos, &bufEnd, NULL, NULL, 0, true);
ctx.ctx.pos = buf.data;
ctx.ctx.end = &buf.data[msgSize];
res = UA_NetworkMessage_encodeJsonInternal(&ctx, &nm);
if(res != UA_STATUSCODE_GOOD) {
cm->freeNetworkBuffer(cm, sendChannel, &buf);
return res;
}
UA_assert(bufPos == bufEnd);
UA_assert(ctx.ctx.pos == ctx.ctx.end);
/* Send the prepared messages */
sendNetworkMessageBuffer(psm, wg, connection, sendChannel, &buf);
@ -782,9 +799,30 @@ sendNetworkMessageBinary(UA_PubSubManager *psm, UA_PubSubConnection *connection,
&wg->config.transportSettings, &nm);
UA_CHECK_STATUS(rv, return rv);
PubSubEncodeCtx ctx;
memset(&ctx, 0, sizeof(PubSubEncodeCtx));
/* Prepare the metadata with information from the readers to decode the
* DataSetMessages */
size_t i = 0;
UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, wg->writersCount);
memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * wg->writersCount);
ctx.eo.metaData = emd;
ctx.eo.metaDataSize = wg->writersCount;
UA_DataSetWriter *dsw;
LIST_FOREACH(dsw, &wg->writers, listEntry) {
emd[i].dataSetWriterId = dsw->config.dataSetWriterId;
UA_PublishedDataSet *pds = dsw->connectedDataSet;
if(pds) {
emd[i].fields = pds->dataSetMetaData.fields;
emd[i].fieldsSize = pds->dataSetMetaData.fieldsSize;
}
i++;
}
/* Compute the message size. Add the overhead for the security signature.
* There is no padding and the encryption incurs no size overhead. */
size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nm);
size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nm, &ctx.eo);
if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE) {
UA_PubSubSecurityPolicy *sp = wg->config.securityPolicy;
msgSize += sp->symmetricModule.cryptoModule.
@ -810,7 +848,9 @@ sendNetworkMessageBinary(UA_PubSubManager *psm, UA_PubSubConnection *connection,
UA_CHECK_STATUS(rv, return rv);
/* Encode and encrypt the message */
rv = encodeNetworkMessage(wg, &nm, &buf);
ctx.ctx.pos = buf.data;
ctx.ctx.end = &buf.data[buf.length];
rv = encodeNetworkMessage(wg, &ctx, &nm, &buf);
if(rv != UA_STATUSCODE_GOOD) {
cm->freeNetworkBuffer(cm, sendChannel, &buf);
return rv;
@ -1514,10 +1554,30 @@ UA_Server_computeWriterGroupOffsetTable(UA_Server *server,
memset(&networkMessage, 0, sizeof(networkMessage));
memset(ot, 0, sizeof(UA_PubSubOffsetTable));
/* Prepare the metadata encode the DataSetMessages */
PubSubEncodeCtx ctx;
memset(&ctx, 0, sizeof(PubSubEncodeCtx));
ctx.ot = ot;
size_t i = 0;
UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, wg->writersCount);
memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * wg->writersCount);
ctx.eo.metaData = emd;
ctx.eo.metaDataSize = wg->writersCount;
UA_DataSetWriter *dsw;
LIST_FOREACH(dsw, &wg->writers, listEntry) {
emd[i].dataSetWriterId = dsw->config.dataSetWriterId;
UA_PublishedDataSet *pds = dsw->connectedDataSet;
if(pds) {
emd[i].fields = pds->dataSetMetaData.fields;
emd[i].fieldsSize = pds->dataSetMetaData.fieldsSize;
}
i++;
}
/* Validate the DataSetWriters and generate their DataSetMessage */
size_t msgSize;
size_t dsmCount = 0;
UA_DataSetWriter *dsw;
UA_StatusCode res = UA_STATUSCODE_GOOD;
UA_STACKARRAY(UA_UInt16, dsWriterIds, wg->writersCount);
UA_STACKARRAY(UA_DataSetMessage, dsmStore, wg->writersCount);
@ -1539,14 +1599,14 @@ UA_Server_computeWriterGroupOffsetTable(UA_Server *server,
/* Compute the message length and generate the old format offset-table (done
* inside calcSizeBinary) */
msgSize = UA_NetworkMessage_calcSizeBinaryWithOffsetTable(&networkMessage, ot);
msgSize = UA_NetworkMessage_calcSizeBinaryInternal(&ctx, &networkMessage);
if(msgSize == 0) {
res = UA_STATUSCODE_BADINTERNALERROR;
goto cleanup;
}
/* Create the encoded network message */
res = UA_NetworkMessage_encodeBinary(&networkMessage, &ot->networkMessage);
res = UA_NetworkMessage_encodeBinary(&networkMessage, &ot->networkMessage, &ctx.eo);
if(res != UA_STATUSCODE_GOOD)
goto cleanup;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,14 +8,27 @@
#include <open62541/client.h>
#include <open62541/types.h>
#include <open62541/util.h>
#include "ua_pubsub_networkmessage.h"
#include <open62541/pubsub.h>
#include <check.h>
#include <stdlib.h>
START_TEST(UA_PubSub_EncodeAllOptionalFields) {
UA_UInt16 dsWriter1 = 12345;
/* Set up the metadata for decoding */
UA_NetworkMessage_EncodingOptions eo = {0};
UA_DataSetMessage_EncodingMetaData emd[1] = {0};
UA_FieldMetaData fmd[1] = {0};
fmd[0].name = UA_STRING("Field1");
eo.metaData = emd;
eo.metaDataSize = 1;
emd[0].dataSetWriterId = dsWriter1;
emd[0].fields = fmd;
emd[0].fieldsSize = 1;
UA_NetworkMessage m;
memset(&m, 0, sizeof(UA_NetworkMessage));
m.version = 1;
@ -41,58 +54,50 @@ START_TEST(UA_PubSub_EncodeAllOptionalFields) {
m.dataSetClassId.data2 = 2;
m.dataSetClassId.data3 = 3;
UA_DataSetMessage *dsm = m.payload.dataSetPayload.dataSetMessages;
/* DatasetMessage */
m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageValid = true;
m.payload.dataSetPayload.dataSetMessages[0].header.fieldEncoding = UA_FIELDENCODING_VARIANT;
m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
dsm->header.dataSetMessageValid = true;
dsm->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
dsm->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
UA_UInt16 fieldCountDS1 = 1;
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount = fieldCountDS1;
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields =
(UA_DataValue*)UA_Array_new(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]);
UA_DataValue_init(&m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0]);
dsm->fieldCount = fieldCountDS1;
dsm->data.keyFrameFields = UA_DataValue_new();
/* enable DataSetMessageSequenceNr */
m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageSequenceNrEnabled = true;
m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageSequenceNr = 4711;
dsm->header.dataSetMessageSequenceNrEnabled = true;
dsm->header.dataSetMessageSequenceNr = 4711;
/* enable metaDataVersion */
m.payload.dataSetPayload.dataSetMessages[0].header.configVersionMajorVersionEnabled = true;
m.payload.dataSetPayload.dataSetMessages[0].header.configVersionMinorVersionEnabled = true;
m.payload.dataSetPayload.dataSetMessages[0].header.configVersionMajorVersion = 42;
m.payload.dataSetPayload.dataSetMessages[0].header.configVersionMinorVersion = 7;
dsm->header.configVersionMajorVersionEnabled = true;
dsm->header.configVersionMinorVersionEnabled = true;
dsm->header.configVersionMajorVersion = 42;
dsm->header.configVersionMinorVersion = 7;
/* enable timestamp */
m.payload.dataSetPayload.dataSetMessages[0].header.timestampEnabled = true;
m.payload.dataSetPayload.dataSetMessages[0].header.timestamp = 11111111111111;
dsm->header.timestampEnabled = true;
dsm->header.timestamp = 11111111111111;
/* enable status */
m.payload.dataSetPayload.dataSetMessages[0].header.statusEnabled = true;
m.payload.dataSetPayload.dataSetMessages[0].header.status = 12345;
/* Set fieldnames */
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames =
(UA_String*)UA_Array_new(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_STRING]);
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0] = UA_STRING_ALLOC("Field1");
dsm->header.statusEnabled = true;
dsm->header.status = 12345;
UA_UInt32 iv = 27;
UA_Variant_setScalarCopy(&m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value, &iv, &UA_TYPES[UA_TYPES_UINT32]);
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue = true;
UA_Variant_setScalarCopy(&dsm->data.keyFrameFields[0].value,
&iv, &UA_TYPES[UA_TYPES_UINT32]);
dsm->data.keyFrameFields[0].hasValue = true;
size_t size = UA_NetworkMessage_calcSizeJsonInternal(&m, NULL, NULL, 0, true);
size_t size = UA_NetworkMessage_calcSizeJson(&m, &eo, NULL);
UA_ByteString buffer;
UA_ByteString buffer = UA_BYTESTRING_NULL;
UA_StatusCode rv = UA_ByteString_allocBuffer(&buffer, size+1);
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
memset(buffer.data, 0, size+1);
UA_Byte *bufPos = buffer.data;
memset(bufPos, 0, size+1);
const UA_Byte *bufEnd = &(buffer.data[buffer.length]);
rv = UA_NetworkMessage_encodeJsonInternal(&m, &bufPos, &bufEnd, NULL, NULL, 0, true);
*bufPos = 0;
// then
rv = UA_NetworkMessage_encodeJson(&m, &buffer, &eo, NULL);
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
// then
char* result = "{\"MessageId\":\"ABCDEFGH\",\"MessageType\":\"ua-data\",\"PublisherId\":\"65535\",\"DataSetClassId\":\"00000001-0002-0003-0000-000000000000\",\"Messages\":[{\"DataSetWriterId\":12345,\"SequenceNumber\":4711,\"MetaDataVersion\":{\"MajorVersion\":42,\"MinorVersion\":7},\"Timestamp\":\"1601-01-13T20:38:31.1111111Z\",\"Status\":12345,\"MessageType\":\"ua-keyframe\",\"Payload\":{\"Field1\":{\"UaType\":7,\"Value\":27}}}]}";
ck_assert_str_eq(result, (char*)buffer.data);
@ -104,6 +109,27 @@ END_TEST
START_TEST(UA_PubSub_EnDecode) {
UA_UInt16 dsWriter1 = 4;
UA_UInt16 dsWriter2 = 7;
/* Set up the metadata for decoding */
UA_NetworkMessage_EncodingOptions eo = {0};
UA_DataSetMessage_EncodingMetaData emd[2]= {0};
UA_FieldMetaData fmd0[1] = {0};
UA_FieldMetaData fmd1[2] = {0};
fmd0[0].name = UA_STRING("Field1");
emd[0].fields = fmd0;
emd[0].fieldsSize = 1;
emd[0].dataSetWriterId = dsWriter1;
fmd1[0].name = UA_STRING("Field2.1");
fmd1[0].name = UA_STRING("Field2.2");
emd[1].fields = fmd1;
emd[1].fieldsSize = 2;
emd[1].dataSetWriterId = dsWriter2;
eo.metaData = emd;
eo.metaDataSize = 2;
UA_NetworkMessage m;
memset(&m, 0, sizeof(UA_NetworkMessage));
m.version = 1;
@ -112,68 +138,57 @@ START_TEST(UA_PubSub_EnDecode) {
m.payload.dataSetPayload.dataSetMessages = (UA_DataSetMessage*)
UA_calloc(2, sizeof(UA_DataSetMessage));
m.payload.dataSetPayload.dataSetMessagesSize = 2;
m.payload.dataSetPayload.dataSetMessages[0].dataSetWriterId = dsWriter1;
m.payload.dataSetPayload.dataSetMessages[1].dataSetWriterId = dsWriter2;
m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageValid = true;
m.payload.dataSetPayload.dataSetMessages[0].header.fieldEncoding = UA_FIELDENCODING_VARIANT;
m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
UA_DataSetMessage *dsm0 = &m.payload.dataSetPayload.dataSetMessages[0];
UA_DataSetMessage *dsm1 = &m.payload.dataSetPayload.dataSetMessages[1];
dsm0->dataSetWriterId = dsWriter1;
dsm1->dataSetWriterId = dsWriter2;
dsm0->header.dataSetMessageValid = true;
dsm0->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
dsm0->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
UA_UInt16 fieldCountDS1 = 1;
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount = fieldCountDS1;
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields =
(UA_DataValue*)UA_Array_new(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]);
UA_DataValue_init(&m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0]);
/* Set fieldnames */
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames =
(UA_String*)UA_Array_new(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_STRING]);
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0] = UA_STRING_ALLOC("Field1");
dsm0->fieldCount = fieldCountDS1;
dsm0->data.keyFrameFields = UA_DataValue_new();
UA_UInt32 iv = 27;
UA_Variant_setScalarCopy(&m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value, &iv, &UA_TYPES[UA_TYPES_UINT32]);
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue = true;
UA_Variant_setScalarCopy(&dsm0->data.keyFrameFields[0].value, &iv, &UA_TYPES[UA_TYPES_UINT32]);
dsm0->data.keyFrameFields[0].hasValue = true;
m.payload.dataSetPayload.dataSetMessages[1].header.dataSetMessageValid = true;
m.payload.dataSetPayload.dataSetMessages[1].header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
m.payload.dataSetPayload.dataSetMessages[1].header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
dsm1->header.dataSetMessageValid = true;
dsm1->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
dsm1->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
UA_UInt16 fieldCountDS2 = 2;
m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.fieldCount = fieldCountDS2;
m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields = (UA_DataSetMessage_DeltaFrameField*)
UA_calloc(m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.fieldCount, sizeof(UA_DataSetMessage_DeltaFrameField));
/* Set fieldnames */
m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.fieldNames =
(UA_String*)UA_Array_new(m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.fieldCount, &UA_TYPES[UA_TYPES_STRING]);
m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.fieldNames[0] = UA_STRING_ALLOC("Field2.1");
m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.fieldNames[1] = UA_STRING_ALLOC("Field2.2");
dsm1->fieldCount = fieldCountDS2;
dsm1->data.deltaFrameFields = (UA_DataSetMessage_DeltaFrameField*)
UA_calloc(dsm1->fieldCount, sizeof(UA_DataSetMessage_DeltaFrameField));
UA_Guid gv = UA_Guid_random();
UA_DataValue_init(&m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.dataSetFields[0]);
UA_Variant_setScalarCopy(&m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.dataSetFields[0].value, &gv, &UA_TYPES[UA_TYPES_GUID]);
m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.dataSetFields[0].hasValue = true;
UA_DataValue_init(&dsm1->data.keyFrameFields[0]);
UA_Variant_setScalarCopy(&dsm1->data.keyFrameFields[0].value, &gv, &UA_TYPES[UA_TYPES_GUID]);
dsm1->data.keyFrameFields[0].hasValue = true;
UA_DataValue_init(&m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.dataSetFields[1]);
UA_DataValue_init(&dsm1->data.keyFrameFields[1]);
UA_Int64 iv64 = 152478978534;
UA_Variant_setScalarCopy(&m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.dataSetFields[1].value, &iv64, &UA_TYPES[UA_TYPES_INT64]);
m.payload.dataSetPayload.dataSetMessages[1].data.keyFrameData.dataSetFields[1].hasValue = true;
UA_Variant_setScalarCopy(&dsm1->data.keyFrameFields[1].value, &iv64, &UA_TYPES[UA_TYPES_INT64]);
dsm1->data.keyFrameFields[1].hasValue = true;
size_t size = UA_NetworkMessage_calcSizeJsonInternal(&m, NULL, NULL, 0, true);
size_t size = UA_NetworkMessage_calcSizeJson(&m, &eo, NULL);
UA_ByteString buffer;
UA_StatusCode rv = UA_ByteString_allocBuffer(&buffer, size);
UA_StatusCode rv = UA_ByteString_allocBuffer(&buffer, size+1);
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
memset(buffer.data, 0, size+1);
rv = UA_NetworkMessage_encodeJson(&m, &buffer, &eo, NULL);
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
UA_Byte *bufPos = buffer.data;
memset(bufPos, 0, size);
const UA_Byte *bufEnd = &(buffer.data[buffer.length]);
rv = UA_NetworkMessage_encodeJsonInternal(&m, &bufPos, &bufEnd, NULL, NULL, 0, true);
//*bufPos = 0;
// then
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
UA_NetworkMessage m2;
memset(&m2, 0, sizeof(UA_NetworkMessage));
rv = UA_NetworkMessage_decodeJson(&buffer, &m2, NULL);
rv = UA_NetworkMessage_decodeJson(&buffer, &m2, &eo, NULL);
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
ck_assert(m.networkMessageType == m2.networkMessageType);
ck_assert(m.timestampEnabled == m2.timestampEnabled);
@ -189,14 +204,14 @@ START_TEST(UA_PubSub_EnDecode) {
ck_assert_uint_eq(m2.payload.dataSetPayload.dataSetMessages[1].dataSetWriterId, dsWriter2);
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageValid == m2.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageValid);
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].header.fieldEncoding == m2.payload.dataSetPayload.dataSetMessages[0].header.fieldEncoding);
ck_assert_int_eq(m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount, fieldCountDS1);
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue == m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue);
ck_assert_uint_eq((uintptr_t)m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value.type, (uintptr_t)&UA_TYPES[UA_TYPES_UINT32]);
ck_assert_uint_eq(*(UA_UInt32 *)m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value.data, iv);
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasSourceTimestamp == m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasSourceTimestamp);
ck_assert_int_eq(m2.payload.dataSetPayload.dataSetMessages[0].fieldCount, fieldCountDS1);
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].hasValue == m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].hasValue);
ck_assert_uint_eq((uintptr_t)m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].value.type, (uintptr_t)&UA_TYPES[UA_TYPES_UINT32]);
ck_assert_uint_eq(*(UA_UInt32 *)m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].value.data, iv);
ck_assert(m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].hasSourceTimestamp == m2.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].hasSourceTimestamp);
ck_assert(m.payload.dataSetPayload.dataSetMessages[1].header.dataSetMessageValid == m2.payload.dataSetPayload.dataSetMessages[1].header.dataSetMessageValid);
ck_assert(m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[0].fieldValue.hasSourceTimestamp == m2.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameData.deltaFrameFields[0].fieldValue.hasSourceTimestamp);
ck_assert(m.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameFields[0].value.hasSourceTimestamp == m2.payload.dataSetPayload.dataSetMessages[1].data.deltaFrameFields[0].value.hasSourceTimestamp);
UA_ByteString_clear(&buffer);
UA_NetworkMessage_clear(&m);
UA_NetworkMessage_clear(&m2);
@ -205,12 +220,23 @@ END_TEST
START_TEST(UA_NetworkMessage_oneMessage_twoFields_json_decode) {
// given
/* Set up the metadata for decoding */
UA_NetworkMessage_EncodingOptions eo = {0};
UA_DataSetMessage_EncodingMetaData emd[1]= {0};
UA_FieldMetaData fmd[2] = {0};
fmd[0].name = UA_STRING("Test");
fmd[1].name = UA_STRING("Server localtime");
emd[0].fields = fmd;
emd[0].fieldsSize = 2;
emd[0].dataSetWriterId = 62541;
eo.metaData = emd;
eo.metaDataSize = 2;
UA_NetworkMessage out;
UA_ByteString buf = UA_STRING("{\"MessageId\":\"5ED82C10-50BB-CD07-0120-22521081E8EE\",\"MessageType\":\"ua-data\",\"Messages\":[{\"DataSetWriterId\":62541,\"MetaDataVersion\":{\"MajorVersion\":1478393530,\"MinorVersion\":12345},\"SequenceNumber\":4711,\"Payload\":{\"Test\":{\"UaType\":5,\"Value\":42},\"Server localtime\":{\"UaType\":13,\"Value\":\"2018-06-05T05:58:36.000Z\"}}}]}");
// when
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&buf, &out, NULL);
// then
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&buf, &out, &eo, NULL);
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
//NetworkMessage
@ -244,10 +270,10 @@ START_TEST(UA_NetworkMessage_oneMessage_twoFields_json_decode) {
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageSequenceNr, 4711);
//ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.dataSetWriterId, 62541);
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue, 1);
ck_assert_int_eq(*((UA_UInt16*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value.data), 42);
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[1].hasValue, 1);
UA_DateTime *dt = (UA_DateTime*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[1].value.data;
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].hasValue, 1);
ck_assert_int_eq(*((UA_UInt16*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].value.data), 42);
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[1].hasValue, 1);
UA_DateTime *dt = (UA_DateTime*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[1].value.data;
UA_DateTimeStruct dts = UA_DateTime_toStruct(*dt);
ck_assert_int_eq(dts.year, 2018);
ck_assert_int_eq(dts.month, 6);
@ -264,13 +290,15 @@ START_TEST(UA_NetworkMessage_oneMessage_twoFields_json_decode) {
END_TEST
// Decode without metadata
// The values still come out in order
START_TEST(UA_NetworkMessage_json_decode) {
// given
UA_NetworkMessage out;
memset(&out,0,sizeof(UA_NetworkMessage));
UA_ByteString buf = UA_STRING("{\"MessageId\":\"5ED82C10-50BB-CD07-0120-22521081E8EE\",\"MessageType\":\"ua-data\",\"Messages\":[{\"MetaDataVersion\":{\"MajorVersion\": 47, \"MinorVersion\": 47},\"DataSetWriterId\":62541,\"Status\":22,\"SequenceNumber\":4711,\"Payload\":{\"Test\":{\"UaType\":5,\"Value\":42},\"Server localtime\":{\"UaType\":1,\"Value\":true}}}]}");
// when
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&buf, &out, NULL);
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&buf, &out, NULL, NULL);
// then
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
@ -307,10 +335,10 @@ START_TEST(UA_NetworkMessage_json_decode) {
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].header.configVersionMajorVersion, 47);
//dataSetFields
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue, true);
ck_assert_int_eq(*((UA_UInt16*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].value.data), 42);
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[1].hasValue, true);
ck_assert_int_eq(*((UA_Boolean*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[1].value.data), 1);
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].hasValue, true);
ck_assert_int_eq(*((UA_UInt16*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[0].value.data), 42);
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[1].hasValue, true);
ck_assert_int_eq(*((UA_Boolean*)out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameFields[1].value.data), 1);
UA_NetworkMessage_clear(&out);
}
@ -323,7 +351,7 @@ START_TEST(UA_NetworkMessage_json_decode_messageObject) {
memset(&out,0,sizeof(UA_NetworkMessage));
UA_ByteString buf = UA_STRING("{\"MessageId\":\"5ED82C10-50BB-CD07-0120-22521081E8EE\",\"MessageType\":\"ua-data\",\"Messages\":{\"MetaDataVersion\":{\"MajorVersion\": 47, \"MinorVersion\": 47},\"DataSetWriterId\":62541,\"Status\":22,\"SequenceNumber\":4711,\"Payload\":{\"Test\":{\"UaType\":5,\"Value\":42},\"Server localtime\":{\"UaType\":1,\"Value\":true}}}}");
// when
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&buf, &out, NULL);
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&buf, &out, NULL, NULL);
// then
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
UA_NetworkMessage_clear(&out);
@ -340,47 +368,18 @@ START_TEST(UA_Networkmessage_DataSetFieldsNull_json_decode) {
"[ { \"DataSetWriterId\": 1, \"SequenceNumber\": 224, \"MetaDataVersion\": "
"{ \"MajorVersion\": 1, \"MinorVersion\": 1 },\"Payload\":null}]}");
// when
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&buf, &out, NULL);
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&buf, &out, NULL, NULL);
// then
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
ck_assert_int_eq(out.dataSetClassId.data1, 5);
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages->header.dataSetMessageSequenceNr, 224);
ck_assert_ptr_eq(out.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields, NULL);
ck_assert_ptr_eq(out.payload.dataSetPayload.dataSetMessages->data.keyFrameFields, NULL);
UA_NetworkMessage_clear(&out);
}
END_TEST
START_TEST(UA_NetworkMessage_fieldNames_json_decode) {
// given
UA_NetworkMessage out;
UA_ByteString buf = UA_STRING("{\"MessageId\":\"5ED82C10-50BB-CD07-0120-22521081E8EE\","
"\"MessageType\":\"ua-data\",\"Messages\":"
"[{\"DataSetWriterId\":62541,\"MetaDataVersion\":"
"{\"MajorVersion\":1478393530,\"MinorVersion\":12345},"
"\"SequenceNumber\":4711,\"Payload\":{\"Test\":{\"UaType\":5,\"Value\":42},\"Test2\":"
"{\"UaType\":13,\"Value\":\"2018-06-05T05:58:36.000Z\"}}}]}");
// when
UA_StatusCode retval = UA_NetworkMessage_decodeJson(&buf, &out, NULL);
// then
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
//NetworkMessage
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0].data[0], 'T');
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0].data[1], 'e');
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0].data[2], 's');
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[0].data[3], 't');
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[0], 'T');
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[1], 'e');
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[2], 's');
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[3], 't');
ck_assert_int_eq(out.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldNames[1].data[4], '2');
UA_NetworkMessage_clear(&out);
}
END_TEST
static Suite *testSuite_networkmessage(void) {
Suite *s = suite_create("Built-in Data Types 62541-6 Json");
TCase *tc_json_networkmessage = tcase_create("networkmessage_json");
@ -391,7 +390,6 @@ static Suite *testSuite_networkmessage(void) {
tcase_add_test(tc_json_networkmessage, UA_NetworkMessage_json_decode);
tcase_add_test(tc_json_networkmessage, UA_NetworkMessage_json_decode_messageObject);
tcase_add_test(tc_json_networkmessage, UA_Networkmessage_DataSetFieldsNull_json_decode);
tcase_add_test(tc_json_networkmessage, UA_NetworkMessage_fieldNames_json_decode);
suite_add_tcase(s, tc_json_networkmessage);
return s;

View File

@ -65,18 +65,18 @@ encodeNetworkMessage(const UA_ByteString *buf, UA_ByteString *out) {
options.useReversible = true;
UA_NetworkMessage msg;
UA_StatusCode retval = UA_NetworkMessage_decodeBinary(buf, &msg, NULL);
UA_StatusCode retval = UA_NetworkMessage_decodeBinary(buf, &msg, NULL, NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
size_t jsonLength = UA_NetworkMessage_calcSizeJson(&msg, &options);
size_t jsonLength = UA_NetworkMessage_calcSizeJson(&msg, NULL, &options);
retval = UA_ByteString_allocBuffer(out, jsonLength);
if(retval != UA_STATUSCODE_GOOD) {
UA_NetworkMessage_clear(&msg);
return retval;
}
retval = UA_NetworkMessage_encodeJson(&msg, out, &options);
retval = UA_NetworkMessage_encodeJson(&msg, out, NULL, &options);
UA_NetworkMessage_clear(&msg);
if(retval != UA_STATUSCODE_GOOD)
UA_ByteString_clear(out);
@ -87,18 +87,18 @@ encodeNetworkMessage(const UA_ByteString *buf, UA_ByteString *out) {
static UA_StatusCode
decodeNetworkMessage(const UA_ByteString *buf, UA_ByteString *out) {
UA_NetworkMessage msg;
UA_StatusCode retval = UA_NetworkMessage_decodeJson(buf, &msg, NULL);
UA_StatusCode retval = UA_NetworkMessage_decodeJson(buf, &msg, NULL, NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
size_t binLength = UA_NetworkMessage_calcSizeBinary(&msg);
size_t binLength = UA_NetworkMessage_calcSizeBinary(&msg, NULL);
retval = UA_ByteString_allocBuffer(out, binLength);
if(retval != UA_STATUSCODE_GOOD) {
UA_NetworkMessage_clear(&msg);
return retval;
}
retval = UA_NetworkMessage_encodeBinary(&msg, out);
retval = UA_NetworkMessage_encodeBinary(&msg, out, NULL);
UA_NetworkMessage_clear(&msg);
if(retval != UA_STATUSCODE_GOOD)
UA_ByteString_clear(out);