ua_client_highlevel.c 16 KB

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