ua_client_highlevel.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. #include "ua_client.h"
  5. #include "ua_nodeids.h"
  6. #include "ua_client_highlevel.h"
  7. #include "ua_types_encoding_binary.h"
  8. #include "ua_util.h"
  9. #include "ua_types.h"
  10. UA_StatusCode
  11. UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,
  12. UA_UInt16 *namespaceIndex) {
  13. UA_ReadRequest request;
  14. UA_ReadRequest_init(&request);
  15. UA_ReadValueId id;
  16. id.attributeId = UA_ATTRIBUTEID_VALUE;
  17. id.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY);
  18. request.nodesToRead = &id;
  19. request.nodesToReadSize = 1;
  20. UA_ReadResponse response = UA_Client_Service_read(client, request);
  21. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  22. if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  23. retval = response.responseHeader.serviceResult;
  24. else if(response.resultsSize != 1 || !response.results[0].hasValue)
  25. retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  26. else if(response.results[0].value.type != &UA_TYPES[UA_TYPES_STRING])
  27. retval = UA_STATUSCODE_BADTYPEMISMATCH;
  28. if(retval != UA_STATUSCODE_GOOD) {
  29. UA_ReadResponse_deleteMembers(&response);
  30. return retval;
  31. }
  32. retval = UA_STATUSCODE_BADNOTFOUND;
  33. UA_String *ns = (UA_String *)response.results[0].value.data;
  34. for(size_t i = 0; i < response.results[0].value.arrayLength; ++i){
  35. if(UA_String_equal(namespaceUri, &ns[i])) {
  36. *namespaceIndex = (UA_UInt16)i;
  37. retval = UA_STATUSCODE_GOOD;
  38. break;
  39. }
  40. }
  41. UA_ReadResponse_deleteMembers(&response);
  42. return retval;
  43. }
  44. UA_StatusCode
  45. UA_Client_forEachChildNodeCall(UA_Client *client, UA_NodeId parentNodeId,
  46. UA_NodeIteratorCallback callback, void *handle) {
  47. UA_BrowseRequest bReq;
  48. UA_BrowseRequest_init(&bReq);
  49. bReq.requestedMaxReferencesPerNode = 0;
  50. bReq.nodesToBrowse = UA_BrowseDescription_new();
  51. bReq.nodesToBrowseSize = 1;
  52. UA_NodeId_copy(&parentNodeId, &bReq.nodesToBrowse[0].nodeId);
  53. bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything
  54. bReq.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_BOTH;
  55. UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
  56. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  57. if(bResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD) {
  58. for (size_t i = 0; i < bResp.resultsSize; ++i) {
  59. for (size_t j = 0; j < bResp.results[i].referencesSize; ++j) {
  60. UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
  61. retval |= callback(ref->nodeId.nodeId, !ref->isForward,
  62. ref->referenceTypeId, handle);
  63. }
  64. }
  65. }
  66. else
  67. retval = bResp.responseHeader.serviceResult;
  68. UA_BrowseRequest_deleteMembers(&bReq);
  69. UA_BrowseResponse_deleteMembers(&bResp);
  70. return retval;
  71. }
  72. /*******************/
  73. /* Node Management */
  74. /*******************/
  75. UA_StatusCode UA_EXPORT
  76. UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId,
  77. const UA_NodeId referenceTypeId, UA_Boolean isForward,
  78. const UA_String targetServerUri,
  79. const UA_ExpandedNodeId targetNodeId,
  80. UA_NodeClass targetNodeClass) {
  81. UA_AddReferencesItem item;
  82. UA_AddReferencesItem_init(&item);
  83. item.sourceNodeId = sourceNodeId;
  84. item.referenceTypeId = referenceTypeId;
  85. item.isForward = isForward;
  86. item.targetServerUri = targetServerUri;
  87. item.targetNodeId = targetNodeId;
  88. item.targetNodeClass = targetNodeClass;
  89. UA_AddReferencesRequest request;
  90. UA_AddReferencesRequest_init(&request);
  91. request.referencesToAdd = &item;
  92. request.referencesToAddSize = 1;
  93. UA_AddReferencesResponse response = UA_Client_Service_addReferences(client, request);
  94. UA_StatusCode retval = response.responseHeader.serviceResult;
  95. if(retval != UA_STATUSCODE_GOOD) {
  96. UA_AddReferencesResponse_deleteMembers(&response);
  97. return retval;
  98. }
  99. if(response.resultsSize != 1) {
  100. UA_AddReferencesResponse_deleteMembers(&response);
  101. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  102. }
  103. retval = response.results[0];
  104. UA_AddReferencesResponse_deleteMembers(&response);
  105. return retval;
  106. }
  107. UA_StatusCode UA_EXPORT
  108. UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId,
  109. const UA_NodeId referenceTypeId, UA_Boolean isForward,
  110. const UA_ExpandedNodeId targetNodeId,
  111. UA_Boolean deleteBidirectional) {
  112. UA_DeleteReferencesItem item;
  113. UA_DeleteReferencesItem_init(&item);
  114. item.sourceNodeId = sourceNodeId;
  115. item.referenceTypeId = referenceTypeId;
  116. item.isForward = isForward;
  117. item.targetNodeId = targetNodeId;
  118. item.deleteBidirectional = deleteBidirectional;
  119. UA_DeleteReferencesRequest request;
  120. UA_DeleteReferencesRequest_init(&request);
  121. request.referencesToDelete = &item;
  122. request.referencesToDeleteSize = 1;
  123. UA_DeleteReferencesResponse response = UA_Client_Service_deleteReferences(client, request);
  124. UA_StatusCode retval = response.responseHeader.serviceResult;
  125. if(retval != UA_STATUSCODE_GOOD) {
  126. UA_DeleteReferencesResponse_deleteMembers(&response);
  127. return retval;
  128. }
  129. if(response.resultsSize != 1) {
  130. UA_DeleteReferencesResponse_deleteMembers(&response);
  131. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  132. }
  133. retval = response.results[0];
  134. UA_DeleteReferencesResponse_deleteMembers(&response);
  135. return retval;
  136. }
  137. UA_StatusCode
  138. UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId,
  139. UA_Boolean deleteTargetReferences) {
  140. UA_DeleteNodesItem item;
  141. UA_DeleteNodesItem_init(&item);
  142. item.nodeId = nodeId;
  143. item.deleteTargetReferences = deleteTargetReferences;
  144. UA_DeleteNodesRequest request;
  145. UA_DeleteNodesRequest_init(&request);
  146. request.nodesToDelete = &item;
  147. request.nodesToDeleteSize = 1;
  148. UA_DeleteNodesResponse response = UA_Client_Service_deleteNodes(client, request);
  149. UA_StatusCode retval = response.responseHeader.serviceResult;
  150. if(retval != UA_STATUSCODE_GOOD) {
  151. UA_DeleteNodesResponse_deleteMembers(&response);
  152. return retval;
  153. }
  154. if(response.resultsSize != 1) {
  155. UA_DeleteNodesResponse_deleteMembers(&response);
  156. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  157. }
  158. retval = response.results[0];
  159. UA_DeleteNodesResponse_deleteMembers(&response);
  160. return retval;
  161. }
  162. UA_StatusCode
  163. __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
  164. const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
  165. const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
  166. const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
  167. const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
  168. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  169. UA_AddNodesRequest request;
  170. UA_AddNodesRequest_init(&request);
  171. UA_AddNodesItem item;
  172. UA_AddNodesItem_init(&item);
  173. item.parentNodeId.nodeId = parentNodeId;
  174. item.referenceTypeId = referenceTypeId;
  175. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  176. item.browseName = browseName;
  177. item.nodeClass = nodeClass;
  178. item.typeDefinition.nodeId = typeDefinition;
  179. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  180. item.nodeAttributes.content.decoded.type = attributeType;
  181. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr; // hack. is not written into.
  182. request.nodesToAdd = &item;
  183. request.nodesToAddSize = 1;
  184. UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request);
  185. if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
  186. retval = response.responseHeader.serviceResult;
  187. UA_AddNodesResponse_deleteMembers(&response);
  188. return retval;
  189. }
  190. if(response.resultsSize != 1) {
  191. UA_AddNodesResponse_deleteMembers(&response);
  192. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  193. }
  194. if(outNewNodeId && response.results[0].statusCode == UA_STATUSCODE_GOOD) {
  195. *outNewNodeId = response.results[0].addedNodeId;
  196. UA_NodeId_init(&response.results[0].addedNodeId);
  197. }
  198. retval = response.results[0].statusCode;
  199. UA_AddNodesResponse_deleteMembers(&response);
  200. return retval;
  201. }
  202. /********/
  203. /* Call */
  204. /********/
  205. #ifdef UA_ENABLE_METHODCALLS
  206. UA_StatusCode
  207. UA_Client_call(UA_Client *client, const UA_NodeId objectId,
  208. const UA_NodeId methodId, size_t inputSize,
  209. const UA_Variant *input, size_t *outputSize,
  210. UA_Variant **output) {
  211. UA_CallRequest request;
  212. UA_CallRequest_init(&request);
  213. UA_CallMethodRequest item;
  214. UA_CallMethodRequest_init(&item);
  215. item.methodId = methodId;
  216. item.objectId = objectId;
  217. item.inputArguments = (UA_Variant *)(void*)(uintptr_t)input; // cast const...
  218. item.inputArgumentsSize = inputSize;
  219. request.methodsToCall = &item;
  220. request.methodsToCallSize = 1;
  221. UA_CallResponse response = UA_Client_Service_call(client, request);
  222. UA_StatusCode retval = response.responseHeader.serviceResult;
  223. if(retval != UA_STATUSCODE_GOOD) {
  224. UA_CallResponse_deleteMembers(&response);
  225. return retval;
  226. }
  227. if(response.resultsSize != 1) {
  228. UA_CallResponse_deleteMembers(&response);
  229. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  230. }
  231. retval = response.results[0].statusCode;
  232. if(retval == UA_STATUSCODE_GOOD && response.resultsSize > 0) {
  233. if (output != NULL && outputSize != NULL) {
  234. *output = response.results[0].outputArguments;
  235. *outputSize = response.results[0].outputArgumentsSize;
  236. }
  237. response.results[0].outputArguments = NULL;
  238. response.results[0].outputArgumentsSize = 0;
  239. }
  240. UA_CallResponse_deleteMembers(&response);
  241. return retval;
  242. }
  243. #endif
  244. /********************/
  245. /* Write Attributes */
  246. /********************/
  247. UA_StatusCode
  248. __UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId,
  249. UA_AttributeId attributeId, const void *in,
  250. const UA_DataType *inDataType) {
  251. if(!in)
  252. return UA_STATUSCODE_BADTYPEMISMATCH;
  253. UA_WriteValue wValue;
  254. UA_WriteValue_init(&wValue);
  255. wValue.nodeId = *nodeId;
  256. wValue.attributeId = attributeId;
  257. if(attributeId == UA_ATTRIBUTEID_VALUE)
  258. wValue.value.value = *(const UA_Variant*)in;
  259. else
  260. /* hack. is never written into. */
  261. UA_Variant_setScalar(&wValue.value.value, (void*)(uintptr_t)in, inDataType);
  262. wValue.value.hasValue = true;
  263. UA_WriteRequest wReq;
  264. UA_WriteRequest_init(&wReq);
  265. wReq.nodesToWrite = &wValue;
  266. wReq.nodesToWriteSize = 1;
  267. UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);
  268. UA_StatusCode retval = wResp.responseHeader.serviceResult;
  269. UA_WriteResponse_deleteMembers(&wResp);
  270. return retval;
  271. }
  272. UA_StatusCode
  273. UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
  274. const UA_Int32 *newArrayDimensions,
  275. size_t newArrayDimensionsSize) {
  276. if(!newArrayDimensions)
  277. return UA_STATUSCODE_BADTYPEMISMATCH;
  278. UA_WriteValue wValue;
  279. UA_WriteValue_init(&wValue);
  280. wValue.nodeId = nodeId;
  281. wValue.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
  282. UA_Variant_setArray(&wValue.value.value, (void*)(uintptr_t)newArrayDimensions,
  283. newArrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
  284. wValue.value.hasValue = true;
  285. UA_WriteRequest wReq;
  286. UA_WriteRequest_init(&wReq);
  287. wReq.nodesToWrite = &wValue;
  288. wReq.nodesToWriteSize = 1;
  289. UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);
  290. UA_StatusCode retval = wResp.responseHeader.serviceResult;
  291. UA_WriteResponse_deleteMembers(&wResp);
  292. return retval;
  293. }
  294. /*******************/
  295. /* Read Attributes */
  296. /*******************/
  297. UA_StatusCode
  298. __UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId,
  299. UA_AttributeId attributeId, void *out,
  300. const UA_DataType *outDataType) {
  301. UA_ReadValueId item;
  302. UA_ReadValueId_init(&item);
  303. item.nodeId = *nodeId;
  304. item.attributeId = attributeId;
  305. UA_ReadRequest request;
  306. UA_ReadRequest_init(&request);
  307. request.nodesToRead = &item;
  308. request.nodesToReadSize = 1;
  309. UA_ReadResponse response = UA_Client_Service_read(client, request);
  310. UA_StatusCode retval = response.responseHeader.serviceResult;
  311. if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
  312. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  313. if(retval != UA_STATUSCODE_GOOD) {
  314. UA_ReadResponse_deleteMembers(&response);
  315. return retval;
  316. }
  317. /* Set the StatusCode */
  318. UA_DataValue *res = response.results;
  319. if(res->hasStatus)
  320. retval = res->status;
  321. /* Return early of no value is given */
  322. if(!res->hasValue) {
  323. if(retval == UA_STATUSCODE_GOOD)
  324. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  325. UA_ReadResponse_deleteMembers(&response);
  326. return retval;
  327. }
  328. /* Copy value into out */
  329. if(attributeId == UA_ATTRIBUTEID_VALUE) {
  330. memcpy(out, &res->value, sizeof(UA_Variant));
  331. UA_Variant_init(&res->value);
  332. } else if(UA_Variant_isScalar(&res->value) &&
  333. res->value.type == outDataType) {
  334. memcpy(out, res->value.data, res->value.type->memSize);
  335. UA_free(res->value.data);
  336. res->value.data = NULL;
  337. } else {
  338. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  339. }
  340. UA_ReadResponse_deleteMembers(&response);
  341. return retval;
  342. }
  343. UA_StatusCode
  344. UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
  345. UA_Int32 **outArrayDimensions,
  346. size_t *outArrayDimensionsSize) {
  347. UA_ReadValueId item;
  348. UA_ReadValueId_init(&item);
  349. item.nodeId = nodeId;
  350. item.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
  351. UA_ReadRequest request;
  352. UA_ReadRequest_init(&request);
  353. request.nodesToRead = &item;
  354. request.nodesToReadSize = 1;
  355. UA_ReadResponse response = UA_Client_Service_read(client, request);
  356. UA_StatusCode retval = response.responseHeader.serviceResult;
  357. UA_DataValue *res = response.results;
  358. if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
  359. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  360. if(retval != UA_STATUSCODE_GOOD)
  361. goto cleanup;
  362. if(res->hasStatus != UA_STATUSCODE_GOOD)
  363. retval = res->hasStatus;
  364. else if(!res->hasValue || UA_Variant_isScalar(&res->value))
  365. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  366. if(retval != UA_STATUSCODE_GOOD)
  367. goto cleanup;
  368. if(UA_Variant_isScalar(&res->value) ||
  369. res->value.type != &UA_TYPES[UA_TYPES_INT32]) {
  370. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  371. goto cleanup;
  372. }
  373. *outArrayDimensions = (UA_Int32 *)res->value.data;
  374. *outArrayDimensionsSize = res->value.arrayLength;
  375. UA_free(res->value.data);
  376. res->value.data = NULL;
  377. res->value.arrayLength = 0;
  378. cleanup:
  379. UA_ReadResponse_deleteMembers(&response);
  380. return retval;
  381. }