ua_pubsub_writer.c 91 KB

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