ua_client_highlevel.c 15 KB

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