ua_pubsub_writer.c 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
  6. * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
  7. * Copyright (c) 2019 Kalycito Infotech Private Limited
  8. */
  9. #include <open62541/server_pubsub.h>
  10. #include "server/ua_server_internal.h"
  11. #ifdef UA_ENABLE_PUBSUB /* conditional compilation */
  12. #include "ua_pubsub.h"
  13. #include "ua_pubsub_networkmessage.h"
  14. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  15. #include "ua_pubsub_ns0.h"
  16. #endif
  17. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  18. #include "ua_types_encoding_binary.h"
  19. #endif
  20. #define UA_MAX_STACKBUF 512 /* Max size of network messages on the stack */
  21. /* Forward declaration */
  22. static void
  23. UA_WriterGroup_clear(UA_Server *server, UA_WriterGroup *writerGroup);
  24. static void
  25. UA_DataSetField_clear(UA_DataSetField *field);
  26. static UA_StatusCode
  27. generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
  28. UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount,
  29. UA_ExtensionObject *messageSettings,
  30. UA_ExtensionObject *transportSettings,
  31. UA_NetworkMessage *networkMessage);
  32. static UA_StatusCode
  33. UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *dataSetMessage,
  34. UA_DataSetWriter *dataSetWriter);
  35. /**********************************************/
  36. /* Connection */
  37. /**********************************************/
  38. UA_StatusCode
  39. UA_PubSubConnectionConfig_copy(const UA_PubSubConnectionConfig *src,
  40. UA_PubSubConnectionConfig *dst) {
  41. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  42. memcpy(dst, src, sizeof(UA_PubSubConnectionConfig));
  43. retVal |= UA_String_copy(&src->name, &dst->name);
  44. retVal |= UA_Variant_copy(&src->address, &dst->address);
  45. retVal |= UA_String_copy(&src->transportProfileUri, &dst->transportProfileUri);
  46. retVal |= UA_Variant_copy(&src->connectionTransportSettings, &dst->connectionTransportSettings);
  47. if(src->connectionPropertiesSize > 0){
  48. dst->connectionProperties = (UA_KeyValuePair *)
  49. UA_calloc(src->connectionPropertiesSize, sizeof(UA_KeyValuePair));
  50. if(!dst->connectionProperties){
  51. return UA_STATUSCODE_BADOUTOFMEMORY;
  52. }
  53. for(size_t i = 0; i < src->connectionPropertiesSize; i++){
  54. retVal |= UA_QualifiedName_copy(&src->connectionProperties[i].key,
  55. &dst->connectionProperties[i].key);
  56. retVal |= UA_Variant_copy(&src->connectionProperties[i].value,
  57. &dst->connectionProperties[i].value);
  58. }
  59. }
  60. return retVal;
  61. }
  62. UA_StatusCode
  63. UA_Server_getPubSubConnectionConfig(UA_Server *server, const UA_NodeId connection,
  64. UA_PubSubConnectionConfig *config) {
  65. if(!config)
  66. return UA_STATUSCODE_BADINVALIDARGUMENT;
  67. UA_PubSubConnection *currentPubSubConnection =
  68. UA_PubSubConnection_findConnectionbyId(server, connection);
  69. if(!currentPubSubConnection)
  70. return UA_STATUSCODE_BADNOTFOUND;
  71. UA_PubSubConnectionConfig tmpPubSubConnectionConfig;
  72. //deep copy of the actual config
  73. UA_PubSubConnectionConfig_copy(currentPubSubConnection->config, &tmpPubSubConnectionConfig);
  74. *config = tmpPubSubConnectionConfig;
  75. return UA_STATUSCODE_GOOD;
  76. }
  77. UA_PubSubConnection *
  78. UA_PubSubConnection_findConnectionbyId(UA_Server *server, UA_NodeId connectionIdentifier) {
  79. UA_PubSubConnection *pubSubConnection;
  80. TAILQ_FOREACH(pubSubConnection, &server->pubSubManager.connections, listEntry){
  81. if(UA_NodeId_equal(&connectionIdentifier, &pubSubConnection->identifier)){
  82. return pubSubConnection;
  83. }
  84. }
  85. return NULL;
  86. }
  87. void
  88. UA_PubSubConnectionConfig_clear(UA_PubSubConnectionConfig *connectionConfig) {
  89. UA_String_clear(&connectionConfig->name);
  90. UA_String_clear(&connectionConfig->transportProfileUri);
  91. UA_Variant_clear(&connectionConfig->connectionTransportSettings);
  92. UA_Variant_clear(&connectionConfig->address);
  93. for(size_t i = 0; i < connectionConfig->connectionPropertiesSize; i++){
  94. UA_QualifiedName_clear(&connectionConfig->connectionProperties[i].key);
  95. UA_Variant_clear(&connectionConfig->connectionProperties[i].value);
  96. }
  97. UA_free(connectionConfig->connectionProperties);
  98. }
  99. void
  100. UA_PubSubConnection_clear(UA_Server *server, UA_PubSubConnection *connection) {
  101. //delete connection config
  102. UA_PubSubConnectionConfig_clear(connection->config);
  103. //remove contained WriterGroups
  104. UA_WriterGroup *writerGroup, *tmpWriterGroup;
  105. LIST_FOREACH_SAFE(writerGroup, &connection->writerGroups, listEntry, tmpWriterGroup){
  106. UA_Server_removeWriterGroup(server, writerGroup->identifier);
  107. }
  108. /* remove contained ReaderGroups */
  109. UA_ReaderGroup *readerGroups, *tmpReaderGroup;
  110. LIST_FOREACH_SAFE(readerGroups, &connection->readerGroups, listEntry, tmpReaderGroup){
  111. UA_Server_removeReaderGroup(server, readerGroups->identifier);
  112. }
  113. UA_NodeId_clear(&connection->identifier);
  114. if(connection->channel){
  115. connection->channel->close(connection->channel);
  116. }
  117. UA_free(connection->config);
  118. }
  119. UA_StatusCode
  120. UA_PubSubConnection_regist(UA_Server *server, UA_NodeId *connectionIdentifier) {
  121. UA_PubSubConnection *connection =
  122. UA_PubSubConnection_findConnectionbyId(server, *connectionIdentifier);
  123. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  124. if(connection == NULL) {
  125. return UA_STATUSCODE_BADNOTFOUND;
  126. }
  127. retval = connection->channel->regist(connection->channel, NULL, NULL);
  128. if(retval != UA_STATUSCODE_GOOD) {
  129. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  130. "register channel failed: 0x%x!", retval);
  131. }
  132. return retval;
  133. }
  134. UA_StatusCode
  135. UA_Server_addWriterGroup(UA_Server *server, const UA_NodeId connection,
  136. const UA_WriterGroupConfig *writerGroupConfig,
  137. UA_NodeId *writerGroupIdentifier) {
  138. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  139. if(!writerGroupConfig)
  140. return UA_STATUSCODE_BADINVALIDARGUMENT;
  141. //search the connection by the given connectionIdentifier
  142. UA_PubSubConnection *currentConnectionContext =
  143. UA_PubSubConnection_findConnectionbyId(server, connection);
  144. if(!currentConnectionContext)
  145. return UA_STATUSCODE_BADNOTFOUND;
  146. if(currentConnectionContext->config->configurationFrozen){
  147. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  148. "Adding WriterGroup failed. PubSubConnection is frozen.");
  149. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  150. }
  151. //allocate memory for new WriterGroup
  152. UA_WriterGroup *newWriterGroup = (UA_WriterGroup *) UA_calloc(1, sizeof(UA_WriterGroup));
  153. if(!newWriterGroup)
  154. return UA_STATUSCODE_BADOUTOFMEMORY;
  155. newWriterGroup->linkedConnection = currentConnectionContext->identifier;
  156. newWriterGroup->linkedConnectionPtr = currentConnectionContext;
  157. UA_PubSubManager_generateUniqueNodeId(server, &newWriterGroup->identifier);
  158. if(writerGroupIdentifier){
  159. UA_NodeId_copy(&newWriterGroup->identifier, writerGroupIdentifier);
  160. }
  161. //deep copy of the config
  162. UA_WriterGroupConfig tmpWriterGroupConfig;
  163. retVal |= UA_WriterGroupConfig_copy(writerGroupConfig, &tmpWriterGroupConfig);
  164. if(!tmpWriterGroupConfig.messageSettings.content.decoded.type) {
  165. UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new();
  166. tmpWriterGroupConfig.messageSettings.content.decoded.data = wgm;
  167. tmpWriterGroupConfig.messageSettings.content.decoded.type =
  168. &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
  169. tmpWriterGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
  170. }
  171. newWriterGroup->config = tmpWriterGroupConfig;
  172. LIST_INSERT_HEAD(&currentConnectionContext->writerGroups, newWriterGroup, listEntry);
  173. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  174. addWriterGroupRepresentation(server, newWriterGroup);
  175. #endif
  176. return retVal;
  177. }
  178. UA_StatusCode
  179. UA_Server_removeWriterGroup(UA_Server *server, const UA_NodeId writerGroup){
  180. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  181. if(!wg)
  182. return UA_STATUSCODE_BADNOTFOUND;
  183. if(wg->config.configurationFrozen){
  184. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  185. "Delete WriterGroup failed. WriterGroup is frozen.");
  186. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  187. }
  188. UA_PubSubConnection *connection =
  189. UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
  190. if(!connection)
  191. return UA_STATUSCODE_BADNOTFOUND;
  192. if(connection->config->configurationFrozen){
  193. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  194. "Delete WriterGroup failed. PubSubConnection is frozen.");
  195. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  196. }
  197. if(wg->state == UA_PUBSUBSTATE_OPERATIONAL){
  198. //unregister the publish callback
  199. UA_PubSubManager_removeRepeatedPubSubCallback(server, wg->publishCallbackId);
  200. }
  201. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  202. removeGroupRepresentation(server, wg);
  203. #endif
  204. UA_WriterGroup_clear(server, wg);
  205. LIST_REMOVE(wg, listEntry);
  206. UA_free(wg);
  207. return UA_STATUSCODE_GOOD;
  208. }
  209. UA_StatusCode
  210. UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup){
  211. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  212. if(!wg)
  213. return UA_STATUSCODE_BADNOTFOUND;
  214. //PubSubConnection freezeCounter++
  215. UA_PubSubConnection *pubSubConnection = UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
  216. pubSubConnection->configurationFreezeCounter++;
  217. pubSubConnection->config->configurationFrozen = UA_TRUE;
  218. //WriterGroup freeze
  219. wg->config.configurationFrozen = UA_TRUE;
  220. //DataSetWriter freeze
  221. UA_DataSetWriter *dataSetWriter;
  222. LIST_FOREACH(dataSetWriter, &wg->writers, listEntry){
  223. dataSetWriter->config.configurationFrozen = UA_TRUE;
  224. //PublishedDataSet freezeCounter++
  225. UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  226. publishedDataSet->configurationFreezeCounter++;
  227. publishedDataSet->config.configurationFrozen = UA_TRUE;
  228. //DataSetFields freeze
  229. UA_DataSetField *dataSetField;
  230. TAILQ_FOREACH(dataSetField, &publishedDataSet->fields, listEntry){
  231. dataSetField->config.configurationFrozen = UA_TRUE;
  232. }
  233. }
  234. if(wg->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE){
  235. size_t dsmCount = 0;
  236. if(wg->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP) {
  237. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  238. "PubSub-RT configuration fail: Non-RT capable encoding.");
  239. return UA_STATUSCODE_BADNOTSUPPORTED;
  240. }
  241. //TODO Clarify: should we only allow = maxEncapsulatedDataSetMessageCount == 1 with RT?
  242. //TODO Clarify: Behaviour if the finale size is more than MTU
  243. /* Generate data set messages */
  244. UA_STACKARRAY(UA_UInt16, dsWriterIds, wg->writersCount);
  245. UA_STACKARRAY(UA_DataSetMessage, dsmStore, wg->writersCount);
  246. UA_DataSetWriter *dsw;
  247. LIST_FOREACH(dsw, &wg->writers, listEntry) {
  248. /* Find the dataset */
  249. UA_PublishedDataSet *pds =
  250. UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet);
  251. if(!pds) {
  252. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  253. "PubSub Publish: PublishedDataSet not found");
  254. continue;
  255. }
  256. if(pds->promotedFieldsCount > 0) {
  257. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  258. "PubSub-RT configuration fail: PDS contains promoted fields.");
  259. return UA_STATUSCODE_BADNOTSUPPORTED;
  260. }
  261. UA_DataSetField *dsf;
  262. TAILQ_FOREACH(dsf, &pds->fields, listEntry){
  263. if(!dsf->config.field.variable.staticValueSourceEnabled){
  264. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  265. "PubSub-RT configuration fail: PDS contains variables with dynamic length types.");
  266. return UA_STATUSCODE_BADNOTSUPPORTED;
  267. }
  268. if((UA_NodeId_equal(&dsf->fieldMetaData.dataType, &UA_TYPES[UA_TYPES_STRING].typeId) ||
  269. UA_NodeId_equal(&dsf->fieldMetaData.dataType, &UA_TYPES[UA_TYPES_BYTESTRING].typeId)) &&
  270. dsf->fieldMetaData.maxStringLength == 0){
  271. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  272. "PubSub-RT configuration fail: PDS contains String/ByteString with dynamic length.");
  273. return UA_STATUSCODE_BADNOTSUPPORTED;
  274. } else if(!UA_DataType_isNumeric(UA_findDataType(&dsf->fieldMetaData.dataType))){
  275. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  276. "PubSub-RT configuration fail: PDS contains variable with dynamic size.");
  277. return UA_STATUSCODE_BADNOTSUPPORTED;
  278. }
  279. }
  280. /* Generate the DSM */
  281. UA_StatusCode res =
  282. UA_DataSetWriter_generateDataSetMessage(server, &dsmStore[dsmCount], dsw);
  283. if(res != UA_STATUSCODE_GOOD) {
  284. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  285. "PubSub RT Offset calculation: DataSetMessage buffering failed");
  286. continue;
  287. }
  288. dsWriterIds[dsmCount] = dsw->config.dataSetWriterId;
  289. dsmCount++;
  290. }
  291. UA_NetworkMessage networkMessage;
  292. memset(&networkMessage, 0, sizeof(networkMessage));
  293. UA_StatusCode res = generateNetworkMessage(pubSubConnection, wg, dsmStore, dsWriterIds, (UA_Byte) dsmCount,
  294. &wg->config.messageSettings, &wg->config.transportSettings, &networkMessage);
  295. if(res != UA_STATUSCODE_GOOD)
  296. return UA_STATUSCODE_BADINTERNALERROR;
  297. UA_NetworkMessage_calcSizeBinary(&networkMessage, &wg->bufferedMessage);
  298. /* Allocate the buffer. Allocate on the stack if the buffer is small. */
  299. UA_ByteString buf;
  300. size_t msgSize = UA_NetworkMessage_calcSizeBinary(&networkMessage, NULL);
  301. res = UA_ByteString_allocBuffer(&buf, msgSize);
  302. if(res != UA_STATUSCODE_GOOD)
  303. return UA_STATUSCODE_BADOUTOFMEMORY;
  304. wg->bufferedMessage.buffer = buf;
  305. const UA_Byte *bufEnd = &wg->bufferedMessage.buffer.data[wg->bufferedMessage.buffer.length];
  306. UA_Byte *bufPos = wg->bufferedMessage.buffer.data;
  307. UA_NetworkMessage_encodeBinary(&networkMessage, &bufPos, bufEnd);
  308. /* Clean up DSM */
  309. for(size_t i = 0; i < dsmCount; i++){
  310. UA_free(dsmStore[i].data.keyFrameData.dataSetFields);
  311. #ifdef UA_ENABLE_JSON_ENCODING
  312. UA_free(dsmStore[i].data.keyFrameData.fieldNames);
  313. #endif
  314. }
  315. //UA_DataSetMessage_free(&dsmStore[i]);
  316. }
  317. return UA_STATUSCODE_GOOD;
  318. }
  319. UA_StatusCode
  320. UA_Server_unfreezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup){
  321. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  322. if(!wg)
  323. return UA_STATUSCODE_BADNOTFOUND;
  324. //if(wg->config.rtLevel == UA_PUBSUB_RT_NONE){
  325. // UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  326. // "PubSub configuration freeze without RT configuration has no effect.");
  327. // return UA_STATUSCODE_BADCONFIGURATIONERROR;
  328. //}
  329. //PubSubConnection freezeCounter--
  330. UA_PubSubConnection *pubSubConnection = UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
  331. pubSubConnection->configurationFreezeCounter--;
  332. if(pubSubConnection->configurationFreezeCounter == 0){
  333. pubSubConnection->config->configurationFrozen = UA_FALSE;
  334. }
  335. //WriterGroup unfreeze
  336. wg->config.configurationFrozen = UA_FALSE;
  337. //DataSetWriter unfreeze
  338. UA_DataSetWriter *dataSetWriter;
  339. LIST_FOREACH(dataSetWriter, &wg->writers, listEntry){
  340. UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  341. //PublishedDataSet freezeCounter--
  342. publishedDataSet->configurationFreezeCounter--;
  343. if(publishedDataSet->configurationFreezeCounter == 0){
  344. publishedDataSet->config.configurationFrozen = UA_FALSE;
  345. UA_DataSetField *dataSetField;
  346. TAILQ_FOREACH(dataSetField, &publishedDataSet->fields, listEntry){
  347. dataSetField->config.configurationFrozen = UA_FALSE;
  348. }
  349. }
  350. dataSetWriter->config.configurationFrozen = UA_FALSE;
  351. }
  352. return UA_STATUSCODE_GOOD;
  353. }
  354. UA_StatusCode UA_EXPORT
  355. UA_Server_setWriterGroupOperational(UA_Server *server, const UA_NodeId writerGroup){
  356. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  357. if(!wg)
  358. return UA_STATUSCODE_BADNOTFOUND;
  359. return UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, wg);
  360. }
  361. UA_StatusCode UA_EXPORT
  362. UA_Server_setWriterGroupDisabled(UA_Server *server, const UA_NodeId writerGroup){
  363. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  364. if(!wg)
  365. return UA_STATUSCODE_BADNOTFOUND;
  366. return UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, wg);
  367. }
  368. /**********************************************/
  369. /* PublishedDataSet */
  370. /**********************************************/
  371. UA_StatusCode
  372. UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src,
  373. UA_PublishedDataSetConfig *dst) {
  374. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  375. memcpy(dst, src, sizeof(UA_PublishedDataSetConfig));
  376. retVal |= UA_String_copy(&src->name, &dst->name);
  377. switch(src->publishedDataSetType){
  378. case UA_PUBSUB_DATASET_PUBLISHEDITEMS:
  379. //no additional items
  380. break;
  381. case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE:
  382. if(src->config.itemsTemplate.variablesToAddSize > 0){
  383. dst->config.itemsTemplate.variablesToAdd = (UA_PublishedVariableDataType *) UA_calloc(
  384. src->config.itemsTemplate.variablesToAddSize, sizeof(UA_PublishedVariableDataType));
  385. }
  386. for(size_t i = 0; i < src->config.itemsTemplate.variablesToAddSize; i++){
  387. retVal |= UA_PublishedVariableDataType_copy(&src->config.itemsTemplate.variablesToAdd[i],
  388. &dst->config.itemsTemplate.variablesToAdd[i]);
  389. }
  390. retVal |= UA_DataSetMetaDataType_copy(&src->config.itemsTemplate.metaData,
  391. &dst->config.itemsTemplate.metaData);
  392. break;
  393. default:
  394. return UA_STATUSCODE_BADINVALIDARGUMENT;
  395. }
  396. return retVal;
  397. }
  398. UA_StatusCode
  399. UA_Server_getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pds,
  400. UA_PublishedDataSetConfig *config){
  401. if(!config)
  402. return UA_STATUSCODE_BADINVALIDARGUMENT;
  403. UA_PublishedDataSet *currentPublishedDataSet = UA_PublishedDataSet_findPDSbyId(server, pds);
  404. if(!currentPublishedDataSet)
  405. return UA_STATUSCODE_BADNOTFOUND;
  406. UA_PublishedDataSetConfig tmpPublishedDataSetConfig;
  407. //deep copy of the actual config
  408. UA_PublishedDataSetConfig_copy(&currentPublishedDataSet->config, &tmpPublishedDataSetConfig);
  409. *config = tmpPublishedDataSetConfig;
  410. return UA_STATUSCODE_GOOD;
  411. }
  412. UA_StatusCode
  413. UA_Server_getPublishedDataSetMetaData(UA_Server *server, const UA_NodeId pds, UA_DataSetMetaDataType *metaData){
  414. if(!metaData)
  415. return UA_STATUSCODE_BADINVALIDARGUMENT;
  416. UA_PublishedDataSet *currentPublishedDataSet = UA_PublishedDataSet_findPDSbyId(server, pds);
  417. if(!currentPublishedDataSet)
  418. return UA_STATUSCODE_BADNOTFOUND;
  419. UA_DataSetMetaDataType tmpDataSetMetaData;
  420. if(UA_DataSetMetaDataType_copy(&currentPublishedDataSet->dataSetMetaData, &tmpDataSetMetaData) != UA_STATUSCODE_GOOD)
  421. return UA_STATUSCODE_BADINTERNALERROR;
  422. *metaData = tmpDataSetMetaData;
  423. return UA_STATUSCODE_GOOD;
  424. }
  425. UA_PublishedDataSet *
  426. UA_PublishedDataSet_findPDSbyId(UA_Server *server, UA_NodeId identifier){
  427. UA_PublishedDataSet *tmpPDS;
  428. TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry){
  429. if(UA_NodeId_equal(&tmpPDS->identifier, &identifier)){
  430. return tmpPDS;
  431. }
  432. }
  433. return NULL;
  434. }
  435. void
  436. UA_PublishedDataSetConfig_clear(UA_PublishedDataSetConfig *pdsConfig){
  437. //delete pds config
  438. UA_String_clear(&pdsConfig->name);
  439. switch (pdsConfig->publishedDataSetType){
  440. case UA_PUBSUB_DATASET_PUBLISHEDITEMS:
  441. //no additional items
  442. break;
  443. case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE:
  444. if(pdsConfig->config.itemsTemplate.variablesToAddSize > 0){
  445. for(size_t i = 0; i < pdsConfig->config.itemsTemplate.variablesToAddSize; i++){
  446. UA_PublishedVariableDataType_clear(&pdsConfig->config.itemsTemplate.variablesToAdd[i]);
  447. }
  448. UA_free(pdsConfig->config.itemsTemplate.variablesToAdd);
  449. }
  450. UA_DataSetMetaDataType_clear(&pdsConfig->config.itemsTemplate.metaData);
  451. break;
  452. default:
  453. break;
  454. }
  455. }
  456. void
  457. UA_PublishedDataSet_clear(UA_Server *server, UA_PublishedDataSet *publishedDataSet){
  458. UA_PublishedDataSetConfig_clear(&publishedDataSet->config);
  459. //delete PDS
  460. UA_DataSetField *field, *tmpField;
  461. TAILQ_FOREACH_SAFE(field, &publishedDataSet->fields, listEntry, tmpField) {
  462. UA_Server_removeDataSetField(server, field->identifier);
  463. }
  464. UA_DataSetMetaDataType_clear(&publishedDataSet->dataSetMetaData);
  465. UA_NodeId_clear(&publishedDataSet->identifier);
  466. }
  467. static UA_StatusCode
  468. generateFieldMetaData(UA_Server *server, UA_DataSetField *field, UA_FieldMetaData *fieldMetaData){
  469. switch (field->config.dataSetFieldType){
  470. case UA_PUBSUB_DATASETFIELD_VARIABLE:
  471. if(UA_String_copy(&field->config.field.variable.fieldNameAlias, &fieldMetaData->name) != UA_STATUSCODE_GOOD)
  472. return UA_STATUSCODE_BADINTERNALERROR;
  473. fieldMetaData->description = UA_LOCALIZEDTEXT_ALLOC("", "");
  474. fieldMetaData->dataSetFieldId = UA_GUID_NULL;
  475. //ToDo after freeze PR, the value source must be checked (other behavior for static value source)
  476. if(field->config.field.variable.staticValueSourceEnabled){
  477. fieldMetaData->arrayDimensions = (UA_UInt32 *) UA_calloc(
  478. field->config.field.variable.staticValueSource.value.arrayDimensionsSize, sizeof(UA_UInt32));
  479. if(fieldMetaData->arrayDimensions == NULL)
  480. return UA_STATUSCODE_BADOUTOFMEMORY;
  481. memcpy(fieldMetaData->arrayDimensions, field->config.field.variable.staticValueSource.value.arrayDimensions,
  482. sizeof(UA_UInt32) *field->config.field.variable.staticValueSource.value.arrayDimensionsSize);
  483. fieldMetaData->arrayDimensionsSize = field->config.field.variable.staticValueSource.value.arrayDimensionsSize;
  484. if(UA_NodeId_copy(&field->config.field.variable.staticValueSource.value.type->typeId,
  485. &fieldMetaData->dataType) != UA_STATUSCODE_GOOD){
  486. if(fieldMetaData->arrayDimensions){
  487. UA_free(fieldMetaData->arrayDimensions);
  488. return UA_STATUSCODE_BADINTERNALERROR;
  489. }
  490. }
  491. fieldMetaData->properties = NULL;
  492. fieldMetaData->propertiesSize = 0;
  493. //TODO collect value rank for the static field source
  494. fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_NONE;
  495. return UA_STATUSCODE_GOOD;
  496. }
  497. UA_Variant value;
  498. UA_Variant_init(&value);
  499. if(UA_Server_readArrayDimensions(server, field->config.field.variable.publishParameters.publishedVariable,
  500. &value) != UA_STATUSCODE_GOOD){
  501. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  502. "PubSub meta data generation. Reading ArrayDimension failed.");
  503. } else {
  504. fieldMetaData->arrayDimensions = (UA_UInt32 *) UA_calloc(value.arrayDimensionsSize, sizeof(UA_UInt32));
  505. if(fieldMetaData->arrayDimensions == NULL)
  506. return UA_STATUSCODE_BADOUTOFMEMORY;
  507. memcpy(fieldMetaData->arrayDimensions, value.arrayDimensions, sizeof(UA_UInt32)*value.arrayDimensionsSize);
  508. fieldMetaData->arrayDimensionsSize = value.arrayDimensionsSize;
  509. }
  510. if(UA_Server_readDataType(server, field->config.field.variable.publishParameters.publishedVariable,
  511. &fieldMetaData->dataType) != UA_STATUSCODE_GOOD){
  512. if(fieldMetaData->arrayDimensions){
  513. UA_free(fieldMetaData->arrayDimensions);
  514. return UA_STATUSCODE_BADINTERNALERROR;
  515. }
  516. }
  517. fieldMetaData->properties = NULL;
  518. fieldMetaData->propertiesSize = 0;
  519. UA_Int32 valueRank;
  520. if(UA_Server_readValueRank(server, field->config.field.variable.publishParameters.publishedVariable,
  521. &valueRank) != UA_STATUSCODE_GOOD){
  522. if(fieldMetaData->arrayDimensions){
  523. UA_free(fieldMetaData->arrayDimensions);
  524. return UA_STATUSCODE_BADINTERNALERROR;
  525. }
  526. }
  527. fieldMetaData->valueRank = valueRank;
  528. if(field->config.field.variable.promotedField){
  529. fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_PROMOTEDFIELD;
  530. } else {
  531. fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_NONE;
  532. }
  533. //TODO collect the following fields
  534. //fieldMetaData.builtInType
  535. //fieldMetaData.maxStringLength
  536. return UA_STATUSCODE_GOOD;
  537. case UA_PUBSUB_DATASETFIELD_EVENT:
  538. return UA_STATUSCODE_BADNOTSUPPORTED;
  539. default:
  540. return UA_STATUSCODE_BADNOTSUPPORTED;
  541. }
  542. }
  543. UA_DataSetFieldResult
  544. UA_Server_addDataSetField(UA_Server *server, const UA_NodeId publishedDataSet,
  545. const UA_DataSetFieldConfig *fieldConfig,
  546. UA_NodeId *fieldIdentifier) {
  547. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  548. UA_DataSetFieldResult result = {UA_STATUSCODE_BADINVALIDARGUMENT, {0, 0}};
  549. if(!fieldConfig)
  550. return result;
  551. UA_PublishedDataSet *currentDataSet = UA_PublishedDataSet_findPDSbyId(server, publishedDataSet);
  552. if(currentDataSet == NULL){
  553. result.result = UA_STATUSCODE_BADNOTFOUND;
  554. return result;
  555. }
  556. if(currentDataSet->config.configurationFrozen){
  557. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  558. "Adding DataSetField failed. PublishedDataSet is frozen.");
  559. result.result = UA_STATUSCODE_BADCONFIGURATIONERROR;
  560. return result;
  561. }
  562. if(currentDataSet->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS){
  563. result.result = UA_STATUSCODE_BADNOTIMPLEMENTED;
  564. return result;
  565. }
  566. UA_DataSetField *newField = (UA_DataSetField *) UA_calloc(1, sizeof(UA_DataSetField));
  567. if(!newField){
  568. result.result = UA_STATUSCODE_BADINTERNALERROR;
  569. return result;
  570. }
  571. UA_DataSetFieldConfig tmpFieldConfig;
  572. retVal |= UA_DataSetFieldConfig_copy(fieldConfig, &tmpFieldConfig);
  573. newField->config = tmpFieldConfig;
  574. UA_PubSubManager_generateUniqueNodeId(server, &newField->identifier);
  575. if(fieldIdentifier != NULL){
  576. UA_NodeId_copy(&newField->identifier, fieldIdentifier);
  577. }
  578. newField->publishedDataSet = currentDataSet->identifier;
  579. //update major version of parent published data set
  580. currentDataSet->dataSetMetaData.configurationVersion.majorVersion = UA_PubSubConfigurationVersionTimeDifference();
  581. /* The order of DataSetFields should be the same in both creating and publishing.
  582. * So adding DataSetFields at the the end of the DataSets using TAILQ structure */
  583. if (currentDataSet->fieldSize != 0)
  584. TAILQ_INSERT_TAIL(&currentDataSet->fields, newField, listEntry);
  585. else
  586. TAILQ_INSERT_HEAD(&currentDataSet->fields, newField, listEntry);
  587. if(newField->config.field.variable.promotedField)
  588. currentDataSet->promotedFieldsCount++;
  589. currentDataSet->fieldSize++;
  590. //generate fieldMetadata within the DataSetMetaData
  591. currentDataSet->dataSetMetaData.fieldsSize++;
  592. UA_FieldMetaData *fieldMetaData = (UA_FieldMetaData *) UA_realloc(currentDataSet->dataSetMetaData.fields, currentDataSet->dataSetMetaData.fieldsSize *
  593. sizeof(UA_FieldMetaData));
  594. if(!fieldMetaData){
  595. result.result = UA_STATUSCODE_BADOUTOFMEMORY;
  596. return result;
  597. }
  598. currentDataSet->dataSetMetaData.fields = fieldMetaData;
  599. UA_FieldMetaData_init(&fieldMetaData[currentDataSet->fieldSize-1]);
  600. if(generateFieldMetaData(server, newField, &fieldMetaData[currentDataSet->fieldSize-1]) != UA_STATUSCODE_GOOD){
  601. UA_Server_removeDataSetField(server, newField->identifier);
  602. result.result = UA_STATUSCODE_BADINTERNALERROR;
  603. return result;
  604. }
  605. UA_DataSetField *dsf;
  606. size_t counter = 0;
  607. TAILQ_FOREACH(dsf, &currentDataSet->fields, listEntry){
  608. dsf->fieldMetaData = fieldMetaData[counter++];
  609. }
  610. result.result = retVal;
  611. result.configurationVersion.majorVersion = currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
  612. result.configurationVersion.minorVersion = currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
  613. return result;
  614. }
  615. UA_DataSetFieldResult
  616. UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf) {
  617. UA_DataSetField *currentField = UA_DataSetField_findDSFbyId(server, dsf);
  618. UA_DataSetFieldResult result = {UA_STATUSCODE_BADNOTFOUND, {0, 0}};
  619. if(!currentField)
  620. return result;
  621. if(currentField->config.configurationFrozen){
  622. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  623. "Remove DataSetField failed. DataSetField is frozen.");
  624. result.result = UA_STATUSCODE_BADCONFIGURATIONERROR;
  625. return result;
  626. }
  627. UA_PublishedDataSet *parentPublishedDataSet =
  628. UA_PublishedDataSet_findPDSbyId(server, currentField->publishedDataSet);
  629. if(!parentPublishedDataSet)
  630. return result;
  631. if(parentPublishedDataSet->config.configurationFrozen){
  632. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  633. "Remove DataSetField failed. PublishedDataSet is frozen.");
  634. result.result = UA_STATUSCODE_BADCONFIGURATIONERROR;
  635. return result;
  636. }
  637. parentPublishedDataSet->fieldSize--;
  638. if(currentField->config.field.variable.promotedField)
  639. parentPublishedDataSet->promotedFieldsCount--;
  640. /* update major version of PublishedDataSet */
  641. parentPublishedDataSet->dataSetMetaData.configurationVersion.majorVersion =
  642. UA_PubSubConfigurationVersionTimeDifference();
  643. currentField->fieldMetaData.arrayDimensions = NULL;
  644. currentField->fieldMetaData.properties = NULL;
  645. currentField->fieldMetaData.name = UA_STRING_NULL;
  646. currentField->fieldMetaData.description.locale = UA_STRING_NULL;
  647. currentField->fieldMetaData.description.text = UA_STRING_NULL;
  648. UA_DataSetField_clear(currentField);
  649. TAILQ_REMOVE(&parentPublishedDataSet->fields, currentField, listEntry);
  650. UA_free(currentField);
  651. result.result = UA_STATUSCODE_GOOD;
  652. //regenerate DataSetMetaData
  653. parentPublishedDataSet->dataSetMetaData.fieldsSize--;
  654. if(parentPublishedDataSet->dataSetMetaData.fieldsSize > 0){
  655. for(size_t i = 0; i < parentPublishedDataSet->dataSetMetaData.fieldsSize+1; i++) {
  656. UA_FieldMetaData_clear(&parentPublishedDataSet->dataSetMetaData.fields[i]);
  657. }
  658. UA_free(parentPublishedDataSet->dataSetMetaData.fields);
  659. UA_FieldMetaData *fieldMetaData = (UA_FieldMetaData *) UA_calloc(parentPublishedDataSet->dataSetMetaData.fieldsSize,
  660. sizeof(UA_FieldMetaData));
  661. if(!fieldMetaData){
  662. result.result = UA_STATUSCODE_BADOUTOFMEMORY;
  663. return result;
  664. }
  665. UA_DataSetField *tmpDSF;
  666. size_t counter = 0;
  667. TAILQ_FOREACH(tmpDSF, &parentPublishedDataSet->fields, listEntry){
  668. UA_FieldMetaData tmpFieldMetaData;
  669. UA_FieldMetaData_init(&tmpFieldMetaData);
  670. if(generateFieldMetaData(server, tmpDSF, &tmpFieldMetaData) != UA_STATUSCODE_GOOD){
  671. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  672. "PubSub MetaData generation failed!");
  673. //TODO how to ensure consistency if the metadata regeneration fails
  674. result.result = UA_STATUSCODE_BADINTERNALERROR;
  675. }
  676. fieldMetaData[counter++] = tmpFieldMetaData;
  677. }
  678. parentPublishedDataSet->dataSetMetaData.fields = fieldMetaData;
  679. } else {
  680. UA_FieldMetaData_delete(parentPublishedDataSet->dataSetMetaData.fields);
  681. parentPublishedDataSet->dataSetMetaData.fields = NULL;
  682. }
  683. result.configurationVersion.majorVersion = parentPublishedDataSet->dataSetMetaData.configurationVersion.majorVersion;
  684. result.configurationVersion.minorVersion = parentPublishedDataSet->dataSetMetaData.configurationVersion.minorVersion;
  685. return result;
  686. }
  687. /**********************************************/
  688. /* DataSetWriter */
  689. /**********************************************/
  690. UA_StatusCode
  691. UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src,
  692. UA_DataSetWriterConfig *dst){
  693. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  694. memcpy(dst, src, sizeof(UA_DataSetWriterConfig));
  695. retVal |= UA_String_copy(&src->name, &dst->name);
  696. retVal |= UA_String_copy(&src->dataSetName, &dst->dataSetName);
  697. retVal |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings);
  698. if (src->dataSetWriterPropertiesSize > 0) {
  699. dst->dataSetWriterProperties = (UA_KeyValuePair *)
  700. UA_calloc(src->dataSetWriterPropertiesSize, sizeof(UA_KeyValuePair));
  701. if(!dst->dataSetWriterProperties)
  702. return UA_STATUSCODE_BADOUTOFMEMORY;
  703. for(size_t i = 0; i < src->dataSetWriterPropertiesSize; i++){
  704. retVal |= UA_KeyValuePair_copy(&src->dataSetWriterProperties[i], &dst->dataSetWriterProperties[i]);
  705. }
  706. }
  707. return retVal;
  708. }
  709. UA_StatusCode
  710. UA_Server_getDataSetWriterConfig(UA_Server *server, const UA_NodeId dsw,
  711. UA_DataSetWriterConfig *config){
  712. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  713. if(!config)
  714. return UA_STATUSCODE_BADINVALIDARGUMENT;
  715. UA_DataSetWriter *currentDataSetWriter = UA_DataSetWriter_findDSWbyId(server, dsw);
  716. if(!currentDataSetWriter)
  717. return UA_STATUSCODE_BADNOTFOUND;
  718. UA_DataSetWriterConfig tmpWriterConfig;
  719. //deep copy of the actual config
  720. retVal |= UA_DataSetWriterConfig_copy(&currentDataSetWriter->config, &tmpWriterConfig);
  721. *config = tmpWriterConfig;
  722. return retVal;
  723. }
  724. UA_DataSetWriter *
  725. UA_DataSetWriter_findDSWbyId(UA_Server *server, UA_NodeId identifier) {
  726. UA_PubSubConnection *pubSubConnection;
  727. TAILQ_FOREACH(pubSubConnection, &server->pubSubManager.connections, listEntry){
  728. UA_WriterGroup *tmpWriterGroup;
  729. LIST_FOREACH(tmpWriterGroup, &pubSubConnection->writerGroups, listEntry){
  730. UA_DataSetWriter *tmpWriter;
  731. LIST_FOREACH(tmpWriter, &tmpWriterGroup->writers, listEntry){
  732. if(UA_NodeId_equal(&tmpWriter->identifier, &identifier)){
  733. return tmpWriter;
  734. }
  735. }
  736. }
  737. }
  738. return NULL;
  739. }
  740. void
  741. UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig *pdsConfig) {
  742. UA_String_clear(&pdsConfig->name);
  743. UA_String_clear(&pdsConfig->dataSetName);
  744. for(size_t i = 0; i < pdsConfig->dataSetWriterPropertiesSize; i++){
  745. UA_KeyValuePair_clear(&pdsConfig->dataSetWriterProperties[i]);
  746. }
  747. UA_free(pdsConfig->dataSetWriterProperties);
  748. UA_ExtensionObject_clear(&pdsConfig->messageSettings);
  749. }
  750. static void
  751. UA_DataSetWriter_clear(UA_Server *server, UA_DataSetWriter *dataSetWriter) {
  752. UA_DataSetWriterConfig_clear(&dataSetWriter->config);
  753. //delete DataSetWriter
  754. UA_NodeId_clear(&dataSetWriter->identifier);
  755. UA_NodeId_clear(&dataSetWriter->linkedWriterGroup);
  756. UA_NodeId_clear(&dataSetWriter->connectedDataSet);
  757. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  758. //delete lastSamples store
  759. for(size_t i = 0; i < dataSetWriter->lastSamplesCount; i++) {
  760. UA_DataValue_clear(&dataSetWriter->lastSamples[i].value);
  761. }
  762. UA_free(dataSetWriter->lastSamples);
  763. dataSetWriter->lastSamples = NULL;
  764. dataSetWriter->lastSamplesCount = 0;
  765. #endif
  766. }
  767. //state machine methods not part of the open62541 state machine API
  768. UA_StatusCode
  769. UA_DataSetWriter_setPubSubState(UA_Server *server, UA_PubSubState state, UA_DataSetWriter *dataSetWriter){
  770. switch(state){
  771. case UA_PUBSUBSTATE_DISABLED:
  772. switch (dataSetWriter->state){
  773. case UA_PUBSUBSTATE_DISABLED:
  774. return UA_STATUSCODE_GOOD;
  775. case UA_PUBSUBSTATE_PAUSED:
  776. dataSetWriter->state = UA_PUBSUBSTATE_DISABLED;
  777. //no further action is required
  778. break;
  779. case UA_PUBSUBSTATE_OPERATIONAL:
  780. dataSetWriter->state = UA_PUBSUBSTATE_DISABLED;
  781. break;
  782. case UA_PUBSUBSTATE_ERROR:
  783. break;
  784. default:
  785. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  786. "Received unknown PubSub state!");
  787. }
  788. break;
  789. case UA_PUBSUBSTATE_PAUSED:
  790. switch (dataSetWriter->state){
  791. case UA_PUBSUBSTATE_DISABLED:
  792. break;
  793. case UA_PUBSUBSTATE_PAUSED:
  794. return UA_STATUSCODE_GOOD;
  795. case UA_PUBSUBSTATE_OPERATIONAL:
  796. break;
  797. case UA_PUBSUBSTATE_ERROR:
  798. break;
  799. default:
  800. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  801. "Received unknown PubSub state!");
  802. }
  803. break;
  804. case UA_PUBSUBSTATE_OPERATIONAL:
  805. switch (dataSetWriter->state){
  806. case UA_PUBSUBSTATE_DISABLED:
  807. dataSetWriter->state = UA_PUBSUBSTATE_OPERATIONAL;
  808. break;
  809. case UA_PUBSUBSTATE_PAUSED:
  810. break;
  811. case UA_PUBSUBSTATE_OPERATIONAL:
  812. return UA_STATUSCODE_GOOD;
  813. case UA_PUBSUBSTATE_ERROR:
  814. break;
  815. default:
  816. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  817. "Received unknown PubSub state!");
  818. }
  819. break;
  820. case UA_PUBSUBSTATE_ERROR:
  821. switch (dataSetWriter->state){
  822. case UA_PUBSUBSTATE_DISABLED:
  823. break;
  824. case UA_PUBSUBSTATE_PAUSED:
  825. break;
  826. case UA_PUBSUBSTATE_OPERATIONAL:
  827. break;
  828. case UA_PUBSUBSTATE_ERROR:
  829. return UA_STATUSCODE_GOOD;
  830. default:
  831. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  832. "Received unknown PubSub state!");
  833. }
  834. break;
  835. default:
  836. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  837. "Received unknown PubSub state!");
  838. }
  839. return UA_STATUSCODE_GOOD;
  840. }
  841. /**********************************************/
  842. /* WriterGroup */
  843. /**********************************************/
  844. UA_StatusCode
  845. UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src,
  846. UA_WriterGroupConfig *dst){
  847. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  848. memcpy(dst, src, sizeof(UA_WriterGroupConfig));
  849. retVal |= UA_String_copy(&src->name, &dst->name);
  850. retVal |= UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings);
  851. retVal |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings);
  852. if (src->groupPropertiesSize > 0) {
  853. dst->groupProperties = (UA_KeyValuePair *) UA_calloc(src->groupPropertiesSize, sizeof(UA_KeyValuePair));
  854. if(!dst->groupProperties)
  855. return UA_STATUSCODE_BADOUTOFMEMORY;
  856. for(size_t i = 0; i < src->groupPropertiesSize; i++){
  857. retVal |= UA_KeyValuePair_copy(&src->groupProperties[i], &dst->groupProperties[i]);
  858. }
  859. }
  860. return retVal;
  861. }
  862. UA_StatusCode
  863. UA_Server_getWriterGroupConfig(UA_Server *server, const UA_NodeId writerGroup,
  864. UA_WriterGroupConfig *config){
  865. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  866. if(!config)
  867. return UA_STATUSCODE_BADINVALIDARGUMENT;
  868. UA_WriterGroup *currentWriterGroup = UA_WriterGroup_findWGbyId(server, writerGroup);
  869. if(!currentWriterGroup){
  870. return UA_STATUSCODE_BADNOTFOUND;
  871. }
  872. UA_WriterGroupConfig tmpWriterGroupConfig;
  873. //deep copy of the actual config
  874. retVal |= UA_WriterGroupConfig_copy(&currentWriterGroup->config, &tmpWriterGroupConfig);
  875. *config = tmpWriterGroupConfig;
  876. return retVal;
  877. }
  878. UA_StatusCode
  879. UA_Server_updateWriterGroupConfig(UA_Server *server, UA_NodeId writerGroupIdentifier,
  880. const UA_WriterGroupConfig *config){
  881. if(!config)
  882. return UA_STATUSCODE_BADINVALIDARGUMENT;
  883. UA_WriterGroup *currentWriterGroup = UA_WriterGroup_findWGbyId(server, writerGroupIdentifier);
  884. if(!currentWriterGroup)
  885. return UA_STATUSCODE_BADNOTFOUND;
  886. if(currentWriterGroup->config.configurationFrozen){
  887. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  888. "Modify WriterGroup failed. WriterGroup is frozen.");
  889. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  890. }
  891. //The update functionality will be extended during the next PubSub batches.
  892. //Currently is only a change of the publishing interval possible.
  893. if(currentWriterGroup->config.maxEncapsulatedDataSetMessageCount != config->maxEncapsulatedDataSetMessageCount){
  894. currentWriterGroup->config.maxEncapsulatedDataSetMessageCount = config->maxEncapsulatedDataSetMessageCount;
  895. if(currentWriterGroup->config.messageSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
  896. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  897. "MaxEncapsulatedDataSetMessag need enabled 'PayloadHeader' within the message settings.");
  898. }
  899. }
  900. if(currentWriterGroup->config.publishingInterval != config->publishingInterval) {
  901. if(currentWriterGroup->config.rtLevel == UA_PUBSUB_RT_NONE && currentWriterGroup->state == UA_PUBSUBSTATE_OPERATIONAL){
  902. UA_PubSubManager_removeRepeatedPubSubCallback(server, currentWriterGroup->publishCallbackId);
  903. currentWriterGroup->config.publishingInterval = config->publishingInterval;
  904. UA_WriterGroup_addPublishCallback(server, currentWriterGroup);
  905. } else {
  906. currentWriterGroup->config.publishingInterval = config->publishingInterval;
  907. }
  908. }
  909. if(currentWriterGroup->config.priority != config->priority) {
  910. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  911. "No or unsupported WriterGroup update.");
  912. }
  913. return UA_STATUSCODE_GOOD;
  914. }
  915. UA_WriterGroup *
  916. UA_WriterGroup_findWGbyId(UA_Server *server, UA_NodeId identifier){
  917. UA_PubSubConnection *tmpConnection;
  918. TAILQ_FOREACH(tmpConnection, &server->pubSubManager.connections, listEntry){
  919. UA_WriterGroup *tmpWriterGroup;
  920. LIST_FOREACH(tmpWriterGroup, &tmpConnection->writerGroups, listEntry) {
  921. if(UA_NodeId_equal(&identifier, &tmpWriterGroup->identifier)){
  922. return tmpWriterGroup;
  923. }
  924. }
  925. }
  926. return NULL;
  927. }
  928. void
  929. UA_WriterGroupConfig_clear(UA_WriterGroupConfig *writerGroupConfig){
  930. //delete writerGroup config
  931. UA_String_clear(&writerGroupConfig->name);
  932. UA_ExtensionObject_clear(&writerGroupConfig->transportSettings);
  933. UA_ExtensionObject_clear(&writerGroupConfig->messageSettings);
  934. for(size_t i = 0; i < writerGroupConfig->groupPropertiesSize; i++){
  935. UA_KeyValuePair_clear(&writerGroupConfig->groupProperties[i]);
  936. }
  937. UA_free(writerGroupConfig->groupProperties);
  938. }
  939. static void
  940. UA_WriterGroup_clear(UA_Server *server, UA_WriterGroup *writerGroup) {
  941. UA_WriterGroupConfig_clear(&writerGroup->config);
  942. //delete WriterGroup
  943. //delete all writers. Therefore removeDataSetWriter is called from PublishedDataSet
  944. UA_DataSetWriter *dataSetWriter, *tmpDataSetWriter;
  945. LIST_FOREACH_SAFE(dataSetWriter, &writerGroup->writers, listEntry, tmpDataSetWriter){
  946. UA_Server_removeDataSetWriter(server, dataSetWriter->identifier);
  947. }
  948. if(writerGroup->bufferedMessage.offsetsSize > 0){
  949. for (size_t i = 0; i < writerGroup->bufferedMessage.offsetsSize; i++) {
  950. if(writerGroup->bufferedMessage.offsets[i].contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT){
  951. UA_DataValue_delete(writerGroup->bufferedMessage.offsets[i].offsetData.value.value);
  952. }
  953. }
  954. UA_ByteString_deleteMembers(&writerGroup->bufferedMessage.buffer);
  955. UA_free(writerGroup->bufferedMessage.offsets);
  956. }
  957. UA_NodeId_clear(&writerGroup->linkedConnection);
  958. UA_NodeId_clear(&writerGroup->identifier);
  959. }
  960. UA_StatusCode
  961. UA_WriterGroup_setPubSubState(UA_Server *server, UA_PubSubState state, UA_WriterGroup *writerGroup){
  962. UA_DataSetWriter *dataSetWriter;
  963. switch(state){
  964. case UA_PUBSUBSTATE_DISABLED:
  965. switch (writerGroup->state){
  966. case UA_PUBSUBSTATE_DISABLED:
  967. return UA_STATUSCODE_GOOD;
  968. case UA_PUBSUBSTATE_PAUSED:
  969. break;
  970. case UA_PUBSUBSTATE_OPERATIONAL:
  971. UA_PubSubManager_removeRepeatedPubSubCallback(server, writerGroup->publishCallbackId);
  972. LIST_FOREACH(dataSetWriter, &writerGroup->writers, listEntry){
  973. UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, dataSetWriter);
  974. }
  975. writerGroup->state = UA_PUBSUBSTATE_DISABLED;
  976. break;
  977. case UA_PUBSUBSTATE_ERROR:
  978. break;
  979. default:
  980. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  981. "Received unknown PubSub state!");
  982. }
  983. break;
  984. case UA_PUBSUBSTATE_PAUSED:
  985. switch (writerGroup->state){
  986. case UA_PUBSUBSTATE_DISABLED:
  987. break;
  988. case UA_PUBSUBSTATE_PAUSED:
  989. return UA_STATUSCODE_GOOD;
  990. case UA_PUBSUBSTATE_OPERATIONAL:
  991. break;
  992. case UA_PUBSUBSTATE_ERROR:
  993. break;
  994. default:
  995. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  996. "Received unknown PubSub state!");
  997. }
  998. break;
  999. case UA_PUBSUBSTATE_OPERATIONAL:
  1000. switch (writerGroup->state){
  1001. case UA_PUBSUBSTATE_DISABLED:
  1002. writerGroup->state = UA_PUBSUBSTATE_OPERATIONAL;
  1003. UA_PubSubManager_removeRepeatedPubSubCallback(server, writerGroup->publishCallbackId);
  1004. LIST_FOREACH(dataSetWriter, &writerGroup->writers, listEntry){
  1005. UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, dataSetWriter);
  1006. }
  1007. UA_WriterGroup_addPublishCallback(server, writerGroup);
  1008. break;
  1009. case UA_PUBSUBSTATE_PAUSED:
  1010. break;
  1011. case UA_PUBSUBSTATE_OPERATIONAL:
  1012. return UA_STATUSCODE_GOOD;
  1013. case UA_PUBSUBSTATE_ERROR:
  1014. break;
  1015. default:
  1016. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1017. "Received unknown PubSub state!");
  1018. }
  1019. break;
  1020. case UA_PUBSUBSTATE_ERROR:
  1021. switch (writerGroup->state){
  1022. case UA_PUBSUBSTATE_DISABLED:
  1023. break;
  1024. case UA_PUBSUBSTATE_PAUSED:
  1025. break;
  1026. case UA_PUBSUBSTATE_OPERATIONAL:
  1027. break;
  1028. case UA_PUBSUBSTATE_ERROR:
  1029. return UA_STATUSCODE_GOOD;
  1030. default:
  1031. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1032. "Received unknown PubSub state!");
  1033. }
  1034. break;
  1035. default:
  1036. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1037. "Received unknown PubSub state!");
  1038. }
  1039. return UA_STATUSCODE_GOOD;
  1040. }
  1041. UA_StatusCode
  1042. UA_Server_addDataSetWriter(UA_Server *server,
  1043. const UA_NodeId writerGroup, const UA_NodeId dataSet,
  1044. const UA_DataSetWriterConfig *dataSetWriterConfig,
  1045. UA_NodeId *writerIdentifier) {
  1046. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  1047. if(!dataSetWriterConfig)
  1048. return UA_STATUSCODE_BADINVALIDARGUMENT;
  1049. UA_PublishedDataSet *currentDataSetContext = UA_PublishedDataSet_findPDSbyId(server, dataSet);
  1050. if(!currentDataSetContext)
  1051. return UA_STATUSCODE_BADNOTFOUND;
  1052. if(currentDataSetContext->config.configurationFrozen){
  1053. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1054. "Adding DataSetWriter failed. PublishedDataSet is frozen.");
  1055. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1056. }
  1057. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  1058. if(!wg)
  1059. return UA_STATUSCODE_BADNOTFOUND;
  1060. if(wg->config.configurationFrozen){
  1061. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1062. "Adding DataSetWriter failed. WriterGroup is frozen.");
  1063. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1064. }
  1065. if(wg->config.rtLevel != UA_PUBSUB_RT_NONE){
  1066. UA_DataSetField *tmpDSF;
  1067. TAILQ_FOREACH(tmpDSF, &currentDataSetContext->fields, listEntry){
  1068. if(tmpDSF->config.field.variable.staticValueSourceEnabled != UA_TRUE){
  1069. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1070. "Adding DataSetWriter failed. Fields in PDS are not RT capable.");
  1071. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1072. }
  1073. }
  1074. }
  1075. UA_DataSetWriter *newDataSetWriter = (UA_DataSetWriter *) UA_calloc(1, sizeof(UA_DataSetWriter));
  1076. if(!newDataSetWriter)
  1077. return UA_STATUSCODE_BADOUTOFMEMORY;
  1078. //copy the config into the new dataSetWriter
  1079. UA_DataSetWriterConfig tmpDataSetWriterConfig;
  1080. retVal |= UA_DataSetWriterConfig_copy(dataSetWriterConfig, &tmpDataSetWriterConfig);
  1081. newDataSetWriter->config = tmpDataSetWriterConfig;
  1082. //save the current version of the connected PublishedDataSet
  1083. newDataSetWriter->connectedDataSetVersion = currentDataSetContext->dataSetMetaData.configurationVersion;
  1084. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1085. //initialize the queue for the last values
  1086. if (currentDataSetContext->fieldSize > 0) {
  1087. newDataSetWriter->lastSamples = (UA_DataSetWriterSample * )
  1088. UA_calloc(currentDataSetContext->fieldSize, sizeof(UA_DataSetWriterSample));
  1089. if(!newDataSetWriter->lastSamples) {
  1090. UA_DataSetWriterConfig_clear(&newDataSetWriter->config);
  1091. UA_free(newDataSetWriter);
  1092. return UA_STATUSCODE_BADOUTOFMEMORY;
  1093. }
  1094. newDataSetWriter->lastSamplesCount = currentDataSetContext->fieldSize;
  1095. }
  1096. #endif
  1097. //connect PublishedDataSet with DataSetWriter
  1098. newDataSetWriter->connectedDataSet = currentDataSetContext->identifier;
  1099. newDataSetWriter->linkedWriterGroup = wg->identifier;
  1100. UA_PubSubManager_generateUniqueNodeId(server, &newDataSetWriter->identifier);
  1101. if(writerIdentifier != NULL)
  1102. UA_NodeId_copy(&newDataSetWriter->identifier, writerIdentifier);
  1103. //add the new writer to the group
  1104. LIST_INSERT_HEAD(&wg->writers, newDataSetWriter, listEntry);
  1105. wg->writersCount++;
  1106. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  1107. addDataSetWriterRepresentation(server, newDataSetWriter);
  1108. #endif
  1109. return retVal;
  1110. }
  1111. UA_StatusCode
  1112. UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw){
  1113. UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_findDSWbyId(server, dsw);
  1114. if(!dataSetWriter)
  1115. return UA_STATUSCODE_BADNOTFOUND;
  1116. if(dataSetWriter->config.configurationFrozen){
  1117. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1118. "Remove DataSetWriter failed. DataSetWriter is frozen.");
  1119. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1120. }
  1121. UA_WriterGroup *linkedWriterGroup = UA_WriterGroup_findWGbyId(server, dataSetWriter->linkedWriterGroup);
  1122. if(!linkedWriterGroup)
  1123. return UA_STATUSCODE_BADNOTFOUND;
  1124. if(linkedWriterGroup->config.configurationFrozen){
  1125. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1126. "Remove DataSetWriter failed. WriterGroup is frozen.");
  1127. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1128. }
  1129. UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  1130. if(!publishedDataSet)
  1131. return UA_STATUSCODE_BADNOTFOUND;
  1132. linkedWriterGroup->writersCount--;
  1133. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  1134. removeDataSetWriterRepresentation(server, dataSetWriter);
  1135. #endif
  1136. //remove DataSetWriter from group
  1137. UA_DataSetWriter_clear(server, dataSetWriter);
  1138. LIST_REMOVE(dataSetWriter, listEntry);
  1139. UA_free(dataSetWriter);
  1140. return UA_STATUSCODE_GOOD;
  1141. }
  1142. /**********************************************/
  1143. /* DataSetField */
  1144. /**********************************************/
  1145. UA_StatusCode
  1146. UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src, UA_DataSetFieldConfig *dst){
  1147. memcpy(dst, src, sizeof(UA_DataSetFieldConfig));
  1148. if(src->dataSetFieldType == UA_PUBSUB_DATASETFIELD_VARIABLE) {
  1149. UA_String_copy(&src->field.variable.fieldNameAlias, &dst->field.variable.fieldNameAlias);
  1150. UA_PublishedVariableDataType_copy(&src->field.variable.publishParameters,
  1151. &dst->field.variable.publishParameters);
  1152. } else {
  1153. return UA_STATUSCODE_BADNOTSUPPORTED;
  1154. }
  1155. return UA_STATUSCODE_GOOD;
  1156. }
  1157. UA_StatusCode
  1158. UA_Server_getDataSetFieldConfig(UA_Server *server, const UA_NodeId dsf,
  1159. UA_DataSetFieldConfig *config) {
  1160. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  1161. if(!config)
  1162. return UA_STATUSCODE_BADINVALIDARGUMENT;
  1163. UA_DataSetField *currentDataSetField = UA_DataSetField_findDSFbyId(server, dsf);
  1164. if(!currentDataSetField)
  1165. return UA_STATUSCODE_BADNOTFOUND;
  1166. UA_DataSetFieldConfig tmpFieldConfig;
  1167. //deep copy of the actual config
  1168. retVal |= UA_DataSetFieldConfig_copy(&currentDataSetField->config, &tmpFieldConfig);
  1169. *config = tmpFieldConfig;
  1170. return retVal;
  1171. }
  1172. UA_DataSetField *
  1173. UA_DataSetField_findDSFbyId(UA_Server *server, UA_NodeId identifier) {
  1174. UA_PublishedDataSet *tmpPDS;
  1175. TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry){
  1176. UA_DataSetField *tmpField;
  1177. TAILQ_FOREACH(tmpField, &tmpPDS->fields, listEntry){
  1178. if(UA_NodeId_equal(&tmpField->identifier, &identifier)){
  1179. return tmpField;
  1180. }
  1181. }
  1182. }
  1183. return NULL;
  1184. }
  1185. void
  1186. UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig *dataSetFieldConfig){
  1187. if(dataSetFieldConfig->dataSetFieldType == UA_PUBSUB_DATASETFIELD_VARIABLE){
  1188. UA_String_clear(&dataSetFieldConfig->field.variable.fieldNameAlias);
  1189. UA_PublishedVariableDataType_clear(&dataSetFieldConfig->field.variable.publishParameters);
  1190. }
  1191. }
  1192. static void
  1193. UA_DataSetField_clear(UA_DataSetField *field) {
  1194. UA_DataSetFieldConfig_clear(&field->config);
  1195. //delete DataSetField
  1196. UA_NodeId_clear(&field->identifier);
  1197. UA_NodeId_clear(&field->publishedDataSet);
  1198. UA_FieldMetaData_clear(&field->fieldMetaData);
  1199. }
  1200. /*********************************************************/
  1201. /* PublishValues handling */
  1202. /*********************************************************/
  1203. /**
  1204. * Compare two variants. Internally used for value change detection.
  1205. *
  1206. * @return true if the value has changed
  1207. */
  1208. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1209. static UA_Boolean
  1210. valueChangedVariant(UA_Variant *oldValue, UA_Variant *newValue){
  1211. if(! (oldValue && newValue))
  1212. return false;
  1213. UA_ByteString *oldValueEncoding = UA_ByteString_new(), *newValueEncoding = UA_ByteString_new();
  1214. size_t oldValueEncodingSize, newValueEncodingSize;
  1215. oldValueEncodingSize = UA_calcSizeBinary(oldValue, &UA_TYPES[UA_TYPES_VARIANT]);
  1216. newValueEncodingSize = UA_calcSizeBinary(newValue, &UA_TYPES[UA_TYPES_VARIANT]);
  1217. if((oldValueEncodingSize == 0) || (newValueEncodingSize == 0))
  1218. return false;
  1219. if(oldValueEncodingSize != newValueEncodingSize)
  1220. return true;
  1221. if(UA_ByteString_allocBuffer(oldValueEncoding, oldValueEncodingSize) != UA_STATUSCODE_GOOD)
  1222. return false;
  1223. if(UA_ByteString_allocBuffer(newValueEncoding, newValueEncodingSize) != UA_STATUSCODE_GOOD)
  1224. return false;
  1225. UA_Byte *bufPosOldValue = oldValueEncoding->data;
  1226. const UA_Byte *bufEndOldValue = &oldValueEncoding->data[oldValueEncoding->length];
  1227. UA_Byte *bufPosNewValue = newValueEncoding->data;
  1228. const UA_Byte *bufEndNewValue = &newValueEncoding->data[newValueEncoding->length];
  1229. if(UA_encodeBinary(oldValue, &UA_TYPES[UA_TYPES_VARIANT],
  1230. &bufPosOldValue, &bufEndOldValue, NULL, NULL) != UA_STATUSCODE_GOOD){
  1231. return false;
  1232. }
  1233. if(UA_encodeBinary(newValue, &UA_TYPES[UA_TYPES_VARIANT],
  1234. &bufPosNewValue, &bufEndNewValue, NULL, NULL) != UA_STATUSCODE_GOOD){
  1235. return false;
  1236. }
  1237. oldValueEncoding->length = (uintptr_t)bufPosOldValue - (uintptr_t)oldValueEncoding->data;
  1238. newValueEncoding->length = (uintptr_t)bufPosNewValue - (uintptr_t)newValueEncoding->data;
  1239. UA_Boolean compareResult = !UA_ByteString_equal(oldValueEncoding, newValueEncoding);
  1240. UA_ByteString_delete(oldValueEncoding);
  1241. UA_ByteString_delete(newValueEncoding);
  1242. return compareResult;
  1243. }
  1244. #endif
  1245. /**
  1246. * Obtain the latest value for a specific DataSetField. This method is currently
  1247. * called inside the DataSetMessage generation process.
  1248. */
  1249. static void
  1250. UA_PubSubDataSetField_sampleValue(UA_Server *server, UA_DataSetField *field,
  1251. UA_DataValue *value) {
  1252. /* Read the value */
  1253. if(field->config.field.variable.staticValueSourceEnabled == UA_FALSE){
  1254. UA_ReadValueId rvid;
  1255. UA_ReadValueId_init(&rvid);
  1256. rvid.nodeId = field->config.field.variable.publishParameters.publishedVariable;
  1257. rvid.attributeId = field->config.field.variable.publishParameters.attributeId;
  1258. rvid.indexRange = field->config.field.variable.publishParameters.indexRange;
  1259. *value = UA_Server_read(server, &rvid, UA_TIMESTAMPSTORETURN_BOTH);
  1260. } else {
  1261. value->value.storageType = UA_VARIANT_DATA_NODELETE;
  1262. *value = field->config.field.variable.staticValueSource;
  1263. }
  1264. }
  1265. static UA_StatusCode
  1266. UA_PubSubDataSetWriter_generateKeyFrameMessage(UA_Server *server, UA_DataSetMessage *dataSetMessage,
  1267. UA_DataSetWriter *dataSetWriter) {
  1268. UA_PublishedDataSet *currentDataSet =
  1269. UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  1270. if(!currentDataSet)
  1271. return UA_STATUSCODE_BADNOTFOUND;
  1272. /* Prepare DataSetMessageContent */
  1273. dataSetMessage->header.dataSetMessageValid = true;
  1274. dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
  1275. dataSetMessage->data.keyFrameData.fieldCount = currentDataSet->fieldSize;
  1276. dataSetMessage->data.keyFrameData.dataSetFields = (UA_DataValue *)
  1277. UA_Array_new(currentDataSet->fieldSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
  1278. if(!dataSetMessage->data.keyFrameData.dataSetFields)
  1279. return UA_STATUSCODE_BADOUTOFMEMORY;
  1280. #ifdef UA_ENABLE_JSON_ENCODING
  1281. /* json: insert fieldnames used as json keys */
  1282. dataSetMessage->data.keyFrameData.fieldNames =
  1283. (UA_String *)UA_Array_new(currentDataSet->fieldSize, &UA_TYPES[UA_TYPES_STRING]);
  1284. if(!dataSetMessage->data.keyFrameData.fieldNames)
  1285. return UA_STATUSCODE_BADOUTOFMEMORY;
  1286. #endif
  1287. /* Loop over the fields */
  1288. size_t counter = 0;
  1289. UA_DataSetField *dsf;
  1290. TAILQ_FOREACH(dsf, &currentDataSet->fields, listEntry) {
  1291. #ifdef UA_ENABLE_JSON_ENCODING
  1292. /* json: store the fieldNameAlias*/
  1293. UA_String_copy(&dsf->config.field.variable.fieldNameAlias,
  1294. &dataSetMessage->data.keyFrameData.fieldNames[counter]);
  1295. #endif
  1296. /* Sample the value */
  1297. UA_DataValue *dfv = &dataSetMessage->data.keyFrameData.dataSetFields[counter];
  1298. UA_PubSubDataSetField_sampleValue(server, dsf, dfv);
  1299. /* Deactivate statuscode? */
  1300. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
  1301. dfv->hasStatus = false;
  1302. /* Deactivate timestamps */
  1303. if(((u64)dataSetWriter->config.dataSetFieldContentMask &
  1304. (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
  1305. dfv->hasSourceTimestamp = false;
  1306. if(((u64)dataSetWriter->config.dataSetFieldContentMask &
  1307. (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
  1308. dfv->hasSourcePicoseconds = false;
  1309. if(((u64)dataSetWriter->config.dataSetFieldContentMask &
  1310. (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
  1311. dfv->hasServerTimestamp = false;
  1312. if(((u64)dataSetWriter->config.dataSetFieldContentMask &
  1313. (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
  1314. dfv->hasServerPicoseconds = false;
  1315. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1316. /* Update lastValue store */
  1317. UA_DataValue_clear(&dataSetWriter->lastSamples[counter].value);
  1318. UA_DataValue_copy(dfv, &dataSetWriter->lastSamples[counter].value);
  1319. #endif
  1320. counter++;
  1321. }
  1322. return UA_STATUSCODE_GOOD;
  1323. }
  1324. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1325. static UA_StatusCode
  1326. UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_Server *server,
  1327. UA_DataSetMessage *dataSetMessage,
  1328. UA_DataSetWriter *dataSetWriter) {
  1329. UA_PublishedDataSet *currentDataSet =
  1330. UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  1331. if(!currentDataSet)
  1332. return UA_STATUSCODE_BADNOTFOUND;
  1333. /* Prepare DataSetMessageContent */
  1334. memset(dataSetMessage, 0, sizeof(UA_DataSetMessage));
  1335. dataSetMessage->header.dataSetMessageValid = true;
  1336. dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATADELTAFRAME;
  1337. if (currentDataSet->fieldSize == 0) {
  1338. return UA_STATUSCODE_GOOD;
  1339. }
  1340. UA_DataSetField *dsf;
  1341. size_t counter = 0;
  1342. TAILQ_FOREACH(dsf, &currentDataSet->fields, listEntry) {
  1343. /* Sample the value */
  1344. UA_DataValue value;
  1345. UA_DataValue_init(&value);
  1346. UA_PubSubDataSetField_sampleValue(server, dsf, &value);
  1347. /* Check if the value has changed */
  1348. if(valueChangedVariant(&dataSetWriter->lastSamples[counter].value.value, &value.value)) {
  1349. /* increase fieldCount for current delta message */
  1350. dataSetMessage->data.deltaFrameData.fieldCount++;
  1351. dataSetWriter->lastSamples[counter].valueChanged = true;
  1352. /* Update last stored sample */
  1353. UA_DataValue_clear(&dataSetWriter->lastSamples[counter].value);
  1354. dataSetWriter->lastSamples[counter].value = value;
  1355. } else {
  1356. UA_DataValue_clear(&value);
  1357. dataSetWriter->lastSamples[counter].valueChanged = false;
  1358. }
  1359. counter++;
  1360. }
  1361. /* Allocate DeltaFrameFields */
  1362. UA_DataSetMessage_DeltaFrameField *deltaFields = (UA_DataSetMessage_DeltaFrameField *)
  1363. UA_calloc(dataSetMessage->data.deltaFrameData.fieldCount, sizeof(UA_DataSetMessage_DeltaFrameField));
  1364. if(!deltaFields)
  1365. return UA_STATUSCODE_BADOUTOFMEMORY;
  1366. dataSetMessage->data.deltaFrameData.deltaFrameFields = deltaFields;
  1367. size_t currentDeltaField = 0;
  1368. for(size_t i = 0; i < currentDataSet->fieldSize; i++) {
  1369. if(!dataSetWriter->lastSamples[i].valueChanged)
  1370. continue;
  1371. UA_DataSetMessage_DeltaFrameField *dff = &deltaFields[currentDeltaField];
  1372. dff->fieldIndex = (UA_UInt16) i;
  1373. UA_DataValue_copy(&dataSetWriter->lastSamples[i].value, &dff->fieldValue);
  1374. dataSetWriter->lastSamples[i].valueChanged = false;
  1375. /* Deactivate statuscode? */
  1376. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
  1377. dff->fieldValue.hasStatus = false;
  1378. /* Deactivate timestamps? */
  1379. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
  1380. dff->fieldValue.hasSourceTimestamp = false;
  1381. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
  1382. dff->fieldValue.hasServerPicoseconds = false;
  1383. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
  1384. dff->fieldValue.hasServerTimestamp = false;
  1385. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
  1386. dff->fieldValue.hasServerPicoseconds = false;
  1387. currentDeltaField++;
  1388. }
  1389. return UA_STATUSCODE_GOOD;
  1390. }
  1391. #endif
  1392. /**
  1393. * Generate a DataSetMessage for the given writer.
  1394. *
  1395. * @param dataSetWriter ptr to corresponding writer
  1396. * @return ptr to generated DataSetMessage
  1397. */
  1398. static UA_StatusCode
  1399. UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *dataSetMessage,
  1400. UA_DataSetWriter *dataSetWriter) {
  1401. UA_PublishedDataSet *currentDataSet =
  1402. UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  1403. if(!currentDataSet)
  1404. return UA_STATUSCODE_BADNOTFOUND;
  1405. /* Reset the message */
  1406. memset(dataSetMessage, 0, sizeof(UA_DataSetMessage));
  1407. /* store messageType to switch between json or uadp (default) */
  1408. UA_UInt16 messageType = UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE;
  1409. UA_JsonDataSetWriterMessageDataType *jsonDataSetWriterMessageDataType = NULL;
  1410. /* The configuration Flags are included
  1411. * inside the std. defined UA_UadpDataSetWriterMessageDataType */
  1412. UA_UadpDataSetWriterMessageDataType defaultUadpConfiguration;
  1413. UA_UadpDataSetWriterMessageDataType *dataSetWriterMessageDataType = NULL;
  1414. if((dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED ||
  1415. dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
  1416. (dataSetWriter->config.messageSettings.content.decoded.type ==
  1417. &UA_TYPES[UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE])) {
  1418. dataSetWriterMessageDataType = (UA_UadpDataSetWriterMessageDataType *)
  1419. dataSetWriter->config.messageSettings.content.decoded.data;
  1420. /* type is UADP */
  1421. messageType = UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE;
  1422. } else if((dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED ||
  1423. dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
  1424. (dataSetWriter->config.messageSettings.content.decoded.type ==
  1425. &UA_TYPES[UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE])) {
  1426. jsonDataSetWriterMessageDataType = (UA_JsonDataSetWriterMessageDataType *)
  1427. dataSetWriter->config.messageSettings.content.decoded.data;
  1428. /* type is JSON */
  1429. messageType = UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE;
  1430. } else {
  1431. /* create default flag configuration if no
  1432. * UadpDataSetWriterMessageDataType was passed in */
  1433. memset(&defaultUadpConfiguration, 0, sizeof(UA_UadpDataSetWriterMessageDataType));
  1434. defaultUadpConfiguration.dataSetMessageContentMask = (UA_UadpDataSetMessageContentMask)
  1435. ((u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP | (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION |
  1436. (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION);
  1437. dataSetWriterMessageDataType = &defaultUadpConfiguration;
  1438. }
  1439. /* Sanity-test the configuration */
  1440. if(dataSetWriterMessageDataType &&
  1441. (dataSetWriterMessageDataType->networkMessageNumber != 0 ||
  1442. dataSetWriterMessageDataType->dataSetOffset != 0 ||
  1443. dataSetWriterMessageDataType->configuredSize != 0)) {
  1444. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1445. "Static DSM configuration not supported. Using defaults");
  1446. dataSetWriterMessageDataType->networkMessageNumber = 0;
  1447. dataSetWriterMessageDataType->dataSetOffset = 0;
  1448. dataSetWriterMessageDataType->configuredSize = 0;
  1449. }
  1450. /* The field encoding depends on the flags inside the writer config.
  1451. * TODO: This can be moved to the encoding layer. */
  1452. if(dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_RAWDATA
  1453. ) {
  1454. dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_RAWDATA;
  1455. } else if((u64)dataSetWriter->config.dataSetFieldContentMask &
  1456. ((u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP | (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS |
  1457. (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS | (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE)) {
  1458. dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
  1459. } else {
  1460. dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
  1461. }
  1462. if(messageType == UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE) {
  1463. /* Std: 'The DataSetMessageContentMask defines the flags for the content of the DataSetMessage header.' */
  1464. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1465. (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION) {
  1466. dataSetMessage->header.configVersionMajorVersionEnabled = true;
  1467. dataSetMessage->header.configVersionMajorVersion =
  1468. currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
  1469. }
  1470. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1471. (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION) {
  1472. dataSetMessage->header.configVersionMinorVersionEnabled = true;
  1473. dataSetMessage->header.configVersionMinorVersion =
  1474. currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
  1475. }
  1476. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1477. (u64)UA_UADPDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
  1478. dataSetMessage->header.dataSetMessageSequenceNrEnabled = true;
  1479. dataSetMessage->header.dataSetMessageSequenceNr =
  1480. dataSetWriter->actualDataSetMessageSequenceCount;
  1481. }
  1482. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1483. (u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP) {
  1484. dataSetMessage->header.timestampEnabled = true;
  1485. dataSetMessage->header.timestamp = UA_DateTime_now();
  1486. }
  1487. /* TODO: Picoseconds resolution not supported atm */
  1488. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1489. (u64)UA_UADPDATASETMESSAGECONTENTMASK_PICOSECONDS) {
  1490. dataSetMessage->header.picoSecondsIncluded = false;
  1491. }
  1492. /* TODO: Statuscode not supported yet */
  1493. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1494. (u64)UA_UADPDATASETMESSAGECONTENTMASK_STATUS) {
  1495. dataSetMessage->header.statusEnabled = false;
  1496. }
  1497. } else if(messageType == UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE) {
  1498. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1499. (u64)UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION) {
  1500. dataSetMessage->header.configVersionMajorVersionEnabled = true;
  1501. dataSetMessage->header.configVersionMajorVersion =
  1502. currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
  1503. }
  1504. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1505. (u64)UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION) {
  1506. dataSetMessage->header.configVersionMinorVersionEnabled = true;
  1507. dataSetMessage->header.configVersionMinorVersion =
  1508. currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
  1509. }
  1510. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1511. (u64)UA_JSONDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
  1512. dataSetMessage->header.dataSetMessageSequenceNrEnabled = true;
  1513. dataSetMessage->header.dataSetMessageSequenceNr =
  1514. dataSetWriter->actualDataSetMessageSequenceCount;
  1515. }
  1516. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1517. (u64)UA_JSONDATASETMESSAGECONTENTMASK_TIMESTAMP) {
  1518. dataSetMessage->header.timestampEnabled = true;
  1519. dataSetMessage->header.timestamp = UA_DateTime_now();
  1520. }
  1521. /* TODO: Statuscode not supported yet */
  1522. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1523. (u64)UA_JSONDATASETMESSAGECONTENTMASK_STATUS) {
  1524. dataSetMessage->header.statusEnabled = false;
  1525. }
  1526. }
  1527. /* Set the sequence count. Automatically rolls over to zero */
  1528. dataSetWriter->actualDataSetMessageSequenceCount++;
  1529. /* JSON does not differ between deltaframes and keyframes, only keyframes are currently used. */
  1530. if(messageType != UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE){
  1531. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1532. /* Check if the PublishedDataSet version has changed -> if yes flush the lastValue store and send a KeyFrame */
  1533. if(dataSetWriter->connectedDataSetVersion.majorVersion != currentDataSet->dataSetMetaData.configurationVersion.majorVersion ||
  1534. dataSetWriter->connectedDataSetVersion.minorVersion != currentDataSet->dataSetMetaData.configurationVersion.minorVersion) {
  1535. /* Remove old samples */
  1536. for(size_t i = 0; i < dataSetWriter->lastSamplesCount; i++)
  1537. UA_DataValue_clear(&dataSetWriter->lastSamples[i].value);
  1538. /* Realloc pds dependent memory */
  1539. dataSetWriter->lastSamplesCount = currentDataSet->fieldSize;
  1540. UA_DataSetWriterSample *newSamplesArray = (UA_DataSetWriterSample * )
  1541. UA_realloc(dataSetWriter->lastSamples, sizeof(UA_DataSetWriterSample) * dataSetWriter->lastSamplesCount);
  1542. if(!newSamplesArray)
  1543. return UA_STATUSCODE_BADOUTOFMEMORY;
  1544. dataSetWriter->lastSamples = newSamplesArray;
  1545. memset(dataSetWriter->lastSamples, 0, sizeof(UA_DataSetWriterSample) * dataSetWriter->lastSamplesCount);
  1546. dataSetWriter->connectedDataSetVersion = currentDataSet->dataSetMetaData.configurationVersion;
  1547. UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage, dataSetWriter);
  1548. dataSetWriter->deltaFrameCounter = 0;
  1549. return UA_STATUSCODE_GOOD;
  1550. }
  1551. /* The standard defines: if a PDS contains only one fields no delta messages
  1552. * should be generated because they need more memory than a keyframe with 1
  1553. * field. */
  1554. if(currentDataSet->fieldSize > 1 && dataSetWriter->deltaFrameCounter > 0 &&
  1555. dataSetWriter->deltaFrameCounter <= dataSetWriter->config.keyFrameCount) {
  1556. UA_PubSubDataSetWriter_generateDeltaFrameMessage(server, dataSetMessage, dataSetWriter);
  1557. dataSetWriter->deltaFrameCounter++;
  1558. return UA_STATUSCODE_GOOD;
  1559. }
  1560. dataSetWriter->deltaFrameCounter = 1;
  1561. #endif
  1562. }
  1563. UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage, dataSetWriter);
  1564. return UA_STATUSCODE_GOOD;
  1565. }
  1566. static UA_StatusCode
  1567. sendNetworkMessageJson(UA_PubSubConnection *connection, UA_DataSetMessage *dsm,
  1568. UA_UInt16 *writerIds, UA_Byte dsmCount, UA_ExtensionObject *transportSettings) {
  1569. UA_StatusCode retval = UA_STATUSCODE_BADNOTSUPPORTED;
  1570. #ifdef UA_ENABLE_JSON_ENCODING
  1571. UA_NetworkMessage nm;
  1572. memset(&nm, 0, sizeof(UA_NetworkMessage));
  1573. nm.version = 1;
  1574. nm.networkMessageType = UA_NETWORKMESSAGE_DATASET;
  1575. nm.payloadHeaderEnabled = true;
  1576. nm.payloadHeader.dataSetPayloadHeader.count = dsmCount;
  1577. nm.payloadHeader.dataSetPayloadHeader.dataSetWriterIds = writerIds;
  1578. nm.payload.dataSetPayload.dataSetMessages = dsm;
  1579. /* Allocate the buffer. Allocate on the stack if the buffer is small. */
  1580. UA_ByteString buf;
  1581. size_t msgSize = UA_NetworkMessage_calcSizeJson(&nm, NULL, 0, NULL, 0, true);
  1582. size_t stackSize = 1;
  1583. if(msgSize <= UA_MAX_STACKBUF)
  1584. stackSize = msgSize;
  1585. UA_STACKARRAY(UA_Byte, stackBuf, stackSize);
  1586. buf.data = stackBuf;
  1587. buf.length = msgSize;
  1588. if(msgSize > UA_MAX_STACKBUF) {
  1589. retval = UA_ByteString_allocBuffer(&buf, msgSize);
  1590. if(retval != UA_STATUSCODE_GOOD)
  1591. return retval;
  1592. }
  1593. /* Encode the message */
  1594. UA_Byte *bufPos = buf.data;
  1595. memset(bufPos, 0, msgSize);
  1596. const UA_Byte *bufEnd = &buf.data[buf.length];
  1597. retval = UA_NetworkMessage_encodeJson(&nm, &bufPos, &bufEnd, NULL, 0, NULL, 0, true);
  1598. if(retval != UA_STATUSCODE_GOOD) {
  1599. if(msgSize > UA_MAX_STACKBUF)
  1600. UA_ByteString_clear(&buf);
  1601. return retval;
  1602. }
  1603. /* Send the prepared messages */
  1604. retval = connection->channel->send(connection->channel, transportSettings, &buf);
  1605. if(msgSize > UA_MAX_STACKBUF)
  1606. UA_ByteString_clear(&buf);
  1607. #endif
  1608. return retval;
  1609. }
  1610. static UA_StatusCode
  1611. generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
  1612. UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount,
  1613. UA_ExtensionObject *messageSettings,
  1614. UA_ExtensionObject *transportSettings,
  1615. UA_NetworkMessage *networkMessage) {
  1616. if(messageSettings->content.decoded.type !=
  1617. &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
  1618. return UA_STATUSCODE_BADINTERNALERROR;
  1619. UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
  1620. messageSettings->content.decoded.data;
  1621. networkMessage->publisherIdEnabled =
  1622. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PUBLISHERID) != 0;
  1623. networkMessage->groupHeaderEnabled =
  1624. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPHEADER) != 0;
  1625. networkMessage->groupHeader.writerGroupIdEnabled =
  1626. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_WRITERGROUPID) != 0;
  1627. networkMessage->groupHeader.groupVersionEnabled =
  1628. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPVERSION) != 0;
  1629. networkMessage->groupHeader.networkMessageNumberEnabled =
  1630. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_NETWORKMESSAGENUMBER) != 0;
  1631. networkMessage->groupHeader.sequenceNumberEnabled =
  1632. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_SEQUENCENUMBER) != 0;
  1633. networkMessage->payloadHeaderEnabled =
  1634. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER) != 0;
  1635. networkMessage->timestampEnabled =
  1636. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_TIMESTAMP) != 0;
  1637. networkMessage->picosecondsEnabled =
  1638. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PICOSECONDS) != 0;
  1639. networkMessage->dataSetClassIdEnabled =
  1640. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_DATASETCLASSID) != 0;
  1641. networkMessage->promotedFieldsEnabled =
  1642. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PROMOTEDFIELDS) != 0;
  1643. networkMessage->version = 1;
  1644. networkMessage->networkMessageType = UA_NETWORKMESSAGE_DATASET;
  1645. if(connection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_NUMERIC) {
  1646. networkMessage->publisherIdType = UA_PUBLISHERDATATYPE_UINT16;
  1647. networkMessage->publisherId.publisherIdUInt32 = connection->config->publisherId.numeric;
  1648. } else if(connection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING){
  1649. networkMessage->publisherIdType = UA_PUBLISHERDATATYPE_STRING;
  1650. networkMessage->publisherId.publisherIdString = connection->config->publisherId.string;
  1651. }
  1652. if(networkMessage->groupHeader.sequenceNumberEnabled)
  1653. networkMessage->groupHeader.sequenceNumber = wg->sequenceNumber;
  1654. /* Compute the length of the dsm separately for the header */
  1655. UA_STACKARRAY(UA_UInt16, dsmLengths, dsmCount);
  1656. for(UA_Byte i = 0; i < dsmCount; i++)
  1657. dsmLengths[i] = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&dsm[i], NULL, 0);
  1658. networkMessage->payloadHeader.dataSetPayloadHeader.count = dsmCount;
  1659. networkMessage->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = writerIds;
  1660. networkMessage->groupHeader.writerGroupId = wg->config.writerGroupId;
  1661. /* number of the NetworkMessage inside a PublishingInterval */
  1662. networkMessage->groupHeader.networkMessageNumber = 1;
  1663. networkMessage->payload.dataSetPayload.sizes = dsmLengths;
  1664. networkMessage->payload.dataSetPayload.dataSetMessages = dsm;
  1665. return UA_STATUSCODE_GOOD;
  1666. }
  1667. static UA_StatusCode
  1668. sendBufferedNetworkMessage(UA_Server *server, UA_PubSubConnection *connection,
  1669. UA_NetworkMessageOffsetBuffer *buffer, UA_ExtensionObject *transportSettings) {
  1670. if(UA_NetworkMessage_updateBufferedMessage(buffer) != UA_STATUSCODE_GOOD)
  1671. UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, "PubSub sending. Unknown field type.");
  1672. UA_StatusCode retval = connection->channel->send(connection->channel, transportSettings, &buffer->buffer);
  1673. return retval;
  1674. }
  1675. static UA_StatusCode
  1676. sendNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
  1677. UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount,
  1678. UA_ExtensionObject *messageSettings,
  1679. UA_ExtensionObject *transportSettings) {
  1680. UA_NetworkMessage nm;
  1681. memset(&nm, 0, sizeof(UA_NetworkMessage));
  1682. generateNetworkMessage(connection, wg, dsm, writerIds, dsmCount, messageSettings, transportSettings, &nm);
  1683. /* Allocate the buffer. Allocate on the stack if the buffer is small. */
  1684. UA_ByteString buf;
  1685. size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nm, NULL);
  1686. size_t stackSize = 1;
  1687. if(msgSize <= UA_MAX_STACKBUF)
  1688. stackSize = msgSize;
  1689. UA_STACKARRAY(UA_Byte, stackBuf, stackSize);
  1690. buf.data = stackBuf;
  1691. buf.length = msgSize;
  1692. UA_StatusCode retval;
  1693. if(msgSize > UA_MAX_STACKBUF) {
  1694. retval = UA_ByteString_allocBuffer(&buf, msgSize);
  1695. if(retval != UA_STATUSCODE_GOOD)
  1696. return retval;
  1697. }
  1698. /* Encode the message */
  1699. UA_Byte *bufPos = buf.data;
  1700. memset(bufPos, 0, msgSize);
  1701. const UA_Byte *bufEnd = &buf.data[buf.length];
  1702. retval = UA_NetworkMessage_encodeBinary(&nm, &bufPos, bufEnd);
  1703. if(retval != UA_STATUSCODE_GOOD) {
  1704. if(msgSize > UA_MAX_STACKBUF)
  1705. UA_ByteString_clear(&buf);
  1706. return retval;
  1707. }
  1708. /* Send the prepared messages */
  1709. retval = connection->channel->send(connection->channel, transportSettings, &buf);
  1710. if(msgSize > UA_MAX_STACKBUF)
  1711. UA_ByteString_clear(&buf);
  1712. return retval;
  1713. }
  1714. /* This callback triggers the collection and publish of NetworkMessages and the
  1715. * contained DataSetMessages. */
  1716. void
  1717. UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
  1718. UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, "Publish Callback");
  1719. if(!writerGroup) {
  1720. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1721. "Publish failed. WriterGroup not found");
  1722. return;
  1723. }
  1724. /* Nothing to do? */
  1725. if(writerGroup->writersCount <= 0)
  1726. return;
  1727. if(!writerGroup->linkedConnectionPtr){
  1728. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1729. "Publish failed: Invalid reference to PubSubConnection");
  1730. return;
  1731. }
  1732. /* Binary or Json encoding? */
  1733. if(writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP &&
  1734. writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_JSON) {
  1735. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1736. "Publish failed: Unknown encoding type.");
  1737. return;
  1738. }
  1739. /* Find the connection associated with the writer */
  1740. UA_PubSubConnection *connection = writerGroup->linkedConnectionPtr;
  1741. if(!connection) {
  1742. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1743. "Publish failed. PubSubConnection invalid.");
  1744. return;
  1745. }
  1746. if(writerGroup->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) {
  1747. sendBufferedNetworkMessage(server, connection, &writerGroup->bufferedMessage, &writerGroup->config.transportSettings);
  1748. writerGroup->sequenceNumber++;
  1749. return;
  1750. }
  1751. /* How many DSM can be sent in one NM? */
  1752. UA_Byte maxDSM = (UA_Byte)writerGroup->config.maxEncapsulatedDataSetMessageCount;
  1753. if(writerGroup->config.maxEncapsulatedDataSetMessageCount > UA_BYTE_MAX)
  1754. maxDSM = UA_BYTE_MAX;
  1755. /* If the maxEncapsulatedDataSetMessageCount is set to 0->1 */
  1756. if(maxDSM == 0)
  1757. maxDSM = 1;
  1758. /* It is possible to put several DataSetMessages into one NetworkMessage.
  1759. * But only if they do not contain promoted fields. NM with only DSM are
  1760. * sent out right away. The others are kept in a buffer for "batching". */
  1761. size_t dsmCount = 0;
  1762. UA_DataSetWriter *dsw;
  1763. UA_STACKARRAY(UA_UInt16, dsWriterIds, writerGroup->writersCount);
  1764. UA_STACKARRAY(UA_DataSetMessage, dsmStore, writerGroup->writersCount);
  1765. LIST_FOREACH(dsw, &writerGroup->writers, listEntry) {
  1766. /* Find the dataset */
  1767. UA_PublishedDataSet *pds =
  1768. UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet);
  1769. if(!pds) {
  1770. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1771. "PubSub Publish: PublishedDataSet not found");
  1772. continue;
  1773. }
  1774. /* Generate the DSM */
  1775. UA_StatusCode res =
  1776. UA_DataSetWriter_generateDataSetMessage(server, &dsmStore[dsmCount], dsw);
  1777. if(res != UA_STATUSCODE_GOOD) {
  1778. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1779. "PubSub Publish: DataSetMessage creation failed");
  1780. continue;
  1781. }
  1782. /* Send right away if there is only this DSM in a NM. If promoted fields
  1783. * are contained in the PublishedDataSet, then this DSM must go into a
  1784. * dedicated NM as well. */
  1785. if(pds->promotedFieldsCount > 0 || maxDSM == 1) {
  1786. if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP){
  1787. res = sendNetworkMessage(connection, writerGroup, &dsmStore[dsmCount],
  1788. &dsw->config.dataSetWriterId, 1,
  1789. &writerGroup->config.messageSettings,
  1790. &writerGroup->config.transportSettings);
  1791. }else if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON){
  1792. res = sendNetworkMessageJson(connection, &dsmStore[dsmCount],
  1793. &dsw->config.dataSetWriterId, 1, &writerGroup->config.transportSettings);
  1794. }
  1795. if(res != UA_STATUSCODE_GOOD)
  1796. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1797. "PubSub Publish: Could not send a NetworkMessage");
  1798. if(writerGroup->config.rtLevel == UA_PUBSUB_RT_DIRECT_VALUE_ACCESS){
  1799. for (size_t i = 0; i < dsmStore[dsmCount].data.keyFrameData.fieldCount; ++i) {
  1800. dsmStore[dsmCount].data.keyFrameData.dataSetFields[i].value.data = NULL;
  1801. }
  1802. }
  1803. UA_DataSetMessage_free(&dsmStore[dsmCount]);
  1804. continue;
  1805. }
  1806. dsWriterIds[dsmCount] = dsw->config.dataSetWriterId;
  1807. dsmCount++;
  1808. }
  1809. /* Send the NetworkMessages with batched DataSetMessages */
  1810. size_t nmCount = (dsmCount / maxDSM) + ((dsmCount % maxDSM) == 0 ? 0 : 1);
  1811. for(UA_UInt32 i = 0; i < nmCount; i++) {
  1812. UA_Byte nmDsmCount = maxDSM;
  1813. if(i == nmCount - 1 && (dsmCount % maxDSM))
  1814. nmDsmCount = (UA_Byte)dsmCount % maxDSM;
  1815. UA_StatusCode res3 = UA_STATUSCODE_GOOD;
  1816. if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP){
  1817. res3 = sendNetworkMessage(connection, writerGroup, &dsmStore[i * maxDSM],
  1818. &dsWriterIds[i * maxDSM], nmDsmCount,
  1819. &writerGroup->config.messageSettings,
  1820. &writerGroup->config.transportSettings);
  1821. writerGroup->sequenceNumber++;
  1822. }else if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON){
  1823. res3 = sendNetworkMessageJson(connection, &dsmStore[i * maxDSM],
  1824. &dsWriterIds[i * maxDSM], nmDsmCount, &writerGroup->config.transportSettings);
  1825. writerGroup->sequenceNumber++;
  1826. }
  1827. if(res3 != UA_STATUSCODE_GOOD)
  1828. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1829. "PubSub Publish: Sending a NetworkMessage failed");
  1830. }
  1831. /* Clean up DSM */
  1832. for(size_t i = 0; i < dsmCount; i++)
  1833. UA_DataSetMessage_free(&dsmStore[i]);
  1834. }
  1835. /* Add new publishCallback. The first execution is triggered directly after
  1836. * creation. */
  1837. UA_StatusCode
  1838. UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
  1839. UA_StatusCode retval =
  1840. UA_PubSubManager_addRepeatedCallback(server,
  1841. (UA_ServerCallback) UA_WriterGroup_publishCallback,
  1842. writerGroup, writerGroup->config.publishingInterval,
  1843. &writerGroup->publishCallbackId);
  1844. if(retval == UA_STATUSCODE_GOOD)
  1845. writerGroup->publishCallbackIsRegistered = true;
  1846. /* Run once after creation */
  1847. UA_WriterGroup_publishCallback(server, writerGroup);
  1848. return retval;
  1849. }
  1850. #endif /* UA_ENABLE_PUBSUB */