ua_pubsub_writer.c 91 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042
  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. for(size_t i = 0; i < server->pubSubManager.connectionsSize; i++){
  80. if(UA_NodeId_equal(&connectionIdentifier, &server->pubSubManager.connections[i].identifier)){
  81. return &server->pubSubManager.connections[i];
  82. }
  83. }
  84. return NULL;
  85. }
  86. void
  87. UA_PubSubConnectionConfig_clear(UA_PubSubConnectionConfig *connectionConfig) {
  88. UA_String_clear(&connectionConfig->name);
  89. UA_String_clear(&connectionConfig->transportProfileUri);
  90. UA_Variant_clear(&connectionConfig->connectionTransportSettings);
  91. UA_Variant_clear(&connectionConfig->address);
  92. for(size_t i = 0; i < connectionConfig->connectionPropertiesSize; i++){
  93. UA_QualifiedName_clear(&connectionConfig->connectionProperties[i].key);
  94. UA_Variant_clear(&connectionConfig->connectionProperties[i].value);
  95. }
  96. UA_free(connectionConfig->connectionProperties);
  97. }
  98. void
  99. UA_PubSubConnection_clear(UA_Server *server, UA_PubSubConnection *connection) {
  100. //delete connection config
  101. UA_PubSubConnectionConfig_clear(connection->config);
  102. //remove contained WriterGroups
  103. UA_WriterGroup *writerGroup, *tmpWriterGroup;
  104. LIST_FOREACH_SAFE(writerGroup, &connection->writerGroups, listEntry, tmpWriterGroup){
  105. UA_Server_removeWriterGroup(server, writerGroup->identifier);
  106. }
  107. /* remove contained ReaderGroups */
  108. UA_ReaderGroup *readerGroups, *tmpReaderGroup;
  109. LIST_FOREACH_SAFE(readerGroups, &connection->readerGroups, listEntry, tmpReaderGroup){
  110. UA_Server_removeReaderGroup(server, readerGroups->identifier);
  111. }
  112. UA_NodeId_clear(&connection->identifier);
  113. if(connection->channel){
  114. connection->channel->close(connection->channel);
  115. }
  116. UA_free(connection->config);
  117. }
  118. UA_StatusCode
  119. UA_PubSubConnection_regist(UA_Server *server, UA_NodeId *connectionIdentifier) {
  120. UA_PubSubConnection *connection =
  121. UA_PubSubConnection_findConnectionbyId(server, *connectionIdentifier);
  122. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  123. if(connection == NULL) {
  124. return UA_STATUSCODE_BADNOTFOUND;
  125. }
  126. retval = connection->channel->regist(connection->channel, NULL, NULL);
  127. if(retval != UA_STATUSCODE_GOOD) {
  128. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  129. "register channel failed: 0x%x!", retval);
  130. }
  131. return retval;
  132. }
  133. UA_StatusCode
  134. UA_Server_addWriterGroup(UA_Server *server, const UA_NodeId connection,
  135. const UA_WriterGroupConfig *writerGroupConfig,
  136. UA_NodeId *writerGroupIdentifier) {
  137. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  138. if(!writerGroupConfig)
  139. return UA_STATUSCODE_BADINVALIDARGUMENT;
  140. //search the connection by the given connectionIdentifier
  141. UA_PubSubConnection *currentConnectionContext =
  142. UA_PubSubConnection_findConnectionbyId(server, connection);
  143. if(!currentConnectionContext)
  144. return UA_STATUSCODE_BADNOTFOUND;
  145. if(currentConnectionContext->config->configurationFrozen){
  146. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  147. "Adding WriterGroup failed. PubSubConnection is frozen.");
  148. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  149. }
  150. //allocate memory for new WriterGroup
  151. UA_WriterGroup *newWriterGroup = (UA_WriterGroup *) UA_calloc(1, sizeof(UA_WriterGroup));
  152. if(!newWriterGroup)
  153. return UA_STATUSCODE_BADOUTOFMEMORY;
  154. newWriterGroup->linkedConnection = currentConnectionContext->identifier;
  155. newWriterGroup->linkedConnectionPtr = 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 =
  188. UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
  189. if(!connection)
  190. return UA_STATUSCODE_BADNOTFOUND;
  191. if(connection->config->configurationFrozen){
  192. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  193. "Delete WriterGroup failed. PubSubConnection is frozen.");
  194. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  195. }
  196. if(wg->state == UA_PUBSUBSTATE_OPERATIONAL){
  197. //unregister the publish callback
  198. UA_PubSubManager_removeRepeatedPubSubCallback(server, wg->publishCallbackId);
  199. }
  200. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  201. removeGroupRepresentation(server, wg);
  202. #endif
  203. UA_WriterGroup_clear(server, wg);
  204. LIST_REMOVE(wg, listEntry);
  205. UA_free(wg);
  206. return UA_STATUSCODE_GOOD;
  207. }
  208. UA_StatusCode
  209. UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup){
  210. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  211. if(!wg)
  212. return UA_STATUSCODE_BADNOTFOUND;
  213. //PubSubConnection freezeCounter++
  214. UA_PubSubConnection *pubSubConnection = UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
  215. pubSubConnection->configurationFreezeCounter++;
  216. pubSubConnection->config->configurationFrozen = UA_TRUE;
  217. //WriterGroup freeze
  218. wg->config.configurationFrozen = UA_TRUE;
  219. //DataSetWriter freeze
  220. UA_DataSetWriter *dataSetWriter;
  221. LIST_FOREACH(dataSetWriter, &wg->writers, listEntry){
  222. dataSetWriter->config.configurationFrozen = UA_TRUE;
  223. //PublishedDataSet freezeCounter++
  224. UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  225. publishedDataSet->configurationFreezeCounter++;
  226. publishedDataSet->config.configurationFrozen = UA_TRUE;
  227. //DataSetFields freeze
  228. UA_DataSetField *dataSetField;
  229. TAILQ_FOREACH(dataSetField, &publishedDataSet->fields, listEntry){
  230. dataSetField->config.configurationFrozen = UA_TRUE;
  231. }
  232. }
  233. if(wg->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE){
  234. size_t dsmCount = 0;
  235. if(wg->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP) {
  236. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  237. "PubSub-RT configuration fail: Non-RT capable encoding.");
  238. return UA_STATUSCODE_BADNOTSUPPORTED;
  239. }
  240. //TODO Clarify: should we only allow = maxEncapsulatedDataSetMessageCount == 1 with RT?
  241. //TODO Clarify: Behaviour if the finale size is more than MTU
  242. /* Generate data set messages */
  243. UA_STACKARRAY(UA_UInt16, dsWriterIds, wg->writersCount);
  244. UA_STACKARRAY(UA_DataSetMessage, dsmStore, wg->writersCount);
  245. UA_DataSetWriter *dsw;
  246. LIST_FOREACH(dsw, &wg->writers, listEntry) {
  247. /* Find the dataset */
  248. UA_PublishedDataSet *pds =
  249. UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet);
  250. if(!pds) {
  251. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  252. "PubSub Publish: PublishedDataSet not found");
  253. continue;
  254. }
  255. if(pds->promotedFieldsCount > 0) {
  256. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  257. "PubSub-RT configuration fail: PDS contains promoted fields.");
  258. return UA_STATUSCODE_BADNOTSUPPORTED;
  259. }
  260. UA_DataSetField *dsf;
  261. TAILQ_FOREACH(dsf, &pds->fields, listEntry){
  262. if(!dsf->config.field.variable.staticValueSourceEnabled){
  263. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  264. "PubSub-RT configuration fail: PDS contains variables with dynamic length types.");
  265. return UA_STATUSCODE_BADNOTSUPPORTED;
  266. }
  267. if((UA_NodeId_equal(&dsf->fieldMetaData.dataType, &UA_TYPES[UA_TYPES_STRING].typeId) ||
  268. UA_NodeId_equal(&dsf->fieldMetaData.dataType, &UA_TYPES[UA_TYPES_BYTESTRING].typeId)) &&
  269. dsf->fieldMetaData.maxStringLength == 0){
  270. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  271. "PubSub-RT configuration fail: PDS contains String/ByteString with dynamic length.");
  272. return UA_STATUSCODE_BADNOTSUPPORTED;
  273. } else if(!UA_DataType_isNumeric(UA_findDataType(&dsf->fieldMetaData.dataType))){
  274. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  275. "PubSub-RT configuration fail: PDS contains variable with dynamic size.");
  276. return UA_STATUSCODE_BADNOTSUPPORTED;
  277. }
  278. }
  279. /* Generate the DSM */
  280. UA_StatusCode res =
  281. UA_DataSetWriter_generateDataSetMessage(server, &dsmStore[dsmCount], dsw);
  282. if(res != UA_STATUSCODE_GOOD) {
  283. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  284. "PubSub RT Offset calculation: DataSetMessage buffering failed");
  285. continue;
  286. }
  287. dsWriterIds[dsmCount] = dsw->config.dataSetWriterId;
  288. dsmCount++;
  289. }
  290. UA_NetworkMessage networkMessage;
  291. memset(&networkMessage, 0, sizeof(networkMessage));
  292. UA_StatusCode res = generateNetworkMessage(pubSubConnection, wg, dsmStore, dsWriterIds, (UA_Byte) dsmCount,
  293. &wg->config.messageSettings, &wg->config.transportSettings, &networkMessage);
  294. if(res != UA_STATUSCODE_GOOD)
  295. return UA_STATUSCODE_BADINTERNALERROR;
  296. UA_NetworkMessage_calcSizeBinary(&networkMessage, &wg->bufferedMessage);
  297. /* Allocate the buffer. Allocate on the stack if the buffer is small. */
  298. UA_ByteString buf;
  299. size_t msgSize = UA_NetworkMessage_calcSizeBinary(&networkMessage, NULL);
  300. res = UA_ByteString_allocBuffer(&buf, msgSize);
  301. if(res != UA_STATUSCODE_GOOD)
  302. return UA_STATUSCODE_BADOUTOFMEMORY;
  303. wg->bufferedMessage.buffer = buf;
  304. const UA_Byte *bufEnd = &wg->bufferedMessage.buffer.data[wg->bufferedMessage.buffer.length];
  305. UA_Byte *bufPos = wg->bufferedMessage.buffer.data;
  306. UA_NetworkMessage_encodeBinary(&networkMessage, &bufPos, bufEnd);
  307. /* Clean up DSM */
  308. for(size_t i = 0; i < dsmCount; i++){
  309. UA_free(dsmStore[i].data.keyFrameData.dataSetFields);
  310. #ifdef UA_ENABLE_JSON_ENCODING
  311. UA_free(dsmStore[i].data.keyFrameData.fieldNames);
  312. #endif
  313. }
  314. //UA_DataSetMessage_free(&dsmStore[i]);
  315. }
  316. return UA_STATUSCODE_GOOD;
  317. }
  318. UA_StatusCode
  319. UA_Server_unfreezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup){
  320. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  321. if(!wg)
  322. return UA_STATUSCODE_BADNOTFOUND;
  323. //if(wg->config.rtLevel == UA_PUBSUB_RT_NONE){
  324. // UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  325. // "PubSub configuration freeze without RT configuration has no effect.");
  326. // return UA_STATUSCODE_BADCONFIGURATIONERROR;
  327. //}
  328. //PubSubConnection freezeCounter--
  329. UA_PubSubConnection *pubSubConnection = UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
  330. pubSubConnection->configurationFreezeCounter--;
  331. if(pubSubConnection->configurationFreezeCounter == 0){
  332. pubSubConnection->config->configurationFrozen = UA_FALSE;
  333. }
  334. //WriterGroup unfreeze
  335. wg->config.configurationFrozen = UA_FALSE;
  336. //DataSetWriter unfreeze
  337. UA_DataSetWriter *dataSetWriter;
  338. LIST_FOREACH(dataSetWriter, &wg->writers, listEntry){
  339. UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  340. //PublishedDataSet freezeCounter--
  341. publishedDataSet->configurationFreezeCounter--;
  342. if(publishedDataSet->configurationFreezeCounter == 0){
  343. publishedDataSet->config.configurationFrozen = UA_FALSE;
  344. UA_DataSetField *dataSetField;
  345. TAILQ_FOREACH(dataSetField, &publishedDataSet->fields, listEntry){
  346. dataSetField->config.configurationFrozen = UA_FALSE;
  347. }
  348. }
  349. dataSetWriter->config.configurationFrozen = UA_FALSE;
  350. }
  351. return UA_STATUSCODE_GOOD;
  352. }
  353. UA_StatusCode UA_EXPORT
  354. UA_Server_setWriterGroupOperational(UA_Server *server, const UA_NodeId writerGroup){
  355. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  356. if(!wg)
  357. return UA_STATUSCODE_BADNOTFOUND;
  358. return UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, wg);
  359. }
  360. UA_StatusCode UA_EXPORT
  361. UA_Server_setWriterGroupDisabled(UA_Server *server, const UA_NodeId writerGroup){
  362. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  363. if(!wg)
  364. return UA_STATUSCODE_BADNOTFOUND;
  365. return UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, wg);
  366. }
  367. /**********************************************/
  368. /* PublishedDataSet */
  369. /**********************************************/
  370. UA_StatusCode
  371. UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src,
  372. UA_PublishedDataSetConfig *dst) {
  373. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  374. memcpy(dst, src, sizeof(UA_PublishedDataSetConfig));
  375. retVal |= UA_String_copy(&src->name, &dst->name);
  376. switch(src->publishedDataSetType){
  377. case UA_PUBSUB_DATASET_PUBLISHEDITEMS:
  378. //no additional items
  379. break;
  380. case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE:
  381. if(src->config.itemsTemplate.variablesToAddSize > 0){
  382. dst->config.itemsTemplate.variablesToAdd = (UA_PublishedVariableDataType *) UA_calloc(
  383. src->config.itemsTemplate.variablesToAddSize, sizeof(UA_PublishedVariableDataType));
  384. }
  385. for(size_t i = 0; i < src->config.itemsTemplate.variablesToAddSize; i++){
  386. retVal |= UA_PublishedVariableDataType_copy(&src->config.itemsTemplate.variablesToAdd[i],
  387. &dst->config.itemsTemplate.variablesToAdd[i]);
  388. }
  389. retVal |= UA_DataSetMetaDataType_copy(&src->config.itemsTemplate.metaData,
  390. &dst->config.itemsTemplate.metaData);
  391. break;
  392. default:
  393. return UA_STATUSCODE_BADINVALIDARGUMENT;
  394. }
  395. return retVal;
  396. }
  397. UA_StatusCode
  398. UA_Server_getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pds,
  399. UA_PublishedDataSetConfig *config){
  400. if(!config)
  401. return UA_STATUSCODE_BADINVALIDARGUMENT;
  402. UA_PublishedDataSet *currentPublishedDataSet = UA_PublishedDataSet_findPDSbyId(server, pds);
  403. if(!currentPublishedDataSet)
  404. return UA_STATUSCODE_BADNOTFOUND;
  405. UA_PublishedDataSetConfig tmpPublishedDataSetConfig;
  406. //deep copy of the actual config
  407. UA_PublishedDataSetConfig_copy(&currentPublishedDataSet->config, &tmpPublishedDataSetConfig);
  408. *config = tmpPublishedDataSetConfig;
  409. return UA_STATUSCODE_GOOD;
  410. }
  411. UA_StatusCode
  412. UA_Server_getPublishedDataSetMetaData(UA_Server *server, const UA_NodeId pds, UA_DataSetMetaDataType *metaData){
  413. if(!metaData)
  414. return UA_STATUSCODE_BADINVALIDARGUMENT;
  415. UA_PublishedDataSet *currentPublishedDataSet = UA_PublishedDataSet_findPDSbyId(server, pds);
  416. if(!currentPublishedDataSet)
  417. return UA_STATUSCODE_BADNOTFOUND;
  418. UA_DataSetMetaDataType tmpDataSetMetaData;
  419. if(UA_DataSetMetaDataType_copy(&currentPublishedDataSet->dataSetMetaData, &tmpDataSetMetaData) != UA_STATUSCODE_GOOD)
  420. return UA_STATUSCODE_BADINTERNALERROR;
  421. *metaData = tmpDataSetMetaData;
  422. return UA_STATUSCODE_GOOD;
  423. }
  424. UA_PublishedDataSet *
  425. UA_PublishedDataSet_findPDSbyId(UA_Server *server, UA_NodeId identifier){
  426. for(size_t i = 0; i < server->pubSubManager.publishedDataSetsSize; i++){
  427. if(UA_NodeId_equal(&server->pubSubManager.publishedDataSets[i].identifier, &identifier)){
  428. return &server->pubSubManager.publishedDataSets[i];
  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. for(size_t i = 0; i < server->pubSubManager.connectionsSize; i++){
  725. UA_WriterGroup *tmpWriterGroup;
  726. LIST_FOREACH(tmpWriterGroup, &server->pubSubManager.connections[i].writerGroups, listEntry){
  727. UA_DataSetWriter *tmpWriter;
  728. LIST_FOREACH(tmpWriter, &tmpWriterGroup->writers, listEntry){
  729. if(UA_NodeId_equal(&tmpWriter->identifier, &identifier)){
  730. return tmpWriter;
  731. }
  732. }
  733. }
  734. }
  735. return NULL;
  736. }
  737. void
  738. UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig *pdsConfig) {
  739. UA_String_clear(&pdsConfig->name);
  740. UA_String_clear(&pdsConfig->dataSetName);
  741. for(size_t i = 0; i < pdsConfig->dataSetWriterPropertiesSize; i++){
  742. UA_KeyValuePair_clear(&pdsConfig->dataSetWriterProperties[i]);
  743. }
  744. UA_free(pdsConfig->dataSetWriterProperties);
  745. UA_ExtensionObject_clear(&pdsConfig->messageSettings);
  746. }
  747. static void
  748. UA_DataSetWriter_clear(UA_Server *server, UA_DataSetWriter *dataSetWriter) {
  749. UA_DataSetWriterConfig_clear(&dataSetWriter->config);
  750. //delete DataSetWriter
  751. UA_NodeId_clear(&dataSetWriter->identifier);
  752. UA_NodeId_clear(&dataSetWriter->linkedWriterGroup);
  753. UA_NodeId_clear(&dataSetWriter->connectedDataSet);
  754. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  755. //delete lastSamples store
  756. for(size_t i = 0; i < dataSetWriter->lastSamplesCount; i++) {
  757. UA_DataValue_clear(&dataSetWriter->lastSamples[i].value);
  758. }
  759. UA_free(dataSetWriter->lastSamples);
  760. dataSetWriter->lastSamples = NULL;
  761. dataSetWriter->lastSamplesCount = 0;
  762. #endif
  763. }
  764. //state machine methods not part of the open62541 state machine API
  765. UA_StatusCode
  766. UA_DataSetWriter_setPubSubState(UA_Server *server, UA_PubSubState state, UA_DataSetWriter *dataSetWriter){
  767. switch(state){
  768. case UA_PUBSUBSTATE_DISABLED:
  769. switch (dataSetWriter->state){
  770. case UA_PUBSUBSTATE_DISABLED:
  771. return UA_STATUSCODE_GOOD;
  772. case UA_PUBSUBSTATE_PAUSED:
  773. dataSetWriter->state = UA_PUBSUBSTATE_DISABLED;
  774. //no further action is required
  775. break;
  776. case UA_PUBSUBSTATE_OPERATIONAL:
  777. dataSetWriter->state = UA_PUBSUBSTATE_DISABLED;
  778. break;
  779. case UA_PUBSUBSTATE_ERROR:
  780. break;
  781. default:
  782. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  783. "Received unknown PubSub state!");
  784. }
  785. break;
  786. case UA_PUBSUBSTATE_PAUSED:
  787. switch (dataSetWriter->state){
  788. case UA_PUBSUBSTATE_DISABLED:
  789. break;
  790. case UA_PUBSUBSTATE_PAUSED:
  791. return UA_STATUSCODE_GOOD;
  792. case UA_PUBSUBSTATE_OPERATIONAL:
  793. break;
  794. case UA_PUBSUBSTATE_ERROR:
  795. break;
  796. default:
  797. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  798. "Received unknown PubSub state!");
  799. }
  800. break;
  801. case UA_PUBSUBSTATE_OPERATIONAL:
  802. switch (dataSetWriter->state){
  803. case UA_PUBSUBSTATE_DISABLED:
  804. dataSetWriter->state = UA_PUBSUBSTATE_OPERATIONAL;
  805. break;
  806. case UA_PUBSUBSTATE_PAUSED:
  807. break;
  808. case UA_PUBSUBSTATE_OPERATIONAL:
  809. return UA_STATUSCODE_GOOD;
  810. case UA_PUBSUBSTATE_ERROR:
  811. break;
  812. default:
  813. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  814. "Received unknown PubSub state!");
  815. }
  816. break;
  817. case UA_PUBSUBSTATE_ERROR:
  818. switch (dataSetWriter->state){
  819. case UA_PUBSUBSTATE_DISABLED:
  820. break;
  821. case UA_PUBSUBSTATE_PAUSED:
  822. break;
  823. case UA_PUBSUBSTATE_OPERATIONAL:
  824. break;
  825. case UA_PUBSUBSTATE_ERROR:
  826. return UA_STATUSCODE_GOOD;
  827. default:
  828. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  829. "Received unknown PubSub state!");
  830. }
  831. break;
  832. default:
  833. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  834. "Received unknown PubSub state!");
  835. }
  836. return UA_STATUSCODE_GOOD;
  837. }
  838. /**********************************************/
  839. /* WriterGroup */
  840. /**********************************************/
  841. UA_StatusCode
  842. UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src,
  843. UA_WriterGroupConfig *dst){
  844. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  845. memcpy(dst, src, sizeof(UA_WriterGroupConfig));
  846. retVal |= UA_String_copy(&src->name, &dst->name);
  847. retVal |= UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings);
  848. retVal |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings);
  849. if (src->groupPropertiesSize > 0) {
  850. dst->groupProperties = (UA_KeyValuePair *) UA_calloc(src->groupPropertiesSize, sizeof(UA_KeyValuePair));
  851. if(!dst->groupProperties)
  852. return UA_STATUSCODE_BADOUTOFMEMORY;
  853. for(size_t i = 0; i < src->groupPropertiesSize; i++){
  854. retVal |= UA_KeyValuePair_copy(&src->groupProperties[i], &dst->groupProperties[i]);
  855. }
  856. }
  857. return retVal;
  858. }
  859. UA_StatusCode
  860. UA_Server_getWriterGroupConfig(UA_Server *server, const UA_NodeId writerGroup,
  861. UA_WriterGroupConfig *config){
  862. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  863. if(!config)
  864. return UA_STATUSCODE_BADINVALIDARGUMENT;
  865. UA_WriterGroup *currentWriterGroup = UA_WriterGroup_findWGbyId(server, writerGroup);
  866. if(!currentWriterGroup){
  867. return UA_STATUSCODE_BADNOTFOUND;
  868. }
  869. UA_WriterGroupConfig tmpWriterGroupConfig;
  870. //deep copy of the actual config
  871. retVal |= UA_WriterGroupConfig_copy(&currentWriterGroup->config, &tmpWriterGroupConfig);
  872. *config = tmpWriterGroupConfig;
  873. return retVal;
  874. }
  875. UA_StatusCode
  876. UA_Server_updateWriterGroupConfig(UA_Server *server, UA_NodeId writerGroupIdentifier,
  877. const UA_WriterGroupConfig *config){
  878. if(!config)
  879. return UA_STATUSCODE_BADINVALIDARGUMENT;
  880. UA_WriterGroup *currentWriterGroup = UA_WriterGroup_findWGbyId(server, writerGroupIdentifier);
  881. if(!currentWriterGroup)
  882. return UA_STATUSCODE_BADNOTFOUND;
  883. if(currentWriterGroup->config.configurationFrozen){
  884. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  885. "Modify WriterGroup failed. WriterGroup is frozen.");
  886. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  887. }
  888. //The update functionality will be extended during the next PubSub batches.
  889. //Currently is only a change of the publishing interval possible.
  890. if(currentWriterGroup->config.maxEncapsulatedDataSetMessageCount != config->maxEncapsulatedDataSetMessageCount){
  891. currentWriterGroup->config.maxEncapsulatedDataSetMessageCount = config->maxEncapsulatedDataSetMessageCount;
  892. if(currentWriterGroup->config.messageSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
  893. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  894. "MaxEncapsulatedDataSetMessag need enabled 'PayloadHeader' within the message settings.");
  895. }
  896. }
  897. if(currentWriterGroup->config.publishingInterval != config->publishingInterval) {
  898. if(currentWriterGroup->config.rtLevel == UA_PUBSUB_RT_NONE && currentWriterGroup->state == UA_PUBSUBSTATE_OPERATIONAL){
  899. UA_PubSubManager_removeRepeatedPubSubCallback(server, currentWriterGroup->publishCallbackId);
  900. currentWriterGroup->config.publishingInterval = config->publishingInterval;
  901. UA_WriterGroup_addPublishCallback(server, currentWriterGroup);
  902. } else {
  903. currentWriterGroup->config.publishingInterval = config->publishingInterval;
  904. }
  905. }
  906. if(currentWriterGroup->config.priority != config->priority) {
  907. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  908. "No or unsupported WriterGroup update.");
  909. }
  910. return UA_STATUSCODE_GOOD;
  911. }
  912. UA_WriterGroup *
  913. UA_WriterGroup_findWGbyId(UA_Server *server, UA_NodeId identifier){
  914. for(size_t i = 0; i < server->pubSubManager.connectionsSize; i++){
  915. UA_WriterGroup *tmpWriterGroup;
  916. LIST_FOREACH(tmpWriterGroup, &server->pubSubManager.connections[i].writerGroups, listEntry) {
  917. if(UA_NodeId_equal(&identifier, &tmpWriterGroup->identifier)){
  918. return tmpWriterGroup;
  919. }
  920. }
  921. }
  922. return NULL;
  923. }
  924. void
  925. UA_WriterGroupConfig_clear(UA_WriterGroupConfig *writerGroupConfig){
  926. //delete writerGroup config
  927. UA_String_clear(&writerGroupConfig->name);
  928. UA_ExtensionObject_clear(&writerGroupConfig->transportSettings);
  929. UA_ExtensionObject_clear(&writerGroupConfig->messageSettings);
  930. for(size_t i = 0; i < writerGroupConfig->groupPropertiesSize; i++){
  931. UA_KeyValuePair_clear(&writerGroupConfig->groupProperties[i]);
  932. }
  933. UA_free(writerGroupConfig->groupProperties);
  934. }
  935. static void
  936. UA_WriterGroup_clear(UA_Server *server, UA_WriterGroup *writerGroup) {
  937. UA_WriterGroupConfig_clear(&writerGroup->config);
  938. //delete WriterGroup
  939. //delete all writers. Therefore removeDataSetWriter is called from PublishedDataSet
  940. UA_DataSetWriter *dataSetWriter, *tmpDataSetWriter;
  941. LIST_FOREACH_SAFE(dataSetWriter, &writerGroup->writers, listEntry, tmpDataSetWriter){
  942. UA_Server_removeDataSetWriter(server, dataSetWriter->identifier);
  943. }
  944. if(writerGroup->bufferedMessage.offsetsSize > 0){
  945. for (size_t i = 0; i < writerGroup->bufferedMessage.offsetsSize; i++) {
  946. if(writerGroup->bufferedMessage.offsets[i].contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT){
  947. UA_DataValue_delete(writerGroup->bufferedMessage.offsets[i].offsetData.value.value);
  948. }
  949. }
  950. UA_ByteString_deleteMembers(&writerGroup->bufferedMessage.buffer);
  951. UA_free(writerGroup->bufferedMessage.offsets);
  952. }
  953. UA_NodeId_clear(&writerGroup->linkedConnection);
  954. UA_NodeId_clear(&writerGroup->identifier);
  955. }
  956. UA_StatusCode
  957. UA_WriterGroup_setPubSubState(UA_Server *server, UA_PubSubState state, UA_WriterGroup *writerGroup){
  958. UA_DataSetWriter *dataSetWriter;
  959. switch(state){
  960. case UA_PUBSUBSTATE_DISABLED:
  961. switch (writerGroup->state){
  962. case UA_PUBSUBSTATE_DISABLED:
  963. return UA_STATUSCODE_GOOD;
  964. case UA_PUBSUBSTATE_PAUSED:
  965. break;
  966. case UA_PUBSUBSTATE_OPERATIONAL:
  967. UA_PubSubManager_removeRepeatedPubSubCallback(server, writerGroup->publishCallbackId);
  968. LIST_FOREACH(dataSetWriter, &writerGroup->writers, listEntry){
  969. UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, dataSetWriter);
  970. }
  971. writerGroup->state = UA_PUBSUBSTATE_DISABLED;
  972. break;
  973. case UA_PUBSUBSTATE_ERROR:
  974. break;
  975. default:
  976. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  977. "Received unknown PubSub state!");
  978. }
  979. break;
  980. case UA_PUBSUBSTATE_PAUSED:
  981. switch (writerGroup->state){
  982. case UA_PUBSUBSTATE_DISABLED:
  983. break;
  984. case UA_PUBSUBSTATE_PAUSED:
  985. return UA_STATUSCODE_GOOD;
  986. case UA_PUBSUBSTATE_OPERATIONAL:
  987. break;
  988. case UA_PUBSUBSTATE_ERROR:
  989. break;
  990. default:
  991. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  992. "Received unknown PubSub state!");
  993. }
  994. break;
  995. case UA_PUBSUBSTATE_OPERATIONAL:
  996. switch (writerGroup->state){
  997. case UA_PUBSUBSTATE_DISABLED:
  998. writerGroup->state = UA_PUBSUBSTATE_OPERATIONAL;
  999. UA_PubSubManager_removeRepeatedPubSubCallback(server, writerGroup->publishCallbackId);
  1000. LIST_FOREACH(dataSetWriter, &writerGroup->writers, listEntry){
  1001. UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, dataSetWriter);
  1002. }
  1003. UA_WriterGroup_addPublishCallback(server, writerGroup);
  1004. break;
  1005. case UA_PUBSUBSTATE_PAUSED:
  1006. break;
  1007. case UA_PUBSUBSTATE_OPERATIONAL:
  1008. return UA_STATUSCODE_GOOD;
  1009. case UA_PUBSUBSTATE_ERROR:
  1010. break;
  1011. default:
  1012. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1013. "Received unknown PubSub state!");
  1014. }
  1015. break;
  1016. case UA_PUBSUBSTATE_ERROR:
  1017. switch (writerGroup->state){
  1018. case UA_PUBSUBSTATE_DISABLED:
  1019. break;
  1020. case UA_PUBSUBSTATE_PAUSED:
  1021. break;
  1022. case UA_PUBSUBSTATE_OPERATIONAL:
  1023. break;
  1024. case UA_PUBSUBSTATE_ERROR:
  1025. return UA_STATUSCODE_GOOD;
  1026. default:
  1027. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1028. "Received unknown PubSub state!");
  1029. }
  1030. break;
  1031. default:
  1032. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1033. "Received unknown PubSub state!");
  1034. }
  1035. return UA_STATUSCODE_GOOD;
  1036. }
  1037. UA_StatusCode
  1038. UA_Server_addDataSetWriter(UA_Server *server,
  1039. const UA_NodeId writerGroup, const UA_NodeId dataSet,
  1040. const UA_DataSetWriterConfig *dataSetWriterConfig,
  1041. UA_NodeId *writerIdentifier) {
  1042. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  1043. if(!dataSetWriterConfig)
  1044. return UA_STATUSCODE_BADINVALIDARGUMENT;
  1045. UA_PublishedDataSet *currentDataSetContext = UA_PublishedDataSet_findPDSbyId(server, dataSet);
  1046. if(!currentDataSetContext)
  1047. return UA_STATUSCODE_BADNOTFOUND;
  1048. if(currentDataSetContext->config.configurationFrozen){
  1049. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1050. "Adding DataSetWriter failed. PublishedDataSet is frozen.");
  1051. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1052. }
  1053. UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
  1054. if(!wg)
  1055. return UA_STATUSCODE_BADNOTFOUND;
  1056. if(wg->config.configurationFrozen){
  1057. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1058. "Adding DataSetWriter failed. WriterGroup is frozen.");
  1059. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1060. }
  1061. if(wg->config.rtLevel != UA_PUBSUB_RT_NONE){
  1062. UA_DataSetField *tmpDSF;
  1063. TAILQ_FOREACH(tmpDSF, &currentDataSetContext->fields, listEntry){
  1064. if(tmpDSF->config.field.variable.staticValueSourceEnabled != UA_TRUE){
  1065. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1066. "Adding DataSetWriter failed. Fields in PDS are not RT capable.");
  1067. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1068. }
  1069. }
  1070. }
  1071. UA_DataSetWriter *newDataSetWriter = (UA_DataSetWriter *) UA_calloc(1, sizeof(UA_DataSetWriter));
  1072. if(!newDataSetWriter)
  1073. return UA_STATUSCODE_BADOUTOFMEMORY;
  1074. //copy the config into the new dataSetWriter
  1075. UA_DataSetWriterConfig tmpDataSetWriterConfig;
  1076. retVal |= UA_DataSetWriterConfig_copy(dataSetWriterConfig, &tmpDataSetWriterConfig);
  1077. newDataSetWriter->config = tmpDataSetWriterConfig;
  1078. //save the current version of the connected PublishedDataSet
  1079. newDataSetWriter->connectedDataSetVersion = currentDataSetContext->dataSetMetaData.configurationVersion;
  1080. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1081. //initialize the queue for the last values
  1082. if (currentDataSetContext->fieldSize > 0) {
  1083. newDataSetWriter->lastSamples = (UA_DataSetWriterSample * )
  1084. UA_calloc(currentDataSetContext->fieldSize, sizeof(UA_DataSetWriterSample));
  1085. if(!newDataSetWriter->lastSamples) {
  1086. UA_DataSetWriterConfig_clear(&newDataSetWriter->config);
  1087. UA_free(newDataSetWriter);
  1088. return UA_STATUSCODE_BADOUTOFMEMORY;
  1089. }
  1090. newDataSetWriter->lastSamplesCount = currentDataSetContext->fieldSize;
  1091. }
  1092. #endif
  1093. //connect PublishedDataSet with DataSetWriter
  1094. newDataSetWriter->connectedDataSet = currentDataSetContext->identifier;
  1095. newDataSetWriter->linkedWriterGroup = wg->identifier;
  1096. UA_PubSubManager_generateUniqueNodeId(server, &newDataSetWriter->identifier);
  1097. if(writerIdentifier != NULL)
  1098. UA_NodeId_copy(&newDataSetWriter->identifier, writerIdentifier);
  1099. //add the new writer to the group
  1100. LIST_INSERT_HEAD(&wg->writers, newDataSetWriter, listEntry);
  1101. wg->writersCount++;
  1102. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  1103. addDataSetWriterRepresentation(server, newDataSetWriter);
  1104. #endif
  1105. return retVal;
  1106. }
  1107. UA_StatusCode
  1108. UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw){
  1109. UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_findDSWbyId(server, dsw);
  1110. if(!dataSetWriter)
  1111. return UA_STATUSCODE_BADNOTFOUND;
  1112. if(dataSetWriter->config.configurationFrozen){
  1113. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1114. "Remove DataSetWriter failed. DataSetWriter is frozen.");
  1115. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1116. }
  1117. UA_WriterGroup *linkedWriterGroup = UA_WriterGroup_findWGbyId(server, dataSetWriter->linkedWriterGroup);
  1118. if(!linkedWriterGroup)
  1119. return UA_STATUSCODE_BADNOTFOUND;
  1120. if(linkedWriterGroup->config.configurationFrozen){
  1121. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1122. "Remove DataSetWriter failed. WriterGroup is frozen.");
  1123. return UA_STATUSCODE_BADCONFIGURATIONERROR;
  1124. }
  1125. UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  1126. if(!publishedDataSet)
  1127. return UA_STATUSCODE_BADNOTFOUND;
  1128. linkedWriterGroup->writersCount--;
  1129. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  1130. removeDataSetWriterRepresentation(server, dataSetWriter);
  1131. #endif
  1132. //remove DataSetWriter from group
  1133. UA_DataSetWriter_clear(server, dataSetWriter);
  1134. LIST_REMOVE(dataSetWriter, listEntry);
  1135. UA_free(dataSetWriter);
  1136. return UA_STATUSCODE_GOOD;
  1137. }
  1138. /**********************************************/
  1139. /* DataSetField */
  1140. /**********************************************/
  1141. UA_StatusCode
  1142. UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src, UA_DataSetFieldConfig *dst){
  1143. memcpy(dst, src, sizeof(UA_DataSetFieldConfig));
  1144. if(src->dataSetFieldType == UA_PUBSUB_DATASETFIELD_VARIABLE) {
  1145. UA_String_copy(&src->field.variable.fieldNameAlias, &dst->field.variable.fieldNameAlias);
  1146. UA_PublishedVariableDataType_copy(&src->field.variable.publishParameters,
  1147. &dst->field.variable.publishParameters);
  1148. } else {
  1149. return UA_STATUSCODE_BADNOTSUPPORTED;
  1150. }
  1151. return UA_STATUSCODE_GOOD;
  1152. }
  1153. UA_StatusCode
  1154. UA_Server_getDataSetFieldConfig(UA_Server *server, const UA_NodeId dsf,
  1155. UA_DataSetFieldConfig *config) {
  1156. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  1157. if(!config)
  1158. return UA_STATUSCODE_BADINVALIDARGUMENT;
  1159. UA_DataSetField *currentDataSetField = UA_DataSetField_findDSFbyId(server, dsf);
  1160. if(!currentDataSetField)
  1161. return UA_STATUSCODE_BADNOTFOUND;
  1162. UA_DataSetFieldConfig tmpFieldConfig;
  1163. //deep copy of the actual config
  1164. retVal |= UA_DataSetFieldConfig_copy(&currentDataSetField->config, &tmpFieldConfig);
  1165. *config = tmpFieldConfig;
  1166. return retVal;
  1167. }
  1168. UA_DataSetField *
  1169. UA_DataSetField_findDSFbyId(UA_Server *server, UA_NodeId identifier) {
  1170. for(size_t i = 0; i < server->pubSubManager.publishedDataSetsSize; i++){
  1171. UA_DataSetField *tmpField;
  1172. TAILQ_FOREACH(tmpField, &server->pubSubManager.publishedDataSets[i].fields, listEntry){
  1173. if(UA_NodeId_equal(&tmpField->identifier, &identifier)){
  1174. return tmpField;
  1175. }
  1176. }
  1177. }
  1178. return NULL;
  1179. }
  1180. void
  1181. UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig *dataSetFieldConfig){
  1182. if(dataSetFieldConfig->dataSetFieldType == UA_PUBSUB_DATASETFIELD_VARIABLE){
  1183. UA_String_clear(&dataSetFieldConfig->field.variable.fieldNameAlias);
  1184. UA_PublishedVariableDataType_clear(&dataSetFieldConfig->field.variable.publishParameters);
  1185. }
  1186. }
  1187. static void
  1188. UA_DataSetField_clear(UA_DataSetField *field) {
  1189. UA_DataSetFieldConfig_clear(&field->config);
  1190. //delete DataSetField
  1191. UA_NodeId_clear(&field->identifier);
  1192. UA_NodeId_clear(&field->publishedDataSet);
  1193. UA_FieldMetaData_clear(&field->fieldMetaData);
  1194. }
  1195. /*********************************************************/
  1196. /* PublishValues handling */
  1197. /*********************************************************/
  1198. /**
  1199. * Compare two variants. Internally used for value change detection.
  1200. *
  1201. * @return true if the value has changed
  1202. */
  1203. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1204. static UA_Boolean
  1205. valueChangedVariant(UA_Variant *oldValue, UA_Variant *newValue){
  1206. if(! (oldValue && newValue))
  1207. return false;
  1208. UA_ByteString *oldValueEncoding = UA_ByteString_new(), *newValueEncoding = UA_ByteString_new();
  1209. size_t oldValueEncodingSize, newValueEncodingSize;
  1210. oldValueEncodingSize = UA_calcSizeBinary(oldValue, &UA_TYPES[UA_TYPES_VARIANT]);
  1211. newValueEncodingSize = UA_calcSizeBinary(newValue, &UA_TYPES[UA_TYPES_VARIANT]);
  1212. if((oldValueEncodingSize == 0) || (newValueEncodingSize == 0))
  1213. return false;
  1214. if(oldValueEncodingSize != newValueEncodingSize)
  1215. return true;
  1216. if(UA_ByteString_allocBuffer(oldValueEncoding, oldValueEncodingSize) != UA_STATUSCODE_GOOD)
  1217. return false;
  1218. if(UA_ByteString_allocBuffer(newValueEncoding, newValueEncodingSize) != UA_STATUSCODE_GOOD)
  1219. return false;
  1220. UA_Byte *bufPosOldValue = oldValueEncoding->data;
  1221. const UA_Byte *bufEndOldValue = &oldValueEncoding->data[oldValueEncoding->length];
  1222. UA_Byte *bufPosNewValue = newValueEncoding->data;
  1223. const UA_Byte *bufEndNewValue = &newValueEncoding->data[newValueEncoding->length];
  1224. if(UA_encodeBinary(oldValue, &UA_TYPES[UA_TYPES_VARIANT],
  1225. &bufPosOldValue, &bufEndOldValue, NULL, NULL) != UA_STATUSCODE_GOOD){
  1226. return false;
  1227. }
  1228. if(UA_encodeBinary(newValue, &UA_TYPES[UA_TYPES_VARIANT],
  1229. &bufPosNewValue, &bufEndNewValue, NULL, NULL) != UA_STATUSCODE_GOOD){
  1230. return false;
  1231. }
  1232. oldValueEncoding->length = (uintptr_t)bufPosOldValue - (uintptr_t)oldValueEncoding->data;
  1233. newValueEncoding->length = (uintptr_t)bufPosNewValue - (uintptr_t)newValueEncoding->data;
  1234. UA_Boolean compareResult = !UA_ByteString_equal(oldValueEncoding, newValueEncoding);
  1235. UA_ByteString_delete(oldValueEncoding);
  1236. UA_ByteString_delete(newValueEncoding);
  1237. return compareResult;
  1238. }
  1239. #endif
  1240. /**
  1241. * Obtain the latest value for a specific DataSetField. This method is currently
  1242. * called inside the DataSetMessage generation process.
  1243. */
  1244. static void
  1245. UA_PubSubDataSetField_sampleValue(UA_Server *server, UA_DataSetField *field,
  1246. UA_DataValue *value) {
  1247. /* Read the value */
  1248. if(field->config.field.variable.staticValueSourceEnabled == UA_FALSE){
  1249. UA_ReadValueId rvid;
  1250. UA_ReadValueId_init(&rvid);
  1251. rvid.nodeId = field->config.field.variable.publishParameters.publishedVariable;
  1252. rvid.attributeId = field->config.field.variable.publishParameters.attributeId;
  1253. rvid.indexRange = field->config.field.variable.publishParameters.indexRange;
  1254. *value = UA_Server_read(server, &rvid, UA_TIMESTAMPSTORETURN_BOTH);
  1255. } else {
  1256. value->value.storageType = UA_VARIANT_DATA_NODELETE;
  1257. *value = field->config.field.variable.staticValueSource;
  1258. }
  1259. }
  1260. static UA_StatusCode
  1261. UA_PubSubDataSetWriter_generateKeyFrameMessage(UA_Server *server, UA_DataSetMessage *dataSetMessage,
  1262. UA_DataSetWriter *dataSetWriter) {
  1263. UA_PublishedDataSet *currentDataSet =
  1264. UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  1265. if(!currentDataSet)
  1266. return UA_STATUSCODE_BADNOTFOUND;
  1267. /* Prepare DataSetMessageContent */
  1268. dataSetMessage->header.dataSetMessageValid = true;
  1269. dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
  1270. dataSetMessage->data.keyFrameData.fieldCount = currentDataSet->fieldSize;
  1271. dataSetMessage->data.keyFrameData.dataSetFields = (UA_DataValue *)
  1272. UA_Array_new(currentDataSet->fieldSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
  1273. if(!dataSetMessage->data.keyFrameData.dataSetFields)
  1274. return UA_STATUSCODE_BADOUTOFMEMORY;
  1275. #ifdef UA_ENABLE_JSON_ENCODING
  1276. /* json: insert fieldnames used as json keys */
  1277. dataSetMessage->data.keyFrameData.fieldNames =
  1278. (UA_String *)UA_Array_new(currentDataSet->fieldSize, &UA_TYPES[UA_TYPES_STRING]);
  1279. if(!dataSetMessage->data.keyFrameData.fieldNames)
  1280. return UA_STATUSCODE_BADOUTOFMEMORY;
  1281. #endif
  1282. /* Loop over the fields */
  1283. size_t counter = 0;
  1284. UA_DataSetField *dsf;
  1285. TAILQ_FOREACH(dsf, &currentDataSet->fields, listEntry) {
  1286. #ifdef UA_ENABLE_JSON_ENCODING
  1287. /* json: store the fieldNameAlias*/
  1288. UA_String_copy(&dsf->config.field.variable.fieldNameAlias,
  1289. &dataSetMessage->data.keyFrameData.fieldNames[counter]);
  1290. #endif
  1291. /* Sample the value */
  1292. UA_DataValue *dfv = &dataSetMessage->data.keyFrameData.dataSetFields[counter];
  1293. UA_PubSubDataSetField_sampleValue(server, dsf, dfv);
  1294. /* Deactivate statuscode? */
  1295. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
  1296. dfv->hasStatus = false;
  1297. /* Deactivate timestamps */
  1298. if(((u64)dataSetWriter->config.dataSetFieldContentMask &
  1299. (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
  1300. dfv->hasSourceTimestamp = false;
  1301. if(((u64)dataSetWriter->config.dataSetFieldContentMask &
  1302. (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
  1303. dfv->hasSourcePicoseconds = false;
  1304. if(((u64)dataSetWriter->config.dataSetFieldContentMask &
  1305. (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
  1306. dfv->hasServerTimestamp = false;
  1307. if(((u64)dataSetWriter->config.dataSetFieldContentMask &
  1308. (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
  1309. dfv->hasServerPicoseconds = false;
  1310. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1311. /* Update lastValue store */
  1312. UA_DataValue_clear(&dataSetWriter->lastSamples[counter].value);
  1313. UA_DataValue_copy(dfv, &dataSetWriter->lastSamples[counter].value);
  1314. #endif
  1315. counter++;
  1316. }
  1317. return UA_STATUSCODE_GOOD;
  1318. }
  1319. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1320. static UA_StatusCode
  1321. UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_Server *server,
  1322. UA_DataSetMessage *dataSetMessage,
  1323. UA_DataSetWriter *dataSetWriter) {
  1324. UA_PublishedDataSet *currentDataSet =
  1325. UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  1326. if(!currentDataSet)
  1327. return UA_STATUSCODE_BADNOTFOUND;
  1328. /* Prepare DataSetMessageContent */
  1329. memset(dataSetMessage, 0, sizeof(UA_DataSetMessage));
  1330. dataSetMessage->header.dataSetMessageValid = true;
  1331. dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATADELTAFRAME;
  1332. if (currentDataSet->fieldSize == 0) {
  1333. return UA_STATUSCODE_GOOD;
  1334. }
  1335. UA_DataSetField *dsf;
  1336. size_t counter = 0;
  1337. TAILQ_FOREACH(dsf, &currentDataSet->fields, listEntry) {
  1338. /* Sample the value */
  1339. UA_DataValue value;
  1340. UA_DataValue_init(&value);
  1341. UA_PubSubDataSetField_sampleValue(server, dsf, &value);
  1342. /* Check if the value has changed */
  1343. if(valueChangedVariant(&dataSetWriter->lastSamples[counter].value.value, &value.value)) {
  1344. /* increase fieldCount for current delta message */
  1345. dataSetMessage->data.deltaFrameData.fieldCount++;
  1346. dataSetWriter->lastSamples[counter].valueChanged = true;
  1347. /* Update last stored sample */
  1348. UA_DataValue_clear(&dataSetWriter->lastSamples[counter].value);
  1349. dataSetWriter->lastSamples[counter].value = value;
  1350. } else {
  1351. UA_DataValue_clear(&value);
  1352. dataSetWriter->lastSamples[counter].valueChanged = false;
  1353. }
  1354. counter++;
  1355. }
  1356. /* Allocate DeltaFrameFields */
  1357. UA_DataSetMessage_DeltaFrameField *deltaFields = (UA_DataSetMessage_DeltaFrameField *)
  1358. UA_calloc(dataSetMessage->data.deltaFrameData.fieldCount, sizeof(UA_DataSetMessage_DeltaFrameField));
  1359. if(!deltaFields)
  1360. return UA_STATUSCODE_BADOUTOFMEMORY;
  1361. dataSetMessage->data.deltaFrameData.deltaFrameFields = deltaFields;
  1362. size_t currentDeltaField = 0;
  1363. for(size_t i = 0; i < currentDataSet->fieldSize; i++) {
  1364. if(!dataSetWriter->lastSamples[i].valueChanged)
  1365. continue;
  1366. UA_DataSetMessage_DeltaFrameField *dff = &deltaFields[currentDeltaField];
  1367. dff->fieldIndex = (UA_UInt16) i;
  1368. UA_DataValue_copy(&dataSetWriter->lastSamples[i].value, &dff->fieldValue);
  1369. dataSetWriter->lastSamples[i].valueChanged = false;
  1370. /* Deactivate statuscode? */
  1371. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
  1372. dff->fieldValue.hasStatus = false;
  1373. /* Deactivate timestamps? */
  1374. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
  1375. dff->fieldValue.hasSourceTimestamp = false;
  1376. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
  1377. dff->fieldValue.hasServerPicoseconds = false;
  1378. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
  1379. dff->fieldValue.hasServerTimestamp = false;
  1380. if(((u64)dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
  1381. dff->fieldValue.hasServerPicoseconds = false;
  1382. currentDeltaField++;
  1383. }
  1384. return UA_STATUSCODE_GOOD;
  1385. }
  1386. #endif
  1387. /**
  1388. * Generate a DataSetMessage for the given writer.
  1389. *
  1390. * @param dataSetWriter ptr to corresponding writer
  1391. * @return ptr to generated DataSetMessage
  1392. */
  1393. static UA_StatusCode
  1394. UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *dataSetMessage,
  1395. UA_DataSetWriter *dataSetWriter) {
  1396. UA_PublishedDataSet *currentDataSet =
  1397. UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
  1398. if(!currentDataSet)
  1399. return UA_STATUSCODE_BADNOTFOUND;
  1400. /* Reset the message */
  1401. memset(dataSetMessage, 0, sizeof(UA_DataSetMessage));
  1402. /* store messageType to switch between json or uadp (default) */
  1403. UA_UInt16 messageType = UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE;
  1404. UA_JsonDataSetWriterMessageDataType *jsonDataSetWriterMessageDataType = NULL;
  1405. /* The configuration Flags are included
  1406. * inside the std. defined UA_UadpDataSetWriterMessageDataType */
  1407. UA_UadpDataSetWriterMessageDataType defaultUadpConfiguration;
  1408. UA_UadpDataSetWriterMessageDataType *dataSetWriterMessageDataType = NULL;
  1409. if((dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED ||
  1410. dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
  1411. (dataSetWriter->config.messageSettings.content.decoded.type ==
  1412. &UA_TYPES[UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE])) {
  1413. dataSetWriterMessageDataType = (UA_UadpDataSetWriterMessageDataType *)
  1414. dataSetWriter->config.messageSettings.content.decoded.data;
  1415. /* type is UADP */
  1416. messageType = UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE;
  1417. } else if((dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED ||
  1418. dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
  1419. (dataSetWriter->config.messageSettings.content.decoded.type ==
  1420. &UA_TYPES[UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE])) {
  1421. jsonDataSetWriterMessageDataType = (UA_JsonDataSetWriterMessageDataType *)
  1422. dataSetWriter->config.messageSettings.content.decoded.data;
  1423. /* type is JSON */
  1424. messageType = UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE;
  1425. } else {
  1426. /* create default flag configuration if no
  1427. * UadpDataSetWriterMessageDataType was passed in */
  1428. memset(&defaultUadpConfiguration, 0, sizeof(UA_UadpDataSetWriterMessageDataType));
  1429. defaultUadpConfiguration.dataSetMessageContentMask = (UA_UadpDataSetMessageContentMask)
  1430. ((u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP | (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION |
  1431. (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION);
  1432. dataSetWriterMessageDataType = &defaultUadpConfiguration;
  1433. }
  1434. /* Sanity-test the configuration */
  1435. if(dataSetWriterMessageDataType &&
  1436. (dataSetWriterMessageDataType->networkMessageNumber != 0 ||
  1437. dataSetWriterMessageDataType->dataSetOffset != 0 ||
  1438. dataSetWriterMessageDataType->configuredSize != 0)) {
  1439. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1440. "Static DSM configuration not supported. Using defaults");
  1441. dataSetWriterMessageDataType->networkMessageNumber = 0;
  1442. dataSetWriterMessageDataType->dataSetOffset = 0;
  1443. dataSetWriterMessageDataType->configuredSize = 0;
  1444. }
  1445. /* The field encoding depends on the flags inside the writer config.
  1446. * TODO: This can be moved to the encoding layer. */
  1447. if(dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_RAWDATA
  1448. ) {
  1449. dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_RAWDATA;
  1450. } else if((u64)dataSetWriter->config.dataSetFieldContentMask &
  1451. ((u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP | (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS |
  1452. (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS | (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE)) {
  1453. dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
  1454. } else {
  1455. dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
  1456. }
  1457. if(messageType == UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE) {
  1458. /* Std: 'The DataSetMessageContentMask defines the flags for the content of the DataSetMessage header.' */
  1459. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1460. (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION) {
  1461. dataSetMessage->header.configVersionMajorVersionEnabled = true;
  1462. dataSetMessage->header.configVersionMajorVersion =
  1463. currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
  1464. }
  1465. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1466. (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION) {
  1467. dataSetMessage->header.configVersionMinorVersionEnabled = true;
  1468. dataSetMessage->header.configVersionMinorVersion =
  1469. currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
  1470. }
  1471. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1472. (u64)UA_UADPDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
  1473. dataSetMessage->header.dataSetMessageSequenceNrEnabled = true;
  1474. dataSetMessage->header.dataSetMessageSequenceNr =
  1475. dataSetWriter->actualDataSetMessageSequenceCount;
  1476. }
  1477. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1478. (u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP) {
  1479. dataSetMessage->header.timestampEnabled = true;
  1480. dataSetMessage->header.timestamp = UA_DateTime_now();
  1481. }
  1482. /* TODO: Picoseconds resolution not supported atm */
  1483. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1484. (u64)UA_UADPDATASETMESSAGECONTENTMASK_PICOSECONDS) {
  1485. dataSetMessage->header.picoSecondsIncluded = false;
  1486. }
  1487. /* TODO: Statuscode not supported yet */
  1488. if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask &
  1489. (u64)UA_UADPDATASETMESSAGECONTENTMASK_STATUS) {
  1490. dataSetMessage->header.statusEnabled = false;
  1491. }
  1492. } else if(messageType == UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE) {
  1493. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1494. (u64)UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION) {
  1495. dataSetMessage->header.configVersionMajorVersionEnabled = true;
  1496. dataSetMessage->header.configVersionMajorVersion =
  1497. currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
  1498. }
  1499. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1500. (u64)UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION) {
  1501. dataSetMessage->header.configVersionMinorVersionEnabled = true;
  1502. dataSetMessage->header.configVersionMinorVersion =
  1503. currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
  1504. }
  1505. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1506. (u64)UA_JSONDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
  1507. dataSetMessage->header.dataSetMessageSequenceNrEnabled = true;
  1508. dataSetMessage->header.dataSetMessageSequenceNr =
  1509. dataSetWriter->actualDataSetMessageSequenceCount;
  1510. }
  1511. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1512. (u64)UA_JSONDATASETMESSAGECONTENTMASK_TIMESTAMP) {
  1513. dataSetMessage->header.timestampEnabled = true;
  1514. dataSetMessage->header.timestamp = UA_DateTime_now();
  1515. }
  1516. /* TODO: Statuscode not supported yet */
  1517. if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask &
  1518. (u64)UA_JSONDATASETMESSAGECONTENTMASK_STATUS) {
  1519. dataSetMessage->header.statusEnabled = false;
  1520. }
  1521. }
  1522. /* Set the sequence count. Automatically rolls over to zero */
  1523. dataSetWriter->actualDataSetMessageSequenceCount++;
  1524. /* JSON does not differ between deltaframes and keyframes, only keyframes are currently used. */
  1525. if(messageType != UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE){
  1526. #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES
  1527. /* Check if the PublishedDataSet version has changed -> if yes flush the lastValue store and send a KeyFrame */
  1528. if(dataSetWriter->connectedDataSetVersion.majorVersion != currentDataSet->dataSetMetaData.configurationVersion.majorVersion ||
  1529. dataSetWriter->connectedDataSetVersion.minorVersion != currentDataSet->dataSetMetaData.configurationVersion.minorVersion) {
  1530. /* Remove old samples */
  1531. for(size_t i = 0; i < dataSetWriter->lastSamplesCount; i++)
  1532. UA_DataValue_clear(&dataSetWriter->lastSamples[i].value);
  1533. /* Realloc pds dependent memory */
  1534. dataSetWriter->lastSamplesCount = currentDataSet->fieldSize;
  1535. UA_DataSetWriterSample *newSamplesArray = (UA_DataSetWriterSample * )
  1536. UA_realloc(dataSetWriter->lastSamples, sizeof(UA_DataSetWriterSample) * dataSetWriter->lastSamplesCount);
  1537. if(!newSamplesArray)
  1538. return UA_STATUSCODE_BADOUTOFMEMORY;
  1539. dataSetWriter->lastSamples = newSamplesArray;
  1540. memset(dataSetWriter->lastSamples, 0, sizeof(UA_DataSetWriterSample) * dataSetWriter->lastSamplesCount);
  1541. dataSetWriter->connectedDataSetVersion = currentDataSet->dataSetMetaData.configurationVersion;
  1542. UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage, dataSetWriter);
  1543. dataSetWriter->deltaFrameCounter = 0;
  1544. return UA_STATUSCODE_GOOD;
  1545. }
  1546. /* The standard defines: if a PDS contains only one fields no delta messages
  1547. * should be generated because they need more memory than a keyframe with 1
  1548. * field. */
  1549. if(currentDataSet->fieldSize > 1 && dataSetWriter->deltaFrameCounter > 0 &&
  1550. dataSetWriter->deltaFrameCounter <= dataSetWriter->config.keyFrameCount) {
  1551. UA_PubSubDataSetWriter_generateDeltaFrameMessage(server, dataSetMessage, dataSetWriter);
  1552. dataSetWriter->deltaFrameCounter++;
  1553. return UA_STATUSCODE_GOOD;
  1554. }
  1555. dataSetWriter->deltaFrameCounter = 1;
  1556. #endif
  1557. }
  1558. UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage, dataSetWriter);
  1559. return UA_STATUSCODE_GOOD;
  1560. }
  1561. static UA_StatusCode
  1562. sendNetworkMessageJson(UA_PubSubConnection *connection, UA_DataSetMessage *dsm,
  1563. UA_UInt16 *writerIds, UA_Byte dsmCount, UA_ExtensionObject *transportSettings) {
  1564. UA_StatusCode retval = UA_STATUSCODE_BADNOTSUPPORTED;
  1565. #ifdef UA_ENABLE_JSON_ENCODING
  1566. UA_NetworkMessage nm;
  1567. memset(&nm, 0, sizeof(UA_NetworkMessage));
  1568. nm.version = 1;
  1569. nm.networkMessageType = UA_NETWORKMESSAGE_DATASET;
  1570. nm.payloadHeaderEnabled = true;
  1571. nm.payloadHeader.dataSetPayloadHeader.count = dsmCount;
  1572. nm.payloadHeader.dataSetPayloadHeader.dataSetWriterIds = writerIds;
  1573. nm.payload.dataSetPayload.dataSetMessages = dsm;
  1574. /* Allocate the buffer. Allocate on the stack if the buffer is small. */
  1575. UA_ByteString buf;
  1576. size_t msgSize = UA_NetworkMessage_calcSizeJson(&nm, NULL, 0, NULL, 0, true);
  1577. size_t stackSize = 1;
  1578. if(msgSize <= UA_MAX_STACKBUF)
  1579. stackSize = msgSize;
  1580. UA_STACKARRAY(UA_Byte, stackBuf, stackSize);
  1581. buf.data = stackBuf;
  1582. buf.length = msgSize;
  1583. if(msgSize > UA_MAX_STACKBUF) {
  1584. retval = UA_ByteString_allocBuffer(&buf, msgSize);
  1585. if(retval != UA_STATUSCODE_GOOD)
  1586. return retval;
  1587. }
  1588. /* Encode the message */
  1589. UA_Byte *bufPos = buf.data;
  1590. memset(bufPos, 0, msgSize);
  1591. const UA_Byte *bufEnd = &buf.data[buf.length];
  1592. retval = UA_NetworkMessage_encodeJson(&nm, &bufPos, &bufEnd, NULL, 0, NULL, 0, true);
  1593. if(retval != UA_STATUSCODE_GOOD) {
  1594. if(msgSize > UA_MAX_STACKBUF)
  1595. UA_ByteString_clear(&buf);
  1596. return retval;
  1597. }
  1598. /* Send the prepared messages */
  1599. retval = connection->channel->send(connection->channel, transportSettings, &buf);
  1600. if(msgSize > UA_MAX_STACKBUF)
  1601. UA_ByteString_clear(&buf);
  1602. #endif
  1603. return retval;
  1604. }
  1605. static UA_StatusCode
  1606. generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
  1607. UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount,
  1608. UA_ExtensionObject *messageSettings,
  1609. UA_ExtensionObject *transportSettings,
  1610. UA_NetworkMessage *networkMessage) {
  1611. if(messageSettings->content.decoded.type !=
  1612. &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
  1613. return UA_STATUSCODE_BADINTERNALERROR;
  1614. UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
  1615. messageSettings->content.decoded.data;
  1616. networkMessage->publisherIdEnabled =
  1617. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PUBLISHERID) != 0;
  1618. networkMessage->groupHeaderEnabled =
  1619. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPHEADER) != 0;
  1620. networkMessage->groupHeader.writerGroupIdEnabled =
  1621. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_WRITERGROUPID) != 0;
  1622. networkMessage->groupHeader.groupVersionEnabled =
  1623. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPVERSION) != 0;
  1624. networkMessage->groupHeader.networkMessageNumberEnabled =
  1625. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_NETWORKMESSAGENUMBER) != 0;
  1626. networkMessage->groupHeader.sequenceNumberEnabled =
  1627. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_SEQUENCENUMBER) != 0;
  1628. networkMessage->payloadHeaderEnabled =
  1629. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER) != 0;
  1630. networkMessage->timestampEnabled =
  1631. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_TIMESTAMP) != 0;
  1632. networkMessage->picosecondsEnabled =
  1633. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PICOSECONDS) != 0;
  1634. networkMessage->dataSetClassIdEnabled =
  1635. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_DATASETCLASSID) != 0;
  1636. networkMessage->promotedFieldsEnabled =
  1637. ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PROMOTEDFIELDS) != 0;
  1638. networkMessage->version = 1;
  1639. networkMessage->networkMessageType = UA_NETWORKMESSAGE_DATASET;
  1640. if(connection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_NUMERIC) {
  1641. networkMessage->publisherIdType = UA_PUBLISHERDATATYPE_UINT16;
  1642. networkMessage->publisherId.publisherIdUInt32 = connection->config->publisherId.numeric;
  1643. } else if(connection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING){
  1644. networkMessage->publisherIdType = UA_PUBLISHERDATATYPE_STRING;
  1645. networkMessage->publisherId.publisherIdString = connection->config->publisherId.string;
  1646. }
  1647. if(networkMessage->groupHeader.sequenceNumberEnabled)
  1648. networkMessage->groupHeader.sequenceNumber = wg->sequenceNumber;
  1649. /* Compute the length of the dsm separately for the header */
  1650. UA_STACKARRAY(UA_UInt16, dsmLengths, dsmCount);
  1651. for(UA_Byte i = 0; i < dsmCount; i++)
  1652. dsmLengths[i] = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&dsm[i], NULL, 0);
  1653. networkMessage->payloadHeader.dataSetPayloadHeader.count = dsmCount;
  1654. networkMessage->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = writerIds;
  1655. networkMessage->groupHeader.writerGroupId = wg->config.writerGroupId;
  1656. /* number of the NetworkMessage inside a PublishingInterval */
  1657. networkMessage->groupHeader.networkMessageNumber = 1;
  1658. networkMessage->payload.dataSetPayload.sizes = dsmLengths;
  1659. networkMessage->payload.dataSetPayload.dataSetMessages = dsm;
  1660. return UA_STATUSCODE_GOOD;
  1661. }
  1662. static UA_StatusCode
  1663. sendBufferedNetworkMessage(UA_Server *server, UA_PubSubConnection *connection,
  1664. UA_NetworkMessageOffsetBuffer *buffer, UA_ExtensionObject *transportSettings) {
  1665. if(UA_NetworkMessage_updateBufferedMessage(buffer) != UA_STATUSCODE_GOOD)
  1666. UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, "PubSub sending. Unknown field type.");
  1667. UA_StatusCode retval = connection->channel->send(connection->channel, transportSettings, &buffer->buffer);
  1668. return retval;
  1669. }
  1670. static UA_StatusCode
  1671. sendNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
  1672. UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount,
  1673. UA_ExtensionObject *messageSettings,
  1674. UA_ExtensionObject *transportSettings) {
  1675. UA_NetworkMessage nm;
  1676. memset(&nm, 0, sizeof(UA_NetworkMessage));
  1677. generateNetworkMessage(connection, wg, dsm, writerIds, dsmCount, messageSettings, transportSettings, &nm);
  1678. /* Allocate the buffer. Allocate on the stack if the buffer is small. */
  1679. UA_ByteString buf;
  1680. size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nm, NULL);
  1681. size_t stackSize = 1;
  1682. if(msgSize <= UA_MAX_STACKBUF)
  1683. stackSize = msgSize;
  1684. UA_STACKARRAY(UA_Byte, stackBuf, stackSize);
  1685. buf.data = stackBuf;
  1686. buf.length = msgSize;
  1687. UA_StatusCode retval;
  1688. if(msgSize > UA_MAX_STACKBUF) {
  1689. retval = UA_ByteString_allocBuffer(&buf, msgSize);
  1690. if(retval != UA_STATUSCODE_GOOD)
  1691. return retval;
  1692. }
  1693. /* Encode the message */
  1694. UA_Byte *bufPos = buf.data;
  1695. memset(bufPos, 0, msgSize);
  1696. const UA_Byte *bufEnd = &buf.data[buf.length];
  1697. retval = UA_NetworkMessage_encodeBinary(&nm, &bufPos, bufEnd);
  1698. if(retval != UA_STATUSCODE_GOOD) {
  1699. if(msgSize > UA_MAX_STACKBUF)
  1700. UA_ByteString_clear(&buf);
  1701. return retval;
  1702. }
  1703. /* Send the prepared messages */
  1704. retval = connection->channel->send(connection->channel, transportSettings, &buf);
  1705. if(msgSize > UA_MAX_STACKBUF)
  1706. UA_ByteString_clear(&buf);
  1707. return retval;
  1708. }
  1709. /* This callback triggers the collection and publish of NetworkMessages and the
  1710. * contained DataSetMessages. */
  1711. void
  1712. UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
  1713. UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, "Publish Callback");
  1714. if(!writerGroup) {
  1715. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1716. "Publish failed. WriterGroup not found");
  1717. return;
  1718. }
  1719. /* Nothing to do? */
  1720. if(writerGroup->writersCount <= 0)
  1721. return;
  1722. if(!writerGroup->linkedConnectionPtr){
  1723. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1724. "Publish failed: Invalid reference to PubSubConnection");
  1725. return;
  1726. }
  1727. /* Binary or Json encoding? */
  1728. if(writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP &&
  1729. writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_JSON) {
  1730. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1731. "Publish failed: Unknown encoding type.");
  1732. return;
  1733. }
  1734. /* Find the connection associated with the writer */
  1735. UA_PubSubConnection *connection = writerGroup->linkedConnectionPtr;
  1736. if(!connection) {
  1737. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1738. "Publish failed. PubSubConnection invalid.");
  1739. return;
  1740. }
  1741. if(writerGroup->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) {
  1742. sendBufferedNetworkMessage(server, connection, &writerGroup->bufferedMessage, &writerGroup->config.transportSettings);
  1743. writerGroup->sequenceNumber++;
  1744. return;
  1745. }
  1746. /* How many DSM can be sent in one NM? */
  1747. UA_Byte maxDSM = (UA_Byte)writerGroup->config.maxEncapsulatedDataSetMessageCount;
  1748. if(writerGroup->config.maxEncapsulatedDataSetMessageCount > UA_BYTE_MAX)
  1749. maxDSM = UA_BYTE_MAX;
  1750. /* If the maxEncapsulatedDataSetMessageCount is set to 0->1 */
  1751. if(maxDSM == 0)
  1752. maxDSM = 1;
  1753. /* It is possible to put several DataSetMessages into one NetworkMessage.
  1754. * But only if they do not contain promoted fields. NM with only DSM are
  1755. * sent out right away. The others are kept in a buffer for "batching". */
  1756. size_t dsmCount = 0;
  1757. UA_DataSetWriter *dsw;
  1758. UA_STACKARRAY(UA_UInt16, dsWriterIds, writerGroup->writersCount);
  1759. UA_STACKARRAY(UA_DataSetMessage, dsmStore, writerGroup->writersCount);
  1760. LIST_FOREACH(dsw, &writerGroup->writers, listEntry) {
  1761. /* Find the dataset */
  1762. UA_PublishedDataSet *pds =
  1763. UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet);
  1764. if(!pds) {
  1765. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1766. "PubSub Publish: PublishedDataSet not found");
  1767. continue;
  1768. }
  1769. /* Generate the DSM */
  1770. UA_StatusCode res =
  1771. UA_DataSetWriter_generateDataSetMessage(server, &dsmStore[dsmCount], dsw);
  1772. if(res != UA_STATUSCODE_GOOD) {
  1773. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1774. "PubSub Publish: DataSetMessage creation failed");
  1775. continue;
  1776. }
  1777. /* Send right away if there is only this DSM in a NM. If promoted fields
  1778. * are contained in the PublishedDataSet, then this DSM must go into a
  1779. * dedicated NM as well. */
  1780. if(pds->promotedFieldsCount > 0 || maxDSM == 1) {
  1781. if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP){
  1782. res = sendNetworkMessage(connection, writerGroup, &dsmStore[dsmCount],
  1783. &dsw->config.dataSetWriterId, 1,
  1784. &writerGroup->config.messageSettings,
  1785. &writerGroup->config.transportSettings);
  1786. }else if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON){
  1787. res = sendNetworkMessageJson(connection, &dsmStore[dsmCount],
  1788. &dsw->config.dataSetWriterId, 1, &writerGroup->config.transportSettings);
  1789. }
  1790. if(res != UA_STATUSCODE_GOOD)
  1791. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1792. "PubSub Publish: Could not send a NetworkMessage");
  1793. if(writerGroup->config.rtLevel == UA_PUBSUB_RT_DIRECT_VALUE_ACCESS){
  1794. for (size_t i = 0; i < dsmStore[dsmCount].data.keyFrameData.fieldCount; ++i) {
  1795. dsmStore[dsmCount].data.keyFrameData.dataSetFields[i].value.data = NULL;
  1796. }
  1797. }
  1798. UA_DataSetMessage_free(&dsmStore[dsmCount]);
  1799. continue;
  1800. }
  1801. dsWriterIds[dsmCount] = dsw->config.dataSetWriterId;
  1802. dsmCount++;
  1803. }
  1804. /* Send the NetworkMessages with batched DataSetMessages */
  1805. size_t nmCount = (dsmCount / maxDSM) + ((dsmCount % maxDSM) == 0 ? 0 : 1);
  1806. for(UA_UInt32 i = 0; i < nmCount; i++) {
  1807. UA_Byte nmDsmCount = maxDSM;
  1808. if(i == nmCount - 1 && (dsmCount % maxDSM))
  1809. nmDsmCount = (UA_Byte)dsmCount % maxDSM;
  1810. UA_StatusCode res3 = UA_STATUSCODE_GOOD;
  1811. if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP){
  1812. res3 = sendNetworkMessage(connection, writerGroup, &dsmStore[i * maxDSM],
  1813. &dsWriterIds[i * maxDSM], nmDsmCount,
  1814. &writerGroup->config.messageSettings,
  1815. &writerGroup->config.transportSettings);
  1816. writerGroup->sequenceNumber++;
  1817. }else if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON){
  1818. res3 = sendNetworkMessageJson(connection, &dsmStore[i * maxDSM],
  1819. &dsWriterIds[i * maxDSM], nmDsmCount, &writerGroup->config.transportSettings);
  1820. writerGroup->sequenceNumber++;
  1821. }
  1822. if(res3 != UA_STATUSCODE_GOOD)
  1823. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  1824. "PubSub Publish: Sending a NetworkMessage failed");
  1825. }
  1826. /* Clean up DSM */
  1827. for(size_t i = 0; i < dsmCount; i++)
  1828. UA_DataSetMessage_free(&dsmStore[i]);
  1829. }
  1830. /* Add new publishCallback. The first execution is triggered directly after
  1831. * creation. */
  1832. UA_StatusCode
  1833. UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
  1834. UA_StatusCode retval =
  1835. UA_PubSubManager_addRepeatedCallback(server,
  1836. (UA_ServerCallback) UA_WriterGroup_publishCallback,
  1837. writerGroup, writerGroup->config.publishingInterval,
  1838. &writerGroup->publishCallbackId);
  1839. if(retval == UA_STATUSCODE_GOOD)
  1840. writerGroup->publishCallbackIsRegistered = true;
  1841. /* Run once after creation */
  1842. UA_WriterGroup_publishCallback(server, writerGroup);
  1843. return retval;
  1844. }
  1845. #endif /* UA_ENABLE_PUBSUB */