ua_client_highlevel.c 16 KB

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