ua_pubsub_ns0.c 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154
  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-2018 Fraunhofer IOSB (Author: Andreas Ebner)
  6. * Copyright (c) 2019 Kalycito Infotech Private Limited
  7. */
  8. #include "ua_pubsub_ns0.h"
  9. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */
  10. typedef struct{
  11. UA_NodeId parentNodeId;
  12. UA_UInt32 parentClassifier;
  13. UA_UInt32 elementClassiefier;
  14. } UA_NodePropertyContext;
  15. //Prototypes
  16. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  17. static UA_StatusCode addWriterGroupAction(UA_Server *server,
  18. const UA_NodeId *sessionId, void *sessionHandle,
  19. const UA_NodeId *methodId, void *methodContext,
  20. const UA_NodeId *objectId, void *objectContext,
  21. size_t inputSize, const UA_Variant *input,
  22. size_t outputSize, UA_Variant *output);
  23. static UA_StatusCode removeGroupAction(UA_Server *server,
  24. const UA_NodeId *sessionId, void *sessionHandle,
  25. const UA_NodeId *methodId, void *methodContext,
  26. const UA_NodeId *objectId, void *objectContext,
  27. size_t inputSize, const UA_Variant *input,
  28. size_t outputSize, UA_Variant *output);
  29. static UA_StatusCode addDataSetWriterAction(UA_Server *server,
  30. const UA_NodeId *sessionId, void *sessionHandle,
  31. const UA_NodeId *methodId, void *methodContext,
  32. const UA_NodeId *objectId, void *objectContext,
  33. size_t inputSize, const UA_Variant *input,
  34. size_t outputSize, UA_Variant *output);
  35. #endif
  36. static UA_StatusCode
  37. addPubSubObjectNode(UA_Server *server, char* name, UA_UInt32 objectid,
  38. UA_UInt32 parentid, UA_UInt32 referenceid, UA_UInt32 type_id) {
  39. UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
  40. object_attr.displayName = UA_LOCALIZEDTEXT("", name);
  41. return UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(0, objectid),
  42. UA_NODEID_NUMERIC(0, parentid),
  43. UA_NODEID_NUMERIC(0, referenceid),
  44. UA_QUALIFIEDNAME(0, name),
  45. UA_NODEID_NUMERIC(0, type_id),
  46. object_attr, NULL, NULL);
  47. }
  48. static UA_StatusCode
  49. writePubSubNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v,
  50. size_t length, const UA_DataType *type) {
  51. UA_Variant var;
  52. UA_Variant_init(&var);
  53. UA_Variant_setArray(&var, v, length, type);
  54. return UA_Server_writeValue(server, UA_NODEID_NUMERIC(0, id), var);
  55. }
  56. static UA_NodeId
  57. findSingleChildNode(UA_Server *server, UA_QualifiedName targetName,
  58. UA_NodeId referenceTypeId, UA_NodeId startingNode){
  59. UA_NodeId resultNodeId;
  60. UA_RelativePathElement rpe;
  61. UA_RelativePathElement_init(&rpe);
  62. rpe.referenceTypeId = referenceTypeId;
  63. rpe.isInverse = false;
  64. rpe.includeSubtypes = false;
  65. rpe.targetName = targetName;
  66. UA_BrowsePath bp;
  67. UA_BrowsePath_init(&bp);
  68. bp.startingNode = startingNode;
  69. bp.relativePath.elementsSize = 1;
  70. bp.relativePath.elements = &rpe;
  71. UA_BrowsePathResult bpr =
  72. UA_Server_translateBrowsePathToNodeIds(server, &bp);
  73. if(bpr.statusCode != UA_STATUSCODE_GOOD ||
  74. bpr.targetsSize < 1)
  75. return UA_NODEID_NULL;
  76. if(UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, &resultNodeId) != UA_STATUSCODE_GOOD){
  77. UA_BrowsePathResult_deleteMembers(&bpr);
  78. return UA_NODEID_NULL;
  79. }
  80. UA_BrowsePathResult_deleteMembers(&bpr);
  81. return resultNodeId;
  82. }
  83. static void
  84. onRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
  85. const UA_NodeId *nodeid, void *context,
  86. const UA_NumericRange *range, const UA_DataValue *data) {
  87. UA_Variant value;
  88. UA_Variant_init(&value);
  89. const UA_NodePropertyContext *nodeContext = (const UA_NodePropertyContext*)context;
  90. const UA_NodeId *myNodeId = &nodeContext->parentNodeId;
  91. switch(nodeContext->parentClassifier){
  92. case UA_NS0ID_PUBSUBCONNECTIONTYPE: {
  93. UA_PubSubConnection *pubSubConnection =
  94. UA_PubSubConnection_findConnectionbyId(server, *myNodeId);
  95. switch(nodeContext->elementClassiefier) {
  96. case UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID:
  97. if(pubSubConnection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING) {
  98. UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric,
  99. &UA_TYPES[UA_TYPES_STRING]);
  100. } else {
  101. UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric,
  102. &UA_TYPES[UA_TYPES_UINT32]);
  103. }
  104. break;
  105. default:
  106. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  107. "Read error! Unknown property.");
  108. }
  109. break;
  110. }
  111. case UA_NS0ID_WRITERGROUPTYPE: {
  112. UA_WriterGroup *writerGroup = UA_WriterGroup_findWGbyId(server, *myNodeId);
  113. if(!writerGroup)
  114. return;
  115. switch(nodeContext->elementClassiefier){
  116. case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
  117. UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval,
  118. &UA_TYPES[UA_TYPES_DURATION]);
  119. break;
  120. default:
  121. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  122. "Read error! Unknown property.");
  123. }
  124. break;
  125. }
  126. case UA_NS0ID_PUBLISHEDDATAITEMSTYPE: {
  127. UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, *myNodeId);
  128. if(!publishedDataSet)
  129. return;
  130. switch(nodeContext->elementClassiefier) {
  131. case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA: {
  132. UA_PublishedVariableDataType *pvd = (UA_PublishedVariableDataType *)
  133. UA_calloc(publishedDataSet->fieldSize, sizeof(UA_PublishedVariableDataType));
  134. size_t counter = 0;
  135. UA_DataSetField *field;
  136. LIST_FOREACH(field, &publishedDataSet->fields, listEntry) {
  137. pvd[counter].attributeId = UA_ATTRIBUTEID_VALUE;
  138. pvd[counter].publishedVariable = field->config.field.variable.publishParameters.publishedVariable;
  139. //UA_NodeId_copy(&field->config.field.variable.publishParameters.publishedVariable, &pvd[counter].publishedVariable);
  140. counter++;
  141. }
  142. UA_Variant_setArray(&value, pvd, publishedDataSet->fieldSize,
  143. &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
  144. break;
  145. }
  146. case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_DATASETMETADATA: {
  147. UA_Variant_setScalarCopy(&value, &publishedDataSet->dataSetMetaData, &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
  148. break;
  149. }
  150. case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_CONFIGURATIONVERSION: {
  151. UA_Variant_setScalarCopy(&value, &publishedDataSet->dataSetMetaData.configurationVersion,
  152. &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
  153. break;
  154. }
  155. default:
  156. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  157. "Read error! Unknown property.");
  158. }
  159. break;
  160. }
  161. default:
  162. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  163. "Read error! Unknown parent element.");
  164. }
  165. UA_Server_writeValue(server, *nodeid, value);
  166. }
  167. static void
  168. onWrite(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
  169. const UA_NodeId *nodeId, void *nodeContext,
  170. const UA_NumericRange *range, const UA_DataValue *data){
  171. UA_Variant value;
  172. UA_NodeId myNodeId;
  173. UA_WriterGroup *writerGroup = NULL;
  174. switch(((UA_NodePropertyContext *) nodeContext)->parentClassifier){
  175. case UA_NS0ID_PUBSUBCONNECTIONTYPE:
  176. //no runtime writable attributes
  177. break;
  178. case UA_NS0ID_WRITERGROUPTYPE:
  179. myNodeId = ((UA_NodePropertyContext *) nodeContext)->parentNodeId;
  180. writerGroup = UA_WriterGroup_findWGbyId(server, myNodeId);
  181. UA_WriterGroupConfig writerGroupConfig;
  182. memset(&writerGroupConfig, 0, sizeof(writerGroupConfig));
  183. if(!writerGroup)
  184. return;
  185. switch(((UA_NodePropertyContext *) nodeContext)->elementClassiefier){
  186. case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
  187. UA_Server_getWriterGroupConfig(server, writerGroup->identifier, &writerGroupConfig);
  188. writerGroupConfig.publishingInterval = *((UA_Duration *) data->value.data);
  189. UA_Server_updateWriterGroupConfig(server, writerGroup->identifier, &writerGroupConfig);
  190. UA_Variant_setScalar(&value, data->value.data, &UA_TYPES[UA_TYPES_DURATION]);
  191. UA_WriterGroupConfig_deleteMembers(&writerGroupConfig);
  192. break;
  193. default:
  194. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  195. "Write error! Unknown property element.");
  196. }
  197. break;
  198. default:
  199. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  200. "Read error! Unknown parent element.");
  201. }
  202. }
  203. static UA_StatusCode
  204. addVariableValueSource(UA_Server *server, UA_ValueCallback valueCallback,
  205. UA_NodeId node, UA_NodePropertyContext *context){
  206. UA_Server_setNodeContext(server, node, context);
  207. return UA_Server_setVariableNode_valueCallback(server, node, valueCallback);
  208. }
  209. /*************************************************/
  210. /* PubSubConnection */
  211. /*************************************************/
  212. UA_StatusCode
  213. addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){
  214. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  215. if(connection->config->name.length > 512)
  216. return UA_STATUSCODE_BADOUTOFMEMORY;
  217. UA_STACKARRAY(char, connectionName, sizeof(char) * connection->config->name.length +1);
  218. memcpy(connectionName, connection->config->name.data, connection->config->name.length);
  219. connectionName[connection->config->name.length] = '\0';
  220. //This code block must use a lock
  221. UA_Nodestore_removeNode(server->nsCtx, &connection->identifier);
  222. UA_NodeId pubSubConnectionNodeId;
  223. UA_ObjectAttributes attr = UA_ObjectAttributes_default;
  224. attr.displayName = UA_LOCALIZEDTEXT("de-DE", connectionName);
  225. retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,
  226. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric),
  227. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE),
  228. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPUBSUBCONNECTION),
  229. UA_QUALIFIEDNAME(0, connectionName),
  230. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE),
  231. (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
  232. NULL, &pubSubConnectionNodeId);
  233. addPubSubObjectNode(server, "Address", connection->identifier.identifier.numeric+1,
  234. pubSubConnectionNodeId.identifier.numeric, UA_NS0ID_HASCOMPONENT,
  235. UA_NS0ID_NETWORKADDRESSURLTYPE);
  236. UA_Server_addNode_finish(server, pubSubConnectionNodeId);
  237. //End lock zone
  238. UA_NodeId addressNode, urlNode, interfaceNode, publisherIdNode, connectionPropertieNode, transportProfileUri;
  239. addressNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Address"),
  240. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  241. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  242. urlNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Url"),
  243. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
  244. interfaceNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkInterface"),
  245. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
  246. publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
  247. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  248. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  249. connectionPropertieNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConnectionProperties"),
  250. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  251. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  252. transportProfileUri = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "TransportProfileUri"),
  253. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  254. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  255. if(UA_NodeId_equal(&addressNode, &UA_NODEID_NULL) ||
  256. UA_NodeId_equal(&urlNode, &UA_NODEID_NULL) ||
  257. UA_NodeId_equal(&interfaceNode, &UA_NODEID_NULL) ||
  258. UA_NodeId_equal(&publisherIdNode, &UA_NODEID_NULL) ||
  259. UA_NodeId_equal(&connectionPropertieNode, &UA_NODEID_NULL) ||
  260. UA_NodeId_equal(&transportProfileUri, &UA_NODEID_NULL)) {
  261. return UA_STATUSCODE_BADNOTFOUND;
  262. }
  263. retVal |= writePubSubNs0VariableArray(server, connectionPropertieNode.identifier.numeric,
  264. connection->config->connectionProperties,
  265. connection->config->connectionPropertiesSize,
  266. &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
  267. UA_NetworkAddressUrlDataType *networkAddressUrlDataType = ((UA_NetworkAddressUrlDataType *) connection->config->address.data);
  268. UA_Variant value;
  269. UA_Variant_init(&value);
  270. UA_Variant_setScalar(&value, &networkAddressUrlDataType->url, &UA_TYPES[UA_TYPES_STRING]);
  271. UA_Server_writeValue(server, urlNode, value);
  272. UA_Variant_setScalar(&value, &networkAddressUrlDataType->networkInterface, &UA_TYPES[UA_TYPES_STRING]);
  273. UA_Server_writeValue(server, interfaceNode, value);
  274. UA_Variant_setScalar(&value, &connection->config->transportProfileUri, &UA_TYPES[UA_TYPES_STRING]);
  275. UA_Server_writeValue(server, transportProfileUri, value);
  276. UA_NodePropertyContext *connectionPublisherIdContext = (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext));
  277. connectionPublisherIdContext->parentNodeId = connection->identifier;
  278. connectionPublisherIdContext->parentClassifier = UA_NS0ID_PUBSUBCONNECTIONTYPE;
  279. connectionPublisherIdContext->elementClassiefier = UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID;
  280. UA_ValueCallback valueCallback;
  281. valueCallback.onRead = onRead;
  282. valueCallback.onWrite = NULL;
  283. retVal |= addVariableValueSource(server, valueCallback, publisherIdNode, connectionPublisherIdContext);
  284. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  285. retVal |= UA_Server_addReference(server, connection->identifier,
  286. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  287. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), true);
  288. retVal |= UA_Server_addReference(server, connection->identifier,
  289. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  290. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), true);
  291. retVal |= UA_Server_addReference(server, connection->identifier,
  292. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  293. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), true);
  294. #endif
  295. return retVal;
  296. }
  297. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  298. static UA_StatusCode
  299. addPubSubConnectionAction(UA_Server *server,
  300. const UA_NodeId *sessionId, void *sessionHandle,
  301. const UA_NodeId *methodId, void *methodContext,
  302. const UA_NodeId *objectId, void *objectContext,
  303. size_t inputSize, const UA_Variant *input,
  304. size_t outputSize, UA_Variant *output){
  305. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  306. UA_PubSubConnectionDataType pubSubConnectionDataType = *((UA_PubSubConnectionDataType *) input[0].data);
  307. UA_NetworkAddressUrlDataType networkAddressUrlDataType;
  308. memset(&networkAddressUrlDataType, 0, sizeof(networkAddressUrlDataType));
  309. UA_ExtensionObject eo = pubSubConnectionDataType.address;
  310. if(eo.encoding == UA_EXTENSIONOBJECT_DECODED){
  311. if(eo.content.decoded.type == &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]){
  312. if(UA_NetworkAddressUrlDataType_copy((UA_NetworkAddressUrlDataType *) eo.content.decoded.data,
  313. &networkAddressUrlDataType) != UA_STATUSCODE_GOOD){
  314. return UA_STATUSCODE_BADOUTOFMEMORY;
  315. }
  316. }
  317. }
  318. UA_PubSubConnectionConfig connectionConfig;
  319. memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
  320. connectionConfig.transportProfileUri = pubSubConnectionDataType.transportProfileUri;
  321. connectionConfig.name = pubSubConnectionDataType.name;
  322. //TODO set real connection state
  323. connectionConfig.enabled = pubSubConnectionDataType.enabled;
  324. //connectionConfig.enabled = pubSubConnectionDataType.enabled;
  325. UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrlDataType,
  326. &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
  327. if(pubSubConnectionDataType.publisherId.type == &UA_TYPES[UA_TYPES_UINT32]){
  328. connectionConfig.publisherId.numeric = * ((UA_UInt32 *) pubSubConnectionDataType.publisherId.data);
  329. } else if(pubSubConnectionDataType.publisherId.type == &UA_TYPES[UA_TYPES_STRING]){
  330. connectionConfig.publisherIdType = UA_PUBSUB_PUBLISHERID_STRING;
  331. UA_String_copy((UA_String *) pubSubConnectionDataType.publisherId.data, &connectionConfig.publisherId.string);
  332. } else {
  333. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Unsupported PublisherId Type used.");
  334. //TODO what's the best default behaviour here?
  335. connectionConfig.publisherId.numeric = 0;
  336. }
  337. //call API function and create the connection
  338. UA_NodeId connectionId;
  339. retVal |= UA_Server_addPubSubConnection(server, &connectionConfig, &connectionId);
  340. if(retVal != UA_STATUSCODE_GOOD){
  341. return retVal;
  342. }
  343. for(size_t i = 0; i < pubSubConnectionDataType.writerGroupsSize; i++){
  344. //UA_PubSubConnection_addWriterGroup(server, UA_NODEID_NULL, NULL, NULL);
  345. }
  346. for(size_t i = 0; i < pubSubConnectionDataType.readerGroupsSize; i++){
  347. //UA_Server_addReaderGroup(server, NULL, NULL, NULL);
  348. }
  349. UA_NetworkAddressUrlDataType_deleteMembers(&networkAddressUrlDataType);
  350. //set ouput value
  351. UA_Variant_setScalarCopy(output, &connectionId, &UA_TYPES[UA_TYPES_NODEID]);
  352. return UA_STATUSCODE_GOOD;
  353. }
  354. #endif
  355. UA_StatusCode
  356. removePubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){
  357. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  358. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  359. retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  360. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP),
  361. false);
  362. retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  363. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP),
  364. false);
  365. retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  366. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP),
  367. false);
  368. #endif
  369. retVal |= UA_Server_deleteNode(server, connection->identifier, true);
  370. return retVal;
  371. }
  372. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  373. static UA_StatusCode
  374. removeConnectionAction(UA_Server *server,
  375. const UA_NodeId *sessionId, void *sessionHandle,
  376. const UA_NodeId *methodId, void *methodContext,
  377. const UA_NodeId *objectId, void *objectContext,
  378. size_t inputSize, const UA_Variant *input,
  379. size_t outputSize, UA_Variant *output){
  380. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  381. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  382. retVal |= UA_Server_removePubSubConnection(server, nodeToRemove);
  383. if(retVal == UA_STATUSCODE_BADNOTFOUND)
  384. retVal = UA_STATUSCODE_BADNODEIDUNKNOWN;
  385. return retVal;
  386. }
  387. #endif
  388. /**********************************************/
  389. /* DataSetReader */
  390. /**********************************************/
  391. UA_StatusCode
  392. addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader){
  393. //TODO implement reader part
  394. return UA_STATUSCODE_BADNOTIMPLEMENTED;
  395. }
  396. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  397. static UA_StatusCode
  398. addDataSetReaderAction(UA_Server *server,
  399. const UA_NodeId *sessionId, void *sessionHandle,
  400. const UA_NodeId *methodId, void *methodContext,
  401. const UA_NodeId *objectId, void *objectContext,
  402. size_t inputSize, const UA_Variant *input,
  403. size_t outputSize, UA_Variant *output){
  404. UA_StatusCode retVal = UA_STATUSCODE_BADNOTIMPLEMENTED;
  405. //TODO implement reader part
  406. return retVal;
  407. }
  408. #endif
  409. UA_StatusCode
  410. removeDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader* dataSetReader){
  411. //TODO implement reader part
  412. return UA_STATUSCODE_BADNOTIMPLEMENTED;
  413. }
  414. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  415. static UA_StatusCode
  416. removeDataSetReaderAction(UA_Server *server,
  417. const UA_NodeId *sessionId, void *sessionHandle,
  418. const UA_NodeId *methodId, void *methodContext,
  419. const UA_NodeId *objectId, void *objectContext,
  420. size_t inputSize, const UA_Variant *input,
  421. size_t outputSize, UA_Variant *output){
  422. UA_StatusCode retVal = UA_STATUSCODE_BADNOTIMPLEMENTED;
  423. //TODO implement reader part
  424. return retVal;
  425. }
  426. #endif
  427. /*************************************************/
  428. /* PublishedDataSet */
  429. /*************************************************/
  430. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  431. static UA_StatusCode
  432. addDataSetFolderAction(UA_Server *server,
  433. const UA_NodeId *sessionId, void *sessionHandle,
  434. const UA_NodeId *methodId, void *methodContext,
  435. const UA_NodeId *objectId, void *objectContext,
  436. size_t inputSize, const UA_Variant *input,
  437. size_t outputSize, UA_Variant *output){
  438. /* defined in R 1.04 9.1.4.5.7 */
  439. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  440. UA_String newFolderName = *((UA_String *) input[0].data);
  441. UA_NodeId generatedId;
  442. UA_ObjectAttributes objectAttributes = UA_ObjectAttributes_default;
  443. UA_LocalizedText name = {UA_STRING("en-US"), newFolderName};
  444. objectAttributes.displayName = name;
  445. retVal |= UA_Server_addObjectNode(server, UA_NODEID_NULL, *objectId, UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES),
  446. UA_QUALIFIEDNAME(0, "DataSetFolder"), UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE),
  447. objectAttributes, NULL, &generatedId);
  448. UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
  449. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  450. retVal |= UA_Server_addReference(server, generatedId,
  451. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  452. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
  453. retVal |= UA_Server_addReference(server, generatedId,
  454. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  455. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
  456. retVal |= UA_Server_addReference(server, generatedId,
  457. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  458. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
  459. retVal |= UA_Server_addReference(server, generatedId,
  460. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  461. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
  462. #endif
  463. return retVal;
  464. }
  465. #endif
  466. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  467. static UA_StatusCode
  468. removeDataSetFolderAction(UA_Server *server,
  469. const UA_NodeId *sessionId, void *sessionHandle,
  470. const UA_NodeId *methodId, void *methodContext,
  471. const UA_NodeId *objectId, void *objectContext,
  472. size_t inputSize, const UA_Variant *input,
  473. size_t outputSize, UA_Variant *output){
  474. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  475. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  476. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  477. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  478. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS),
  479. false);
  480. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  481. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET),
  482. false);
  483. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  484. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER),
  485. false);
  486. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  487. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER),
  488. false);
  489. #endif
  490. retVal |= UA_Server_deleteNode(server, nodeToRemove, false);
  491. return retVal;
  492. }
  493. #endif
  494. UA_StatusCode
  495. addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet) {
  496. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  497. if(publishedDataSet->config.name.length > 512)
  498. return UA_STATUSCODE_BADOUTOFMEMORY;
  499. UA_STACKARRAY(char, pdsName, sizeof(char) * publishedDataSet->config.name.length +1);
  500. memcpy(pdsName, publishedDataSet->config.name.data, publishedDataSet->config.name.length);
  501. pdsName[publishedDataSet->config.name.length] = '\0';
  502. //This code block must use a lock
  503. UA_Nodestore_removeNode(server->nsCtx, &publishedDataSet->identifier);
  504. retVal |= addPubSubObjectNode(server, pdsName, publishedDataSet->identifier.identifier.numeric,
  505. UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS,
  506. UA_NS0ID_HASPROPERTY, UA_NS0ID_PUBLISHEDDATAITEMSTYPE);
  507. //End lock zone
  508. UA_ValueCallback valueCallback;
  509. valueCallback.onRead = onRead;
  510. valueCallback.onWrite = NULL;
  511. UA_NodeId configurationVersionNode =
  512. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
  513. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  514. UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
  515. if(UA_NodeId_equal(&configurationVersionNode, &UA_NODEID_NULL))
  516. return UA_STATUSCODE_BADNOTFOUND;
  517. UA_NodePropertyContext * configurationVersionContext = (UA_NodePropertyContext *)
  518. UA_malloc(sizeof(UA_NodePropertyContext));
  519. configurationVersionContext->parentNodeId = publishedDataSet->identifier;
  520. configurationVersionContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
  521. configurationVersionContext->elementClassiefier =
  522. UA_NS0ID_PUBLISHEDDATAITEMSTYPE_CONFIGURATIONVERSION;
  523. retVal |= addVariableValueSource(server, valueCallback, configurationVersionNode,
  524. configurationVersionContext);
  525. UA_NodeId publishedDataNode =
  526. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
  527. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  528. UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
  529. if(UA_NodeId_equal(&publishedDataNode, &UA_NODEID_NULL))
  530. return UA_STATUSCODE_BADNOTFOUND;
  531. UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
  532. UA_malloc(sizeof(UA_NodePropertyContext));
  533. publishingIntervalContext->parentNodeId = publishedDataSet->identifier;
  534. publishingIntervalContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
  535. publishingIntervalContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA;
  536. retVal |= addVariableValueSource(server, valueCallback, publishedDataNode,
  537. publishingIntervalContext);
  538. UA_NodeId dataSetMetaDataNode =
  539. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
  540. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  541. UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
  542. if(UA_NodeId_equal(&dataSetMetaDataNode, &UA_NODEID_NULL))
  543. return UA_STATUSCODE_BADNOTFOUND;
  544. UA_NodePropertyContext *metaDataContext = (UA_NodePropertyContext *)
  545. UA_malloc(sizeof(UA_NodePropertyContext));
  546. metaDataContext->parentNodeId = publishedDataSet->identifier;
  547. metaDataContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
  548. metaDataContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE_DATASETMETADATA;
  549. retVal |= addVariableValueSource(server, valueCallback, dataSetMetaDataNode, metaDataContext);
  550. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  551. retVal |= UA_Server_addReference(server, publishedDataSet->identifier,
  552. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  553. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), true);
  554. retVal |= UA_Server_addReference(server, publishedDataSet->identifier,
  555. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  556. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), true);
  557. #endif
  558. return retVal;
  559. }
  560. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  561. static UA_StatusCode
  562. addPublishedDataItemsAction(UA_Server *server,
  563. const UA_NodeId *sessionId, void *sessionHandle,
  564. const UA_NodeId *methodId, void *methodContext,
  565. const UA_NodeId *objectId, void *objectContext,
  566. size_t inputSize, const UA_Variant *input,
  567. size_t outputSize, UA_Variant *output){
  568. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  569. size_t fieldNameAliasesSize = input[1].arrayLength;
  570. UA_String * fieldNameAliases = (UA_String *) input[1].data;
  571. size_t fieldFlagsSize = input[2].arrayLength;
  572. UA_DataSetFieldFlags * fieldFlags = (UA_DataSetFieldFlags *) input[2].data;
  573. size_t variablesToAddSize = input[3].arrayLength;
  574. UA_PublishedVariableDataType *variablesToAddField = (UA_PublishedVariableDataType *) input[3].data;
  575. if(!(fieldNameAliasesSize == fieldFlagsSize || fieldFlagsSize == variablesToAddSize))
  576. return UA_STATUSCODE_BADINVALIDARGUMENT;
  577. UA_PublishedDataSetConfig publishedDataSetConfig;
  578. memset(&publishedDataSetConfig, 0, sizeof(publishedDataSetConfig));
  579. publishedDataSetConfig.name = *((UA_String *) input[0].data);
  580. publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;
  581. UA_NodeId dataSetItemsNodeId;
  582. retVal |= UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, &dataSetItemsNodeId).addResult;
  583. UA_DataSetFieldConfig dataSetFieldConfig;
  584. for(size_t j = 0; j < variablesToAddSize; ++j) {
  585. memset(&dataSetFieldConfig, 0, sizeof(dataSetFieldConfig));
  586. dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
  587. dataSetFieldConfig.field.variable.fieldNameAlias = fieldNameAliases[j];
  588. if(fieldFlags[j] == UA_DATASETFIELDFLAGS_PROMOTEDFIELD){
  589. dataSetFieldConfig.field.variable.promotedField = UA_TRUE;
  590. }
  591. dataSetFieldConfig.field.variable.publishParameters = variablesToAddField[j];
  592. UA_Server_addDataSetField(server, dataSetItemsNodeId, &dataSetFieldConfig, NULL);
  593. }
  594. UA_PublishedVariableDataType_clear(variablesToAddField);
  595. return retVal;
  596. }
  597. #endif
  598. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  599. static UA_StatusCode
  600. addVariablesAction(UA_Server *server,
  601. const UA_NodeId *sessionId, void *sessionHandle,
  602. const UA_NodeId *methodId, void *methodContext,
  603. const UA_NodeId *objectId, void *objectContext,
  604. size_t inputSize, const UA_Variant *input,
  605. size_t outputSize, UA_Variant *output){
  606. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  607. return retVal;
  608. }
  609. static UA_StatusCode
  610. removeVariablesAction(UA_Server *server,
  611. const UA_NodeId *sessionId, void *sessionHandle,
  612. const UA_NodeId *methodId, void *methodContext,
  613. const UA_NodeId *objectId, void *objectContext,
  614. size_t inputSize, const UA_Variant *input,
  615. size_t outputSize, UA_Variant *output){
  616. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  617. return retVal;
  618. }
  619. #endif
  620. UA_StatusCode
  621. removePublishedDataSetRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet){
  622. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  623. retVal |= UA_Server_deleteNode(server, publishedDataSet->identifier, false);
  624. return retVal;
  625. }
  626. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  627. static UA_StatusCode
  628. removePublishedDataSetAction(UA_Server *server,
  629. const UA_NodeId *sessionId, void *sessionHandle,
  630. const UA_NodeId *methodId, void *methodContext,
  631. const UA_NodeId *objectId, void *objectContext,
  632. size_t inputSize, const UA_Variant *input,
  633. size_t outputSize, UA_Variant *output){
  634. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  635. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  636. retVal |= UA_Server_removePublishedDataSet(server, nodeToRemove);
  637. return retVal;
  638. }
  639. #endif
  640. /**********************************************/
  641. /* WriterGroup */
  642. /**********************************************/
  643. static UA_StatusCode
  644. readContentMask(UA_Server *server, const UA_NodeId *sessionId,
  645. void *sessionContext, const UA_NodeId *nodeId,
  646. void *nodeContext, UA_Boolean includeSourceTimeStamp,
  647. const UA_NumericRange *range, UA_DataValue *value) {
  648. UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
  649. if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
  650. writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
  651. writerGroup->config.messageSettings.content.decoded.type !=
  652. &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
  653. return UA_STATUSCODE_BADINTERNALERROR;
  654. UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
  655. writerGroup->config.messageSettings.content.decoded.data;
  656. UA_Variant_setScalarCopy(&value->value, &wgm->networkMessageContentMask,
  657. &UA_TYPES[UA_TYPES_UADPNETWORKMESSAGECONTENTMASK]);
  658. value->hasValue = true;
  659. return UA_STATUSCODE_GOOD;
  660. }
  661. static UA_StatusCode
  662. writeContentMask(UA_Server *server, const UA_NodeId *sessionId,
  663. void *sessionContext, const UA_NodeId *nodeId,
  664. void *nodeContext, const UA_NumericRange *range,
  665. const UA_DataValue *value) {
  666. UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
  667. if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
  668. writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
  669. writerGroup->config.messageSettings.content.decoded.type !=
  670. &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
  671. return UA_STATUSCODE_BADINTERNALERROR;
  672. UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
  673. writerGroup->config.messageSettings.content.decoded.data;
  674. if(!value->value.type)
  675. return UA_STATUSCODE_BADTYPEMISMATCH;
  676. if(value->value.type->typeKind != UA_DATATYPEKIND_ENUM &&
  677. value->value.type->typeKind != UA_DATATYPEKIND_INT32)
  678. return UA_STATUSCODE_BADTYPEMISMATCH;
  679. wgm->networkMessageContentMask = *(UA_UadpNetworkMessageContentMask*)value->value.data;
  680. return UA_STATUSCODE_GOOD;
  681. }
  682. UA_StatusCode
  683. addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup){
  684. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  685. if(writerGroup->config.name.length > 512)
  686. return UA_STATUSCODE_BADOUTOFMEMORY;
  687. UA_STACKARRAY(char, wgName, sizeof(char) * writerGroup->config.name.length + 1);
  688. memcpy(wgName, writerGroup->config.name.data, writerGroup->config.name.length);
  689. wgName[writerGroup->config.name.length] = '\0';
  690. //This code block must use a lock
  691. UA_Nodestore_removeNode(server->nsCtx, &writerGroup->identifier);
  692. retVal |= addPubSubObjectNode(server, wgName, writerGroup->identifier.identifier.numeric,
  693. writerGroup->linkedConnection.identifier.numeric,
  694. UA_NS0ID_HASCOMPONENT, UA_NS0ID_WRITERGROUPTYPE);
  695. //End lock zone
  696. UA_NodeId keepAliveNode =
  697. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeepAliveTime"),
  698. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  699. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  700. UA_NodeId publishingIntervalNode =
  701. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
  702. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  703. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  704. if(UA_NodeId_equal(&keepAliveNode, &UA_NODEID_NULL) ||
  705. UA_NodeId_equal(&publishingIntervalNode, &UA_NODEID_NULL))
  706. return UA_STATUSCODE_BADNOTFOUND;
  707. UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
  708. UA_malloc(sizeof(UA_NodePropertyContext));
  709. publishingIntervalContext->parentNodeId = writerGroup->identifier;
  710. publishingIntervalContext->parentClassifier = UA_NS0ID_WRITERGROUPTYPE;
  711. publishingIntervalContext->elementClassiefier = UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL;
  712. UA_ValueCallback valueCallback;
  713. valueCallback.onRead = onRead;
  714. valueCallback.onWrite = onWrite;
  715. retVal |= addVariableValueSource(server, valueCallback,
  716. publishingIntervalNode, publishingIntervalContext);
  717. UA_Server_writeAccessLevel(server, publishingIntervalNode,
  718. UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE);
  719. UA_NodeId priorityNode =
  720. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Priority"),
  721. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  722. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  723. UA_NodeId writerGroupIdNode =
  724. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"),
  725. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  726. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  727. UA_Variant value;
  728. UA_Variant_init(&value);
  729. UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval, &UA_TYPES[UA_TYPES_DURATION]);
  730. UA_Server_writeValue(server, publishingIntervalNode, value);
  731. UA_Variant_setScalar(&value, &writerGroup->config.keepAliveTime, &UA_TYPES[UA_TYPES_DURATION]);
  732. UA_Server_writeValue(server, keepAliveNode, value);
  733. UA_Variant_setScalar(&value, &writerGroup->config.priority, &UA_TYPES[UA_TYPES_BYTE]);
  734. UA_Server_writeValue(server, priorityNode, value);
  735. UA_Variant_setScalar(&value, &writerGroup->config.writerGroupId, &UA_TYPES[UA_TYPES_UINT16]);
  736. UA_Server_writeValue(server, writerGroupIdNode, value);
  737. retVal |= addPubSubObjectNode(server, "MessageSettings", 0,
  738. writerGroup->identifier.identifier.numeric,
  739. UA_NS0ID_HASCOMPONENT, UA_NS0ID_UADPWRITERGROUPMESSAGETYPE);
  740. /* Find the variable with the content mask */
  741. UA_NodeId messageSettingsId =
  742. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "MessageSettings"),
  743. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  744. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  745. UA_NodeId contentMaskId =
  746. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkMessageContentMask"),
  747. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), messageSettingsId);
  748. if(UA_NodeId_equal(&messageSettingsId, &UA_NODEID_NULL) ||
  749. UA_NodeId_equal(&contentMaskId, &UA_NODEID_NULL)) {
  750. return UA_STATUSCODE_BADNOTFOUND;
  751. }
  752. /* Set the callback */
  753. UA_DataSource ds;
  754. ds.read = readContentMask;
  755. ds.write = writeContentMask;
  756. UA_Server_setVariableNode_dataSource(server, contentMaskId, ds);
  757. UA_Server_setNodeContext(server, contentMaskId, writerGroup);
  758. /* Make writable */
  759. UA_Server_writeAccessLevel(server, contentMaskId,
  760. UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_READ);
  761. return retVal;
  762. }
  763. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  764. static UA_StatusCode
  765. addWriterGroupAction(UA_Server *server,
  766. const UA_NodeId *sessionId, void *sessionHandle,
  767. const UA_NodeId *methodId, void *methodContext,
  768. const UA_NodeId *objectId, void *objectContext,
  769. size_t inputSize, const UA_Variant *input,
  770. size_t outputSize, UA_Variant *output){
  771. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  772. UA_WriterGroupDataType *writerGroupDataType = ((UA_WriterGroupDataType *) input[0].data);
  773. UA_NodeId generatedId;
  774. UA_WriterGroupConfig writerGroupConfig;
  775. memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
  776. writerGroupConfig.name = writerGroupDataType->name;
  777. writerGroupConfig.publishingInterval = writerGroupDataType->publishingInterval;
  778. writerGroupConfig.writerGroupId = writerGroupDataType->writerGroupId;
  779. writerGroupConfig.enabled = writerGroupDataType->enabled;
  780. writerGroupConfig.priority = writerGroupDataType->priority;
  781. //TODO remove hard coded UADP
  782. writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
  783. //ToDo transfer all arguments to internal WGConfiguration
  784. retVal |= UA_Server_addWriterGroup(server, *objectId, &writerGroupConfig, &generatedId);
  785. UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
  786. return retVal;
  787. }
  788. #endif
  789. UA_StatusCode
  790. removeGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup) {
  791. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  792. retVal |= UA_Server_deleteNode(server, writerGroup->identifier, false);
  793. return retVal;
  794. }
  795. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  796. static UA_StatusCode
  797. removeGroupAction(UA_Server *server,
  798. const UA_NodeId *sessionId, void *sessionHandle,
  799. const UA_NodeId *methodId, void *methodContext,
  800. const UA_NodeId *objectId, void *objectContext,
  801. size_t inputSize, const UA_Variant *input,
  802. size_t outputSize, UA_Variant *output){
  803. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  804. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  805. if(UA_WriterGroup_findWGbyId(server, nodeToRemove) != NULL)
  806. retVal |= UA_Server_removeWriterGroup(server, nodeToRemove);
  807. //else
  808. //retVal |= UA_Server_removeReaderGroup(server, nodeToRemve);
  809. return retVal;
  810. }
  811. #endif
  812. /**********************************************/
  813. /* ReaderGroup */
  814. /**********************************************/
  815. UA_StatusCode
  816. addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup){
  817. //TODO implement reader part
  818. return UA_STATUSCODE_BADNOTIMPLEMENTED;
  819. }
  820. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  821. static UA_StatusCode
  822. addReaderGroupAction(UA_Server *server,
  823. const UA_NodeId *sessionId, void *sessionHandle,
  824. const UA_NodeId *methodId, void *methodContext,
  825. const UA_NodeId *objectId, void *objectContext,
  826. size_t inputSize, const UA_Variant *input,
  827. size_t outputSize, UA_Variant *output){
  828. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  829. //TODO implement reader part
  830. return retVal;
  831. }
  832. #endif
  833. /**********************************************/
  834. /* DataSetWriter */
  835. /**********************************************/
  836. UA_StatusCode
  837. addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter){
  838. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  839. if(dataSetWriter->config.name.length > 512)
  840. return UA_STATUSCODE_BADOUTOFMEMORY;
  841. UA_STACKARRAY(char, dswName, sizeof(char) * dataSetWriter->config.name.length + 1);
  842. memcpy(dswName, dataSetWriter->config.name.data, dataSetWriter->config.name.length);
  843. dswName[dataSetWriter->config.name.length] = '\0';
  844. //This code block must use a lock
  845. UA_Nodestore_removeNode(server->nsCtx, &dataSetWriter->identifier);
  846. retVal |= addPubSubObjectNode(server, dswName, dataSetWriter->identifier.identifier.numeric,
  847. dataSetWriter->linkedWriterGroup.identifier.numeric,
  848. UA_NS0ID_HASDATASETWRITER, UA_NS0ID_DATASETWRITERTYPE);
  849. //End lock zone
  850. retVal |= UA_Server_addReference(server, dataSetWriter->connectedDataSet,
  851. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETTOWRITER),
  852. UA_EXPANDEDNODEID_NUMERIC(0, dataSetWriter->identifier.identifier.numeric), true);
  853. retVal |= addPubSubObjectNode(server, "MessageSettings", 0,
  854. dataSetWriter->identifier.identifier.numeric,
  855. UA_NS0ID_HASCOMPONENT, UA_NS0ID_UADPDATASETWRITERMESSAGETYPE);
  856. return retVal;
  857. }
  858. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  859. static UA_StatusCode
  860. addDataSetWriterAction(UA_Server *server,
  861. const UA_NodeId *sessionId, void *sessionHandle,
  862. const UA_NodeId *methodId, void *methodContext,
  863. const UA_NodeId *objectId, void *objectContext,
  864. size_t inputSize, const UA_Variant *input,
  865. size_t outputSize, UA_Variant *output){
  866. UA_DataSetWriterDataType *dataSetWriterDataType = (UA_DataSetWriterDataType *) input[0].data;
  867. UA_NodeId targetPDS = UA_NODEID_NULL;
  868. for(size_t i = 0; i < server->pubSubManager.publishedDataSetsSize; ++i) {
  869. if(UA_String_equal(&dataSetWriterDataType->dataSetName,
  870. &server->pubSubManager.publishedDataSets[i].config.name)){
  871. targetPDS = server->pubSubManager.publishedDataSets[i].identifier;
  872. }
  873. }
  874. if(UA_NodeId_isNull(&targetPDS))
  875. return UA_STATUSCODE_BADPARENTNODEIDINVALID;
  876. UA_NodeId generatedId;
  877. UA_DataSetWriterConfig dataSetWriterConfig;
  878. memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
  879. dataSetWriterConfig.name = dataSetWriterDataType->name;
  880. dataSetWriterConfig.dataSetName = dataSetWriterDataType->dataSetName;
  881. dataSetWriterConfig.keyFrameCount = dataSetWriterDataType->keyFrameCount;
  882. dataSetWriterConfig.dataSetWriterId = dataSetWriterDataType->dataSetWriterId;
  883. UA_Server_addDataSetWriter(server, *objectId, targetPDS, &dataSetWriterConfig, &generatedId);
  884. UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
  885. return UA_STATUSCODE_GOOD;
  886. }
  887. #endif
  888. UA_StatusCode
  889. removeDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter) {
  890. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  891. retVal |= UA_Server_deleteNode(server, dataSetWriter->identifier, false);
  892. return retVal;
  893. }
  894. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  895. static UA_StatusCode
  896. removeDataSetWriterAction(UA_Server *server,
  897. const UA_NodeId *sessionId, void *sessionHandle,
  898. const UA_NodeId *methodId, void *methodContext,
  899. const UA_NodeId *objectId, void *objectContext,
  900. size_t inputSize, const UA_Variant *input,
  901. size_t outputSize, UA_Variant *output){
  902. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  903. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  904. retVal |= UA_Server_removeDataSetWriter(server, nodeToRemove);
  905. return retVal;
  906. }
  907. #endif
  908. /**********************************************/
  909. /* Destructors */
  910. /**********************************************/
  911. static void
  912. connectionTypeDestructor(UA_Server *server,
  913. const UA_NodeId *sessionId, void *sessionContext,
  914. const UA_NodeId *typeId, void *typeContext,
  915. const UA_NodeId *nodeId, void **nodeContext) {
  916. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Connection destructor called!");
  917. UA_NodeId publisherIdNode;
  918. publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
  919. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  920. UA_NodePropertyContext *internalConnectionContext;
  921. UA_Server_getNodeContext(server, publisherIdNode, (void **) &internalConnectionContext);
  922. if(!UA_NodeId_equal(&UA_NODEID_NULL , &publisherIdNode)){
  923. UA_free(internalConnectionContext);
  924. }
  925. }
  926. static void
  927. writerGroupTypeDestructor(UA_Server *server,
  928. const UA_NodeId *sessionId, void *sessionContext,
  929. const UA_NodeId *typeId, void *typeContext,
  930. const UA_NodeId *nodeId, void **nodeContext) {
  931. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "WriterGroup destructor called!");
  932. UA_NodeId intervalNode;
  933. intervalNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
  934. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  935. UA_NodePropertyContext *internalConnectionContext;
  936. UA_Server_getNodeContext(server, intervalNode, (void **) &internalConnectionContext);
  937. if(!UA_NodeId_equal(&UA_NODEID_NULL , &intervalNode)){
  938. UA_free(internalConnectionContext);
  939. }
  940. }
  941. static void
  942. readerGroupTypeDestructor(UA_Server *server,
  943. const UA_NodeId *sessionId, void *sessionContext,
  944. const UA_NodeId *typeId, void *typeContext,
  945. const UA_NodeId *nodeId, void **nodeContext) {
  946. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "ReaderGroup destructor called!");
  947. }
  948. static void
  949. dataSetWriterTypeDestructor(UA_Server *server,
  950. const UA_NodeId *sessionId, void *sessionContext,
  951. const UA_NodeId *typeId, void *typeContext,
  952. const UA_NodeId *nodeId, void **nodeContext) {
  953. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "DataSetWriter destructor called!");
  954. }
  955. static void
  956. dataSetReaderTypeDestructor(UA_Server *server,
  957. const UA_NodeId *sessionId, void *sessionContext,
  958. const UA_NodeId *typeId, void *typeContext,
  959. const UA_NodeId *nodeId, void **nodeContext) {
  960. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "DataSetReader destructor called!");
  961. }
  962. static void
  963. publishedDataItemsTypeDestructor(UA_Server *server,
  964. const UA_NodeId *sessionId, void *sessionContext,
  965. const UA_NodeId *typeId, void *typeContext,
  966. const UA_NodeId *nodeId, void **nodeContext) {
  967. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND,
  968. "PublishedDataItems destructor called!");
  969. void *childContext;
  970. UA_NodeId node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
  971. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  972. UA_Server_getNodeContext(server, node, (void**)&childContext);
  973. if(!UA_NodeId_equal(&UA_NODEID_NULL , &node))
  974. UA_free(childContext);
  975. node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
  976. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  977. *nodeId);
  978. UA_Server_getNodeContext(server, node, (void**)&childContext);
  979. if(!UA_NodeId_equal(&UA_NODEID_NULL , &node))
  980. UA_free(childContext);
  981. node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
  982. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  983. UA_Server_getNodeContext(server, node, (void**)&childContext);
  984. if(!UA_NodeId_equal(&node, &UA_NODEID_NULL))
  985. UA_free(childContext);
  986. }
  987. UA_StatusCode
  988. UA_Server_initPubSubNS0(UA_Server *server) {
  989. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  990. UA_String profileArray[1];
  991. profileArray[0] = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
  992. retVal |= writePubSubNs0VariableArray(server, UA_NS0ID_PUBLISHSUBSCRIBE_SUPPORTEDTRANSPORTPROFILES,
  993. profileArray,
  994. 1, &UA_TYPES[UA_TYPES_STRING]);
  995. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  996. retVal |= UA_Server_setMethodNode_callback(server,
  997. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION), addPubSubConnectionAction);
  998. retVal |= UA_Server_setMethodNode_callback(server,
  999. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION), removeConnectionAction);
  1000. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  1001. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  1002. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
  1003. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  1004. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  1005. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
  1006. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  1007. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  1008. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
  1009. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  1010. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  1011. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
  1012. retVal |= UA_Server_setMethodNode_callback(server,
  1013. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), addDataSetFolderAction);
  1014. retVal |= UA_Server_setMethodNode_callback(server,
  1015. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), removeDataSetFolderAction);
  1016. retVal |= UA_Server_setMethodNode_callback(server,
  1017. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), addPublishedDataItemsAction);
  1018. retVal |= UA_Server_setMethodNode_callback(server,
  1019. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), removePublishedDataSetAction);
  1020. retVal |= UA_Server_setMethodNode_callback(server,
  1021. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), addVariablesAction);
  1022. retVal |= UA_Server_setMethodNode_callback(server,
  1023. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), removeVariablesAction);
  1024. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), addWriterGroupAction);
  1025. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), addReaderGroupAction);
  1026. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), removeGroupAction);
  1027. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_ADDDATASETWRITER), addDataSetWriterAction);
  1028. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_REMOVEDATASETWRITER), removeDataSetWriterAction);
  1029. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_ADDDATASETREADER), addDataSetReaderAction);
  1030. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_REMOVEDATASETREADER), removeDataSetReaderAction);
  1031. #else
  1032. retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  1033. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION),
  1034. false);
  1035. retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  1036. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION),
  1037. false);
  1038. #endif
  1039. UA_NodeTypeLifecycle liveCycle;
  1040. liveCycle.constructor = NULL;
  1041. liveCycle.destructor = connectionTypeDestructor;
  1042. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE), liveCycle);
  1043. liveCycle.destructor = writerGroupTypeDestructor;
  1044. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE), liveCycle);
  1045. liveCycle.destructor = readerGroupTypeDestructor;
  1046. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE), liveCycle);
  1047. liveCycle.destructor = dataSetWriterTypeDestructor;
  1048. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETWRITERDATATYPE), liveCycle);
  1049. liveCycle.destructor = publishedDataItemsTypeDestructor;
  1050. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE), liveCycle);
  1051. liveCycle.destructor = dataSetReaderTypeDestructor;
  1052. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETREADERDATATYPE), liveCycle);
  1053. return retVal;
  1054. }
  1055. #endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */