ua_client.c 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049
  1. #include "ua_types_generated.h"
  2. #include "ua_client.h"
  3. #include "ua_nodeids.h"
  4. #include "ua_securechannel.h"
  5. #include "ua_types_encoding_binary.h"
  6. #include "ua_transport_generated.h"
  7. #include "ua_client_internal.h"
  8. typedef enum {
  9. UA_CLIENTSTATE_READY,
  10. UA_CLIENTSTATE_CONNECTED,
  11. UA_CLIENTSTATE_ERRORED
  12. } UA_Client_State;
  13. struct UA_Client {
  14. /* State */ //maybe it should be visible to user
  15. UA_Client_State state;
  16. /* Connection */
  17. UA_Connection connection;
  18. UA_SecureChannel channel;
  19. UA_String endpointUrl;
  20. UA_UInt32 requestId;
  21. /* Session */
  22. UA_UserTokenPolicy token;
  23. UA_NodeId sessionId;
  24. UA_NodeId authenticationToken;
  25. #ifdef ENABLE_SUBSCRIPTIONS
  26. UA_Int32 monitoredItemHandles;
  27. LIST_HEAD(UA_ListOfUnacknowledgedNotificationNumbers, UA_Client_NotificationsAckNumber_s) pendingNotificationsAcks;
  28. LIST_HEAD(UA_ListOfClientSubscriptionItems, UA_Client_Subscription_s) subscriptions;
  29. #endif
  30. /* Config */
  31. UA_Logger logger;
  32. UA_ClientConfig config;
  33. UA_DateTime scExpiresAt;
  34. };
  35. const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard =
  36. { 5 /* ms receive timout */, 30000, 2000,
  37. {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
  38. .maxMessageSize = 65536, .maxChunkCount = 1}};
  39. UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
  40. UA_Client *client = UA_calloc(1, sizeof(UA_Client));
  41. if(!client)
  42. return UA_NULL;
  43. UA_Client_init(client, config, logger);
  44. return client;
  45. }
  46. void UA_Client_reset(UA_Client* client){
  47. UA_Client_deleteMembers(client);
  48. UA_Client_init(client, client->config, client->logger);
  49. }
  50. void UA_Client_init(UA_Client* client, UA_ClientConfig config, UA_Logger logger){
  51. client->state = UA_CLIENTSTATE_READY;
  52. UA_Connection_init(&client->connection);
  53. UA_SecureChannel_init(&client->channel);
  54. client->channel.connection = &client->connection;
  55. UA_String_init(&client->endpointUrl);
  56. client->requestId = 0;
  57. UA_NodeId_init(&client->authenticationToken);
  58. client->logger = logger;
  59. client->config = config;
  60. client->scExpiresAt = 0;
  61. #ifdef ENABLE_SUBSCRIPTIONS
  62. client->monitoredItemHandles = 0;
  63. LIST_INIT(&client->pendingNotificationsAcks);
  64. LIST_INIT(&client->subscriptions);
  65. #endif
  66. }
  67. void UA_Client_deleteMembers(UA_Client* client){
  68. if(client->state == UA_CLIENTSTATE_READY) //initialized client has no dynamic memory allocated
  69. return;
  70. UA_Connection_deleteMembers(&client->connection);
  71. UA_SecureChannel_deleteMembersCleanup(&client->channel);
  72. if(client->endpointUrl.data)
  73. UA_String_deleteMembers(&client->endpointUrl);
  74. UA_UserTokenPolicy_deleteMembers(&client->token);
  75. }
  76. void UA_Client_delete(UA_Client* client){
  77. if(client->state != UA_CLIENTSTATE_READY)
  78. UA_Client_deleteMembers(client);
  79. UA_free(client);
  80. }
  81. static UA_StatusCode HelAckHandshake(UA_Client *c) {
  82. UA_TcpMessageHeader messageHeader;
  83. messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_HELF;
  84. UA_TcpHelloMessage hello;
  85. UA_String_copy(&c->endpointUrl, &hello.endpointUrl); /* must be less than 4096 bytes */
  86. UA_Connection *conn = &c->connection;
  87. hello.maxChunkCount = conn->localConf.maxChunkCount;
  88. hello.maxMessageSize = conn->localConf.maxMessageSize;
  89. hello.protocolVersion = conn->localConf.protocolVersion;
  90. hello.receiveBufferSize = conn->localConf.recvBufferSize;
  91. hello.sendBufferSize = conn->localConf.sendBufferSize;
  92. UA_ByteString message;
  93. UA_StatusCode retval = c->connection.getBuffer(&c->connection, &message);
  94. if(retval != UA_STATUSCODE_GOOD)
  95. return retval;
  96. size_t offset = 8;
  97. retval |= UA_TcpHelloMessage_encodeBinary(&hello, &message, &offset);
  98. messageHeader.messageSize = offset;
  99. offset = 0;
  100. retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &message, &offset);
  101. UA_TcpHelloMessage_deleteMembers(&hello);
  102. if(retval != UA_STATUSCODE_GOOD) {
  103. c->connection.releaseBuffer(&c->connection, &message);
  104. return retval;
  105. }
  106. retval = c->connection.write(&c->connection, &message, messageHeader.messageSize);
  107. if(retval != UA_STATUSCODE_GOOD) {
  108. c->connection.releaseBuffer(&c->connection, &message);
  109. return retval;
  110. }
  111. UA_ByteString reply;
  112. UA_ByteString_init(&reply);
  113. do {
  114. retval = c->connection.recv(&c->connection, &reply, c->config.timeout);
  115. if(retval != UA_STATUSCODE_GOOD)
  116. return retval;
  117. } while(!reply.data);
  118. offset = 0;
  119. UA_TcpMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
  120. UA_TcpAcknowledgeMessage ackMessage;
  121. retval = UA_TcpAcknowledgeMessage_decodeBinary(&reply, &offset, &ackMessage);
  122. UA_ByteString_deleteMembers(&reply);
  123. if(retval != UA_STATUSCODE_GOOD)
  124. return retval;
  125. conn->remoteConf.maxChunkCount = ackMessage.maxChunkCount;
  126. conn->remoteConf.maxMessageSize = ackMessage.maxMessageSize;
  127. conn->remoteConf.protocolVersion = ackMessage.protocolVersion;
  128. conn->remoteConf.recvBufferSize = ackMessage.receiveBufferSize;
  129. conn->remoteConf.sendBufferSize = ackMessage.sendBufferSize;
  130. conn->state = UA_CONNECTION_ESTABLISHED;
  131. return UA_STATUSCODE_GOOD;
  132. }
  133. static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
  134. UA_SecureConversationMessageHeader messageHeader;
  135. messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
  136. messageHeader.secureChannelId = 0;
  137. UA_SequenceHeader seqHeader;
  138. seqHeader.sequenceNumber = ++client->channel.sequenceNumber;
  139. seqHeader.requestId = ++client->requestId;
  140. UA_AsymmetricAlgorithmSecurityHeader asymHeader;
  141. UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader);
  142. asymHeader.securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
  143. /* id of opensecurechannelrequest */
  144. UA_NodeId requestType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
  145. UA_OpenSecureChannelRequest opnSecRq;
  146. UA_OpenSecureChannelRequest_init(&opnSecRq);
  147. opnSecRq.requestHeader.timestamp = UA_DateTime_now();
  148. opnSecRq.requestHeader.authenticationToken = client->authenticationToken;
  149. opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
  150. if(renew) {
  151. opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW;
  152. } else {
  153. opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
  154. UA_SecureChannel_generateNonce(&client->channel.clientNonce);
  155. UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce);
  156. opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
  157. }
  158. UA_ByteString message;
  159. UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message);
  160. if(retval != UA_STATUSCODE_GOOD) {
  161. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
  162. UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
  163. return retval;
  164. }
  165. size_t offset = 12;
  166. retval = UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &message, &offset);
  167. retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
  168. retval |= UA_NodeId_encodeBinary(&requestType, &message, &offset);
  169. retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset);
  170. messageHeader.messageHeader.messageSize = offset;
  171. offset = 0;
  172. retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &message, &offset);
  173. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
  174. UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
  175. if(retval != UA_STATUSCODE_GOOD) {
  176. client->connection.releaseBuffer(&client->connection, &message);
  177. return retval;
  178. }
  179. retval = client->connection.write(&client->connection, &message, messageHeader.messageHeader.messageSize);
  180. if(retval != UA_STATUSCODE_GOOD) {
  181. client->connection.releaseBuffer(&client->connection, &message);
  182. return retval;
  183. }
  184. UA_ByteString reply;
  185. UA_ByteString_init(&reply);
  186. do {
  187. retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
  188. if(retval != UA_STATUSCODE_GOOD)
  189. return retval;
  190. } while(!reply.data);
  191. offset = 0;
  192. UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
  193. UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &asymHeader);
  194. UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
  195. UA_NodeId_decodeBinary(&reply, &offset, &requestType);
  196. UA_NodeId expectedRequest = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
  197. UA_ENCODINGOFFSET_BINARY);
  198. if(!UA_NodeId_equal(&requestType, &expectedRequest)) {
  199. UA_ByteString_deleteMembers(&reply);
  200. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
  201. UA_NodeId_deleteMembers(&requestType);
  202. UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT,
  203. "Reply answers the wrong request. Expected OpenSecureChannelResponse.");
  204. return UA_STATUSCODE_BADINTERNALERROR;
  205. }
  206. UA_OpenSecureChannelResponse response;
  207. UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response);
  208. client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000;
  209. UA_ByteString_deleteMembers(&reply);
  210. retval = response.responseHeader.serviceResult;
  211. if(!renew && retval == UA_STATUSCODE_GOOD) {
  212. UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel.securityToken);
  213. UA_ByteString_deleteMembers(&client->channel.serverNonce); // if the handshake is repeated
  214. UA_ByteString_copy(&response.serverNonce, &client->channel.serverNonce);
  215. }
  216. UA_OpenSecureChannelResponse_deleteMembers(&response);
  217. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
  218. return retval;
  219. }
  220. /** If the request fails, then the response is cast to UA_ResponseHeader (at the beginning of every
  221. response) and filled with the appropriate error code */
  222. static void synchronousRequest(UA_Client *client, void *request, const UA_DataType *requestType,
  223. void *response, const UA_DataType *responseType) {
  224. /* Check if sc needs to be renewed */
  225. if(client->scExpiresAt - UA_DateTime_now() <= client->config.timeToRenewSecureChannel * 10000 )
  226. UA_Client_renewSecureChannel(client);
  227. /* Copy authenticationToken token to request header */
  228. typedef struct {
  229. UA_RequestHeader requestHeader;
  230. } headerOnlyRequest;
  231. /* The cast is valid, since all requests start with a requestHeader */
  232. UA_NodeId_copy(&client->authenticationToken, &((headerOnlyRequest*)request)->requestHeader.authenticationToken);
  233. if(!response)
  234. return;
  235. UA_init(response, responseType);
  236. /* Send the request */
  237. UA_UInt32 requestId = ++client->requestId;
  238. UA_StatusCode retval = UA_SecureChannel_sendBinaryMessage(&client->channel, requestId,
  239. request, requestType);
  240. UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response;
  241. if(retval) {
  242. if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED)
  243. respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE;
  244. else
  245. respHeader->serviceResult = retval;
  246. client->state = UA_CLIENTSTATE_ERRORED;
  247. return;
  248. }
  249. /* Retrieve the response */
  250. // Todo: push this into the generic securechannel implementation for client and server
  251. UA_ByteString reply;
  252. UA_ByteString_init(&reply);
  253. do {
  254. retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
  255. if(retval != UA_STATUSCODE_GOOD) {
  256. respHeader->serviceResult = retval;
  257. client->state = UA_CLIENTSTATE_ERRORED;
  258. return;
  259. }
  260. } while(!reply.data);
  261. size_t offset = 0;
  262. UA_SecureConversationMessageHeader msgHeader;
  263. retval |= UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &msgHeader);
  264. UA_SymmetricAlgorithmSecurityHeader symHeader;
  265. retval |= UA_SymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &symHeader);
  266. UA_SequenceHeader seqHeader;
  267. retval |= UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
  268. UA_NodeId responseId;
  269. retval |= UA_NodeId_decodeBinary(&reply, &offset, &responseId);
  270. UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
  271. UA_ENCODINGOFFSET_BINARY);
  272. if(retval != UA_STATUSCODE_GOOD)
  273. goto finish;
  274. /* Todo: we need to demux responses since a publish responses may come at any time */
  275. if(!UA_NodeId_equal(&responseId, &expectedNodeId) || seqHeader.requestId != requestId) {
  276. if(responseId.identifier.numeric != UA_NS0ID_SERVICEFAULT + UA_ENCODINGOFFSET_BINARY) {
  277. UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT,
  278. "Reply answers the wrong request. Expected ns=%i,i=%i. But retrieved ns=%i,i=%i",
  279. expectedNodeId.namespaceIndex, expectedNodeId.identifier.numeric,
  280. responseId.namespaceIndex, responseId.identifier.numeric);
  281. respHeader->serviceResult = UA_STATUSCODE_BADINTERNALERROR;
  282. } else
  283. retval = UA_decodeBinary(&reply, &offset, respHeader, &UA_TYPES[UA_TYPES_SERVICEFAULT]);
  284. goto finish;
  285. }
  286. retval = UA_decodeBinary(&reply, &offset, response, responseType);
  287. if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED)
  288. retval = UA_STATUSCODE_BADRESPONSETOOLARGE;
  289. finish:
  290. UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
  291. UA_ByteString_deleteMembers(&reply);
  292. if(retval != UA_STATUSCODE_GOOD){
  293. client->state = UA_CLIENTSTATE_ERRORED;
  294. respHeader->serviceResult = retval;
  295. }
  296. }
  297. static UA_StatusCode ActivateSession(UA_Client *client) {
  298. UA_ActivateSessionRequest request;
  299. UA_ActivateSessionRequest_init(&request);
  300. request.requestHeader.requestHandle = 2; //TODO: is it a magic number?
  301. request.requestHeader.authenticationToken = client->authenticationToken;
  302. request.requestHeader.timestamp = UA_DateTime_now();
  303. request.requestHeader.timeoutHint = 10000;
  304. UA_AnonymousIdentityToken identityToken;
  305. UA_AnonymousIdentityToken_init(&identityToken);
  306. UA_String_copy(&client->token.policyId, &identityToken.policyId);
  307. //manual ExtensionObject encoding of the identityToken
  308. request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
  309. request.userIdentityToken.typeId = UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN].typeId;
  310. request.userIdentityToken.typeId.identifier.numeric+=UA_ENCODINGOFFSET_BINARY;
  311. UA_ByteString_newMembers(&request.userIdentityToken.body, identityToken.policyId.length+4);
  312. size_t offset = 0;
  313. UA_ByteString_encodeBinary(&identityToken.policyId,&request.userIdentityToken.body,&offset);
  314. UA_ActivateSessionResponse response;
  315. synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
  316. &response, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]);
  317. UA_AnonymousIdentityToken_deleteMembers(&identityToken);
  318. UA_ActivateSessionRequest_deleteMembers(&request);
  319. UA_ActivateSessionResponse_deleteMembers(&response);
  320. return response.responseHeader.serviceResult; // not deleted
  321. }
  322. static UA_StatusCode EndpointsHandshake(UA_Client *client) {
  323. UA_GetEndpointsRequest request;
  324. UA_GetEndpointsRequest_init(&request);
  325. UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
  326. request.requestHeader.timestamp = UA_DateTime_now();
  327. request.requestHeader.timeoutHint = 10000;
  328. UA_String_copy(&client->endpointUrl, &request.endpointUrl);
  329. request.profileUrisSize = 1;
  330. request.profileUris = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], request.profileUrisSize);
  331. *request.profileUris = UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
  332. UA_GetEndpointsResponse response;
  333. UA_GetEndpointsResponse_init(&response);
  334. synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
  335. &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);
  336. UA_Boolean endpointFound = UA_FALSE;
  337. UA_Boolean tokenFound = UA_FALSE;
  338. for(UA_Int32 i=0; i<response.endpointsSize; ++i){
  339. UA_EndpointDescription* endpoint = &response.endpoints[i];
  340. /* look out for an endpoint without security */
  341. if(!UA_String_equal(&endpoint->securityPolicyUri,
  342. &UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None")))
  343. continue;
  344. endpointFound = UA_TRUE;
  345. /* endpoint with no security found */
  346. /* look for a user token policy with an anonymous token */
  347. for(UA_Int32 j=0; j<endpoint->userIdentityTokensSize; ++j) {
  348. UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j];
  349. if(userToken->tokenType != UA_USERTOKENTYPE_ANONYMOUS)
  350. continue;
  351. tokenFound = UA_TRUE;
  352. UA_UserTokenPolicy_copy(userToken, &client->token);
  353. break;
  354. }
  355. }
  356. UA_GetEndpointsRequest_deleteMembers(&request);
  357. UA_GetEndpointsResponse_deleteMembers(&response);
  358. if(!endpointFound){
  359. UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No suitable endpoint found");
  360. return UA_STATUSCODE_BADINTERNALERROR;
  361. }
  362. if(!tokenFound){
  363. UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No anonymous token found");
  364. return UA_STATUSCODE_BADINTERNALERROR;
  365. }
  366. return response.responseHeader.serviceResult;
  367. }
  368. static UA_StatusCode SessionHandshake(UA_Client *client) {
  369. UA_CreateSessionRequest request;
  370. UA_CreateSessionRequest_init(&request);
  371. // todo: is this needed for all requests?
  372. UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
  373. request.requestHeader.timestamp = UA_DateTime_now();
  374. request.requestHeader.timeoutHint = 10000;
  375. UA_ByteString_copy(&client->channel.clientNonce, &request.clientNonce);
  376. request.requestedSessionTimeout = 1200000;
  377. request.maxResponseMessageSize = UA_INT32_MAX;
  378. UA_CreateSessionResponse response;
  379. UA_CreateSessionResponse_init(&response);
  380. synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
  381. &response, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]);
  382. UA_NodeId_copy(&response.authenticationToken, &client->authenticationToken);
  383. UA_CreateSessionRequest_deleteMembers(&request);
  384. UA_CreateSessionResponse_deleteMembers(&response);
  385. return response.responseHeader.serviceResult; // not deleted
  386. }
  387. static UA_StatusCode CloseSession(UA_Client *client) {
  388. UA_CloseSessionRequest request;
  389. UA_CloseSessionRequest_init(&request);
  390. request.requestHeader.timestamp = UA_DateTime_now();
  391. request.requestHeader.timeoutHint = 10000;
  392. request.deleteSubscriptions = UA_TRUE;
  393. UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
  394. UA_CreateSessionResponse response;
  395. synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
  396. &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]);
  397. UA_CloseSessionRequest_deleteMembers(&request);
  398. UA_CloseSessionResponse_deleteMembers(&response);
  399. return response.responseHeader.serviceResult; // not deleted
  400. }
  401. static UA_StatusCode CloseSecureChannel(UA_Client *client) {
  402. UA_SecureChannel *channel = &client->channel;
  403. UA_CloseSecureChannelRequest request;
  404. UA_CloseSecureChannelRequest_init(&request);
  405. request.requestHeader.requestHandle = 1; //TODO: magic number?
  406. request.requestHeader.timestamp = UA_DateTime_now();
  407. request.requestHeader.timeoutHint = 10000;
  408. request.requestHeader.authenticationToken = client->authenticationToken;
  409. UA_SecureConversationMessageHeader msgHeader;
  410. msgHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_CLOF;
  411. msgHeader.secureChannelId = client->channel.securityToken.channelId;
  412. UA_SymmetricAlgorithmSecurityHeader symHeader;
  413. symHeader.tokenId = channel->securityToken.tokenId;
  414. UA_SequenceHeader seqHeader;
  415. seqHeader.sequenceNumber = ++channel->sequenceNumber;
  416. seqHeader.requestId = ++client->requestId;
  417. UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CLOSESECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
  418. UA_ByteString message;
  419. UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message);
  420. if(retval != UA_STATUSCODE_GOOD)
  421. return retval;
  422. size_t offset = 12;
  423. retval |= UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symHeader, &message, &offset);
  424. retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
  425. retval |= UA_NodeId_encodeBinary(&typeId, &message, &offset);
  426. retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST], &message, &offset);
  427. msgHeader.messageHeader.messageSize = offset;
  428. offset = 0;
  429. retval |= UA_SecureConversationMessageHeader_encodeBinary(&msgHeader, &message, &offset);
  430. if(retval != UA_STATUSCODE_GOOD) {
  431. client->connection.releaseBuffer(&client->connection, &message);
  432. return retval;
  433. }
  434. retval = client->connection.write(&client->connection, &message, msgHeader.messageHeader.messageSize);
  435. if(retval != UA_STATUSCODE_GOOD)
  436. client->connection.releaseBuffer(&client->connection, &message);
  437. return retval;
  438. }
  439. /*************************/
  440. /* User-Facing Functions */
  441. /*************************/
  442. UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc, char *endpointUrl) {
  443. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  444. /** make the function more convenient to the end-user **/
  445. if(client->state == UA_CLIENTSTATE_CONNECTED){
  446. UA_Client_disconnect(client);
  447. }
  448. if(client->state == UA_CLIENTSTATE_ERRORED){
  449. UA_Client_reset(client);
  450. }
  451. client->connection = connectFunc(UA_ConnectionConfig_standard, endpointUrl, &client->logger);
  452. if(client->connection.state != UA_CONNECTION_OPENING){
  453. retval = UA_STATUSCODE_BADCONNECTIONCLOSED;
  454. goto cleanup;
  455. }
  456. client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
  457. if(client->endpointUrl.length < 0){
  458. retval = UA_STATUSCODE_BADOUTOFMEMORY;
  459. goto cleanup;
  460. }
  461. client->connection.localConf = client->config.localConnectionConfig;
  462. retval = HelAckHandshake(client);
  463. if(retval == UA_STATUSCODE_GOOD)
  464. retval = SecureChannelHandshake(client, UA_FALSE);
  465. if(retval == UA_STATUSCODE_GOOD)
  466. retval = EndpointsHandshake(client);
  467. if(retval == UA_STATUSCODE_GOOD)
  468. retval = SessionHandshake(client);
  469. if(retval == UA_STATUSCODE_GOOD)
  470. retval = ActivateSession(client);
  471. if(retval == UA_STATUSCODE_GOOD){
  472. client->connection.state = UA_CONNECTION_ESTABLISHED;
  473. client->state = UA_CLIENTSTATE_CONNECTED;
  474. }else{
  475. goto cleanup;
  476. }
  477. return retval;
  478. cleanup:
  479. client->state = UA_CLIENTSTATE_ERRORED;
  480. UA_Client_reset(client);
  481. return retval;
  482. }
  483. UA_StatusCode UA_Client_disconnect(UA_Client *client) {
  484. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  485. if(client->channel.connection->state == UA_CONNECTION_ESTABLISHED){
  486. retval = CloseSession(client);
  487. if(retval == UA_STATUSCODE_GOOD)
  488. retval = CloseSecureChannel(client);
  489. }
  490. UA_Client_reset(client);
  491. return retval;
  492. }
  493. UA_StatusCode UA_Client_renewSecureChannel(UA_Client *client) {
  494. return SecureChannelHandshake(client, UA_TRUE);
  495. }
  496. UA_ReadResponse UA_Client_read(UA_Client *client, UA_ReadRequest *request) {
  497. UA_ReadResponse response;
  498. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_READREQUEST], &response,
  499. &UA_TYPES[UA_TYPES_READRESPONSE]);
  500. return response;
  501. }
  502. UA_WriteResponse UA_Client_write(UA_Client *client, UA_WriteRequest *request) {
  503. UA_WriteResponse response;
  504. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_WRITEREQUEST], &response,
  505. &UA_TYPES[UA_TYPES_WRITERESPONSE]);
  506. return response;
  507. }
  508. UA_BrowseResponse UA_Client_browse(UA_Client *client, UA_BrowseRequest *request) {
  509. UA_BrowseResponse response;
  510. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
  511. &UA_TYPES[UA_TYPES_BROWSERESPONSE]);
  512. return response;
  513. }
  514. UA_BrowseNextResponse UA_Client_browseNext(UA_Client *client, UA_BrowseNextRequest *request) {
  515. UA_BrowseNextResponse response;
  516. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], &response,
  517. &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]);
  518. return response;
  519. }
  520. UA_TranslateBrowsePathsToNodeIdsResponse
  521. UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
  522. UA_TranslateBrowsePathsToNodeIdsRequest *request) {
  523. UA_TranslateBrowsePathsToNodeIdsResponse response;
  524. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST],
  525. &response, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]);
  526. return response;
  527. }
  528. UA_AddNodesResponse UA_Client_addNodes(UA_Client *client, UA_AddNodesRequest *request) {
  529. UA_AddNodesResponse response;
  530. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_ADDNODESREQUEST],
  531. &response, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]);
  532. return response;
  533. }
  534. UA_AddReferencesResponse UA_Client_addReferences(UA_Client *client, UA_AddReferencesRequest *request) {
  535. UA_AddReferencesResponse response;
  536. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST],
  537. &response, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]);
  538. return response;
  539. }
  540. UA_DeleteNodesResponse UA_Client_deleteNodes(UA_Client *client, UA_DeleteNodesRequest *request) {
  541. UA_DeleteNodesResponse response;
  542. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETENODESREQUEST],
  543. &response, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]);
  544. return response;
  545. }
  546. UA_DeleteReferencesResponse UA_Client_deleteReferences(UA_Client *client, UA_DeleteReferencesRequest *request) {
  547. UA_DeleteReferencesResponse response;
  548. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST],
  549. &response, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]);
  550. return response;
  551. }
  552. #ifdef ENABLE_SUBSCRIPTIONS
  553. UA_CreateSubscriptionResponse UA_Client_createSubscription(UA_Client *client, UA_CreateSubscriptionRequest *request) {
  554. UA_CreateSubscriptionResponse response;
  555. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST],
  556. &response, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]);
  557. return response;
  558. }
  559. UA_DeleteSubscriptionsResponse UA_Client_deleteSubscriptions(UA_Client *client, UA_DeleteSubscriptionsRequest *request) {
  560. UA_DeleteSubscriptionsResponse response;
  561. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST],
  562. &response, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]);
  563. return response;
  564. }
  565. UA_ModifySubscriptionResponse UA_Client_modifySubscription(UA_Client *client, UA_ModifySubscriptionRequest *request) {
  566. UA_ModifySubscriptionResponse response;
  567. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST],
  568. &response, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]);
  569. return response;
  570. }
  571. UA_CreateMonitoredItemsResponse UA_Client_createMonitoredItems(UA_Client *client, UA_CreateMonitoredItemsRequest *request) {
  572. UA_CreateMonitoredItemsResponse response;
  573. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST],
  574. &response, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]);
  575. return response;
  576. }
  577. UA_DeleteMonitoredItemsResponse UA_Client_deleteMonitoredItems(UA_Client *client, UA_DeleteMonitoredItemsRequest *request) {
  578. UA_DeleteMonitoredItemsResponse response;
  579. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST],
  580. &response, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]);
  581. return response;
  582. }
  583. UA_PublishResponse UA_Client_publish(UA_Client *client, UA_PublishRequest *request) {
  584. UA_PublishResponse response;
  585. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_PUBLISHREQUEST],
  586. &response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
  587. return response;
  588. }
  589. UA_Int32 UA_Client_newSubscription(UA_Client *client, UA_Int32 publishInterval) {
  590. UA_Int32 retval;
  591. UA_CreateSubscriptionRequest aReq;
  592. UA_CreateSubscriptionResponse aRes;
  593. UA_CreateSubscriptionRequest_init(&aReq);
  594. UA_CreateSubscriptionResponse_init(&aRes);
  595. aReq.maxNotificationsPerPublish = 10;
  596. aReq.priority = 0;
  597. aReq.publishingEnabled = UA_TRUE;
  598. aReq.requestedLifetimeCount = 100;
  599. aReq.requestedMaxKeepAliveCount = 10;
  600. aReq.requestedPublishingInterval = publishInterval;
  601. aRes = UA_Client_createSubscription(client, &aReq);
  602. if (aRes.responseHeader.serviceResult == UA_STATUSCODE_GOOD) {
  603. UA_Client_Subscription *newSub = UA_malloc(sizeof(UA_Client_Subscription));
  604. LIST_INIT(&newSub->MonitoredItems);
  605. newSub->LifeTime = aRes.revisedLifetimeCount;
  606. newSub->KeepAliveCount = aRes.revisedMaxKeepAliveCount;
  607. newSub->PublishingInterval = aRes.revisedPublishingInterval;
  608. newSub->SubscriptionID = aRes.subscriptionId;
  609. newSub->NotificationsPerPublish = aReq.maxNotificationsPerPublish;
  610. newSub->Priority = aReq.priority;
  611. retval = newSub->SubscriptionID;
  612. LIST_INSERT_HEAD(&(client->subscriptions), newSub, listEntry);
  613. } else
  614. retval = 0;
  615. UA_CreateSubscriptionResponse_deleteMembers(&aRes);
  616. UA_CreateSubscriptionRequest_deleteMembers(&aReq);
  617. return retval;
  618. }
  619. UA_StatusCode UA_Client_removeSubscription(UA_Client *client, UA_UInt32 subscriptionId) {
  620. UA_Client_Subscription *sub;
  621. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  622. LIST_FOREACH(sub, &(client->subscriptions), listEntry) {
  623. if (sub->SubscriptionID == subscriptionId)
  624. break;
  625. }
  626. // Problem? We do not have this subscription registeres. Maybe the server should
  627. // be consulted at this point?
  628. if (sub == NULL)
  629. return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
  630. UA_DeleteSubscriptionsRequest request;
  631. UA_DeleteSubscriptionsResponse response;
  632. UA_DeleteSubscriptionsRequest_init(&request);
  633. UA_DeleteSubscriptionsResponse_init(&response);
  634. request.subscriptionIdsSize=1;
  635. request.subscriptionIds = (UA_UInt32 *) UA_malloc(sizeof(UA_UInt32));
  636. *(request.subscriptionIds) = sub->SubscriptionID;
  637. UA_Client_MonitoredItem *mon, *tmpmon;
  638. LIST_FOREACH_SAFE(mon, &(sub->MonitoredItems), listEntry, tmpmon) {
  639. retval |= UA_Client_unMonitorItemChanges(client, sub->SubscriptionID, mon->MonitoredItemId);
  640. }
  641. if (retval != UA_STATUSCODE_GOOD){
  642. UA_DeleteSubscriptionsRequest_deleteMembers(&request);
  643. return retval;
  644. }
  645. response = UA_Client_deleteSubscriptions(client, &request);
  646. if (response.resultsSize > 0)
  647. retval = response.results[0];
  648. else
  649. retval = response.responseHeader.serviceResult;
  650. if (retval == UA_STATUSCODE_GOOD) {
  651. LIST_REMOVE(sub, listEntry);
  652. UA_free(sub);
  653. }
  654. UA_DeleteSubscriptionsRequest_deleteMembers(&request);
  655. UA_DeleteSubscriptionsResponse_deleteMembers(&response);
  656. return retval;
  657. }
  658. UA_UInt32 UA_Client_monitorItemChanges(UA_Client *client, UA_UInt32 subscriptionId,
  659. UA_NodeId nodeId, UA_UInt32 attributeID, void *handlingFunction) {
  660. UA_Client_Subscription *sub;
  661. UA_StatusCode retval = 0;
  662. LIST_FOREACH(sub, &(client->subscriptions), listEntry) {
  663. if (sub->SubscriptionID == subscriptionId)
  664. break;
  665. }
  666. // Maybe the same problem as in DeleteSubscription... ask the server?
  667. if (sub == NULL)
  668. return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
  669. UA_CreateMonitoredItemsRequest request;
  670. UA_CreateMonitoredItemsResponse response;
  671. UA_CreateMonitoredItemsRequest_init(&request);
  672. UA_CreateMonitoredItemsResponse_init(&response);
  673. request.subscriptionId = subscriptionId;
  674. request.itemsToCreateSize = 1;
  675. request.itemsToCreate = UA_MonitoredItemCreateRequest_new();
  676. UA_NodeId_copy(&nodeId, &((request.itemsToCreate[0]).itemToMonitor.nodeId));
  677. (request.itemsToCreate[0]).itemToMonitor.attributeId = attributeID;
  678. (request.itemsToCreate[0]).monitoringMode = UA_MONITORINGMODE_REPORTING;
  679. (request.itemsToCreate[0]).requestedParameters.clientHandle = ++(client->monitoredItemHandles);
  680. (request.itemsToCreate[0]).requestedParameters.samplingInterval = sub->PublishingInterval;
  681. (request.itemsToCreate[0]).requestedParameters.discardOldest = UA_TRUE;
  682. (request.itemsToCreate[0]).requestedParameters.queueSize = 1;
  683. // Filter can be left void for now, only changes are supported (UA_Expert does the same with changeItems)
  684. response = UA_Client_createMonitoredItems(client, &request);
  685. // slight misuse of retval here to check if the deletion was successfull.
  686. if (response.resultsSize == 0)
  687. retval = response.responseHeader.serviceResult;
  688. else
  689. retval = response.results[0].statusCode;
  690. if (retval == UA_STATUSCODE_GOOD) {
  691. UA_Client_MonitoredItem *newMon = (UA_Client_MonitoredItem *) UA_malloc(sizeof(UA_Client_MonitoredItem));
  692. newMon->MonitoringMode = UA_MONITORINGMODE_REPORTING;
  693. UA_NodeId_copy(&nodeId, &(newMon->monitoredNodeId));
  694. newMon->AttributeID = attributeID;
  695. newMon->ClientHandle = client->monitoredItemHandles;
  696. newMon->SamplingInterval = sub->PublishingInterval;
  697. newMon->QueueSize = 1;
  698. newMon->DiscardOldest = UA_TRUE;
  699. newMon->handler = handlingFunction;
  700. newMon->MonitoredItemId = response.results[0].monitoredItemId;
  701. LIST_INSERT_HEAD(&(sub->MonitoredItems), newMon, listEntry);
  702. retval = newMon->MonitoredItemId ;
  703. }
  704. else {
  705. retval = 0;
  706. }
  707. UA_CreateMonitoredItemsRequest_deleteMembers(&request);
  708. UA_CreateMonitoredItemsResponse_deleteMembers(&response);
  709. return retval;
  710. }
  711. UA_StatusCode UA_Client_unMonitorItemChanges(UA_Client *client, UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId ) {
  712. UA_Client_Subscription *sub;
  713. UA_StatusCode retval = 0;
  714. LIST_FOREACH(sub, &(client->subscriptions), listEntry) {
  715. if (sub->SubscriptionID == subscriptionId)
  716. break;
  717. }
  718. // Maybe the same problem as in DeleteSubscription... ask the server?
  719. if (sub == NULL)
  720. return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
  721. UA_Client_MonitoredItem *mon, *tmpmon;
  722. LIST_FOREACH_SAFE(mon, &(sub->MonitoredItems), listEntry, tmpmon) {
  723. if (mon->MonitoredItemId == monitoredItemId)
  724. break;
  725. }
  726. // Also... ask the server?
  727. if(mon==NULL) {
  728. return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
  729. }
  730. UA_DeleteMonitoredItemsRequest request;
  731. UA_DeleteMonitoredItemsResponse response;
  732. UA_DeleteMonitoredItemsRequest_init(&request);
  733. UA_DeleteMonitoredItemsResponse_init(&response);
  734. request.subscriptionId = sub->SubscriptionID;
  735. request.monitoredItemIdsSize = 1;
  736. request.monitoredItemIds = (UA_UInt32 *) UA_malloc(sizeof(UA_UInt32));
  737. request.monitoredItemIds[0] = mon->MonitoredItemId;
  738. response = UA_Client_deleteMonitoredItems(client, &request);
  739. if (response.resultsSize > 1)
  740. retval = response.results[0];
  741. else
  742. retval = response.responseHeader.serviceResult;
  743. if (retval == 0) {
  744. LIST_REMOVE(mon, listEntry);
  745. UA_NodeId_deleteMembers(&mon->monitoredNodeId);
  746. UA_free(mon);
  747. }
  748. UA_DeleteMonitoredItemsRequest_deleteMembers(&request);
  749. UA_DeleteMonitoredItemsResponse_deleteMembers(&response);
  750. return retval;
  751. }
  752. UA_Boolean UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response) {
  753. UA_Client_Subscription *sub;
  754. UA_Client_MonitoredItem *mon;
  755. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  756. if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  757. return UA_FALSE;
  758. // Check if the server has acknowledged any of our ACKS
  759. // Note that a list of serverside status codes may be send without valid publish data, i.e.
  760. // during keepalives or no data availability
  761. UA_Client_NotificationsAckNumber *tmpAck = client->pendingNotificationsAcks.lh_first;
  762. UA_Client_NotificationsAckNumber *nxtAck = tmpAck;
  763. for(int i=0; i<response.resultsSize && nxtAck != NULL; i++) {
  764. tmpAck = nxtAck;
  765. nxtAck = tmpAck->listEntry.le_next;
  766. if (response.results[i] == UA_STATUSCODE_GOOD) {
  767. LIST_REMOVE(tmpAck, listEntry);
  768. UA_free(tmpAck);
  769. }
  770. }
  771. if(response.subscriptionId == 0)
  772. return UA_FALSE;
  773. LIST_FOREACH(sub, &(client->subscriptions), listEntry) {
  774. if (sub->SubscriptionID == response.subscriptionId)
  775. break;
  776. }
  777. if (sub == NULL)
  778. return UA_FALSE;
  779. UA_NotificationMessage msg = response.notificationMessage;
  780. UA_DataChangeNotification dataChangeNotification;
  781. size_t decodingOffset = 0;
  782. for (int k=0; k<msg.notificationDataSize; k++) {
  783. if (msg.notificationData[k].encoding == UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING) {
  784. if (msg.notificationData[k].typeId.namespaceIndex == 0 && msg.notificationData[k].typeId.identifier.numeric == 811 ) {
  785. // This is a dataChangeNotification
  786. retval |= UA_DataChangeNotification_decodeBinary(&(msg.notificationData[k].body), &decodingOffset, &dataChangeNotification);
  787. UA_MonitoredItemNotification *mitemNot;
  788. for(int i=0; i<dataChangeNotification.monitoredItemsSize; i++) {
  789. mitemNot = &dataChangeNotification.monitoredItems[i];
  790. // find this client handle
  791. LIST_FOREACH(mon, &(sub->MonitoredItems), listEntry) {
  792. if (mon->ClientHandle == mitemNot->clientHandle) {
  793. mon->handler(mitemNot->clientHandle, &(mitemNot->value));
  794. break;
  795. }
  796. }
  797. }
  798. UA_DataChangeNotification_deleteMembers(&dataChangeNotification);
  799. }
  800. else if (msg.notificationData[k].typeId.namespaceIndex == 0 && msg.notificationData[k].typeId.identifier.numeric == 820 ) {
  801. //FIXME: This is a statusChangeNotification (not supported yet)
  802. continue;
  803. }
  804. else if (msg.notificationData[k].typeId.namespaceIndex == 0 && msg.notificationData[k].typeId.identifier.numeric == 916 ) {
  805. //FIXME: This is an EventNotification
  806. continue;
  807. }
  808. }
  809. }
  810. // We processed this message, add it to the list of pending acks (but make sure it's not in the list first)
  811. LIST_FOREACH(tmpAck, &(client->pendingNotificationsAcks), listEntry) {
  812. if (tmpAck->subAck.sequenceNumber == msg.sequenceNumber &&
  813. tmpAck->subAck.subscriptionId == response.subscriptionId)
  814. break;
  815. }
  816. if (tmpAck == NULL ){
  817. tmpAck = (UA_Client_NotificationsAckNumber *) malloc(sizeof(UA_Client_NotificationsAckNumber));
  818. tmpAck->subAck.sequenceNumber = msg.sequenceNumber;
  819. tmpAck->subAck.subscriptionId = sub->SubscriptionID;
  820. LIST_INSERT_HEAD(&(client->pendingNotificationsAcks), tmpAck, listEntry);
  821. }
  822. return response.moreNotifications;
  823. }
  824. void UA_Client_doPublish(UA_Client *client) {
  825. UA_PublishRequest request;
  826. UA_PublishResponse response;
  827. UA_Client_NotificationsAckNumber *ack;
  828. UA_Boolean moreNotifications = UA_TRUE;
  829. int index = 0 ;
  830. do {
  831. UA_PublishRequest_init(&request);
  832. UA_PublishResponse_init(&response);
  833. request.subscriptionAcknowledgementsSize = 0;
  834. LIST_FOREACH(ack, &(client->pendingNotificationsAcks), listEntry) {
  835. request.subscriptionAcknowledgementsSize++;
  836. }
  837. request.subscriptionAcknowledgements = (UA_SubscriptionAcknowledgement *) UA_malloc(sizeof(UA_SubscriptionAcknowledgement)*request.subscriptionAcknowledgementsSize);
  838. index = 0;
  839. LIST_FOREACH(ack, &(client->pendingNotificationsAcks), listEntry) {
  840. ack = client->pendingNotificationsAcks.lh_first;
  841. request.subscriptionAcknowledgements[index].sequenceNumber = ack->subAck.sequenceNumber;
  842. request.subscriptionAcknowledgements[index].subscriptionId = ack->subAck.subscriptionId;
  843. index++;
  844. }
  845. response = UA_Client_publish(client, &request);
  846. if (response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
  847. moreNotifications = UA_Client_processPublishRx(client, response);
  848. else
  849. moreNotifications = UA_FALSE;
  850. UA_PublishResponse_deleteMembers(&response);
  851. UA_PublishRequest_deleteMembers(&request);
  852. } while(moreNotifications == UA_TRUE);
  853. return;
  854. }
  855. #endif
  856. /**********************************/
  857. /* User-Facing Macros-Function */
  858. /**********************************/
  859. #ifdef ENABLE_METHODCALLS
  860. UA_CallResponse UA_Client_call(UA_Client *client, UA_CallRequest *request) {
  861. UA_CallResponse response;
  862. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_CALLREQUEST],
  863. &response, &UA_TYPES[UA_TYPES_CALLRESPONSE]);
  864. return response;
  865. }
  866. UA_StatusCode UA_Client_callServerMethod(UA_Client *client, UA_NodeId objectNodeId, UA_NodeId methodNodeId,
  867. UA_Int32 inputSize, const UA_Variant *input,
  868. UA_Int32 *outputSize, UA_Variant **output) {
  869. UA_CallRequest request;
  870. UA_CallRequest_init(&request);
  871. request.methodsToCallSize = 1;
  872. request.methodsToCall = UA_CallMethodRequest_new();
  873. if(!request.methodsToCall)
  874. return UA_STATUSCODE_BADOUTOFMEMORY;
  875. UA_CallMethodRequest *rq = &request.methodsToCall[0];
  876. UA_NodeId_copy(&methodNodeId, &rq->methodId);
  877. UA_NodeId_copy(&objectNodeId, &rq->objectId);
  878. rq->inputArguments = (void*)(uintptr_t)input; // cast const...
  879. rq->inputArgumentsSize = inputSize;
  880. UA_CallResponse response;
  881. response = UA_Client_call(client, &request);
  882. rq->inputArguments = UA_NULL;
  883. rq->inputArgumentsSize = -1;
  884. UA_CallRequest_deleteMembers(&request);
  885. UA_StatusCode retval = response.responseHeader.serviceResult;
  886. if(retval == UA_STATUSCODE_GOOD) {
  887. retval |= response.results[0].statusCode;
  888. *output = response.results[0].outputArguments;
  889. *outputSize = response.results[0].outputArgumentsSize;
  890. response.results[0].outputArguments = UA_NULL;
  891. response.results[0].outputArgumentsSize = -1;
  892. }
  893. UA_CallResponse_deleteMembers(&response);
  894. return retval;
  895. }
  896. #endif
  897. /* Delete Node */
  898. #define UA_CLIENT_DELETENODETYPEALIAS(TYPE) \
  899. UA_StatusCode UA_Client_delete##TYPE##Node(UA_Client *client, UA_NodeId nodeId) { \
  900. return UA_Client_deleteNode(client, nodeId);\
  901. }
  902. UA_StatusCode UA_Client_deleteNode(UA_Client *client, UA_NodeId nodeId) {
  903. UA_DeleteNodesRequest *drq = UA_DeleteNodesRequest_new();
  904. UA_DeleteNodesResponse drs;
  905. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  906. drq->nodesToDeleteSize = 1;
  907. drq->nodesToDelete = (UA_DeleteNodesItem *) UA_malloc(sizeof(UA_DeleteNodesItem));
  908. drq->nodesToDelete[0].deleteTargetReferences = UA_TRUE;
  909. UA_NodeId_copy(&nodeId, &drq->nodesToDelete[0].nodeId);
  910. drs = UA_Client_deleteNodes(client, drq);
  911. UA_DeleteNodesRequest_delete(drq);
  912. if (drs.responseHeader.serviceResult != UA_STATUSCODE_GOOD || drs.resultsSize < 1) {
  913. UA_DeleteNodesResponse_deleteMembers(&drs);
  914. return drs.responseHeader.serviceResult;
  915. }
  916. UA_DeleteNodesResponse_deleteMembers(&drs);
  917. retval = drs.results[0];
  918. return retval;
  919. }
  920. UA_CLIENT_DELETENODETYPEALIAS(Object)
  921. UA_CLIENT_DELETENODETYPEALIAS(Variable)
  922. UA_CLIENT_DELETENODETYPEALIAS(ObjectType)
  923. UA_CLIENT_DELETENODETYPEALIAS(VariableType)
  924. UA_CLIENT_DELETENODETYPEALIAS(DataType)
  925. UA_CLIENT_DELETENODETYPEALIAS(Method)
  926. UA_CLIENT_DELETENODETYPEALIAS(View)
  927. #define ADDNODES_COPYDEFAULTATTRIBUTES(REQUEST,ATTRIBUTES) do { \
  928. ATTRIBUTES.specifiedAttributes = 0; \
  929. if(! UA_LocalizedText_copy(&description, &(ATTRIBUTES.description))) \
  930. ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DESCRIPTION; \
  931. if(! UA_LocalizedText_copy(&displayName, &(ATTRIBUTES.displayName))) \
  932. ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DISPLAYNAME; \
  933. ATTRIBUTES.userWriteMask = userWriteMask; \
  934. ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_USERWRITEMASK; \
  935. ATTRIBUTES.writeMask = writeMask; \
  936. ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_WRITEMASK; \
  937. UA_QualifiedName_copy(&browseName, &(REQUEST.nodesToAdd[0].browseName)); \
  938. UA_ExpandedNodeId_copy(&parentNodeId, &(REQUEST.nodesToAdd[0].parentNodeId)); \
  939. UA_NodeId_copy(&referenceTypeId, &(REQUEST.nodesToAdd[0].referenceTypeId)); \
  940. UA_ExpandedNodeId_copy(&typeDefinition, &(REQUEST.nodesToAdd[0].typeDefinition)); \
  941. UA_ExpandedNodeId reqExpNodeId; \
  942. UA_ExpandedNodeId_init(&reqExpNodeId); \
  943. UA_NodeId_copy(&reqId, &reqExpNodeId.nodeId); \
  944. UA_ExpandedNodeId_copy(&reqExpNodeId, &(REQUEST.nodesToAdd[0].requestedNewNodeId )); \
  945. REQUEST.nodesToAddSize = 1; \
  946. } while(0)
  947. #define ADDNODES_PACK_AND_SEND(PREQUEST,PATTRIBUTES,PNODETYPE) do { \
  948. PREQUEST.nodesToAdd[0].nodeAttributes.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING; \
  949. PREQUEST.nodesToAdd[0].nodeAttributes.typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_##PNODETYPE##ATTRIBUTES + UA_ENCODINGOFFSET_BINARY); \
  950. size_t encOffset = 0; \
  951. UA_ByteString_newMembers(&PREQUEST.nodesToAdd[0].nodeAttributes.body, client->connection.remoteConf.maxMessageSize); \
  952. UA_encodeBinary(&PATTRIBUTES,&UA_TYPES[UA_TYPES_##PNODETYPE##ATTRIBUTES], &(PREQUEST.nodesToAdd[0].nodeAttributes.body), &encOffset); \
  953. PREQUEST.nodesToAdd[0].nodeAttributes.body.length = encOffset; \
  954. *(adRes) = UA_Client_addNodes(client, &PREQUEST); \
  955. UA_AddNodesRequest_deleteMembers(&PREQUEST); \
  956. } while(0)
  957. /* NodeManagement */
  958. UA_StatusCode UA_Client_addObjectNode(UA_Client *client, UA_NodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName,
  959. UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
  960. UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId) {
  961. UA_AddNodesRequest adReq;
  962. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  963. UA_AddNodesRequest_init(&adReq);
  964. UA_AddNodesResponse *adRes = UA_AddNodesResponse_new();
  965. UA_ObjectAttributes vAtt;
  966. UA_ObjectAttributes_init(&vAtt);
  967. adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
  968. UA_AddNodesItem_init(adReq.nodesToAdd);
  969. // Default node properties and attributes
  970. ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
  971. // Specific to objects
  972. adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_OBJECT;
  973. vAtt.eventNotifier = 0;
  974. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_EVENTNOTIFIER;
  975. ADDNODES_PACK_AND_SEND(adReq,vAtt,OBJECT);
  976. if(adRes->responseHeader.serviceResult != UA_STATUSCODE_GOOD || adRes->resultsSize == 0)
  977. retval = adRes->responseHeader.serviceResult;
  978. retval |= adRes->results[0].statusCode;
  979. if(createdNodeId != NULL)
  980. UA_NodeId_copy(&adRes->results[0].addedNodeId, createdNodeId);
  981. UA_AddNodesResponse_delete(adRes);
  982. return retval;
  983. }
  984. UA_StatusCode UA_Client_addVariableNode(UA_Client *client, UA_NodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName,
  985. UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
  986. UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_Variant *value, UA_NodeId *createdNodeId) {
  987. UA_AddNodesRequest adReq;
  988. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  989. UA_AddNodesRequest_init(&adReq);
  990. UA_AddNodesResponse *adRes = UA_AddNodesResponse_new();
  991. UA_VariableAttributes vAtt;
  992. UA_VariableAttributes_init(&vAtt);
  993. adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
  994. UA_AddNodesItem_init(adReq.nodesToAdd);
  995. UA_ExpandedNodeId typeDefinition;
  996. UA_ExpandedNodeId_init(&typeDefinition);
  997. if (value != UA_NULL)
  998. UA_NodeId_copy(&value->type->typeId, &typeDefinition.nodeId);
  999. // Default node properties and attributes
  1000. ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
  1001. // Specific to variables
  1002. adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_VARIABLE;
  1003. vAtt.accessLevel = 0;
  1004. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_ACCESSLEVEL;
  1005. vAtt.userAccessLevel = 0;
  1006. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_USERACCESSLEVEL;
  1007. vAtt.minimumSamplingInterval = 100;
  1008. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL;
  1009. vAtt.historizing = UA_FALSE;
  1010. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_HISTORIZING;
  1011. if (value != NULL) {
  1012. UA_Variant_copy(value, &(vAtt.value));
  1013. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE;
  1014. vAtt.valueRank = -2;
  1015. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUERANK;
  1016. // These are defined by the variant
  1017. //vAtt.arrayDimensionsSize = value->arrayDimensionsSize;
  1018. //vAtt.arrayDimensions = NULL;
  1019. UA_NodeId_copy(&value->type->typeId, &(vAtt.dataType));
  1020. }
  1021. ADDNODES_PACK_AND_SEND(adReq,vAtt,VARIABLE);
  1022. if(adRes->responseHeader.serviceResult != UA_STATUSCODE_GOOD || adRes->resultsSize == 0)
  1023. retval = adRes->responseHeader.serviceResult;
  1024. retval |= adRes->results[0].statusCode;
  1025. if(createdNodeId != NULL)
  1026. UA_NodeId_copy(&adRes->results[0].addedNodeId, createdNodeId);
  1027. UA_AddNodesResponse_delete(adRes);
  1028. return retval;
  1029. }
  1030. UA_StatusCode UA_Client_addReferenceTypeNode( UA_Client *client, UA_NodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName,
  1031. UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
  1032. UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition,
  1033. UA_LocalizedText inverseName, UA_NodeId *createdNodeId ) {
  1034. UA_AddNodesRequest adReq;
  1035. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1036. UA_AddNodesRequest_init(&adReq);
  1037. UA_AddNodesResponse *adRes = UA_AddNodesResponse_new();
  1038. UA_ReferenceTypeAttributes vAtt;
  1039. UA_ReferenceTypeAttributes_init(&vAtt);
  1040. adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
  1041. UA_AddNodesItem_init(adReq.nodesToAdd);
  1042. // Default node properties and attributes
  1043. ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
  1044. // Specific to referencetypes
  1045. adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_REFERENCETYPE;
  1046. UA_LocalizedText_copy(&inverseName, &(vAtt.inverseName));
  1047. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_INVERSENAME;
  1048. vAtt.symmetric = UA_FALSE;
  1049. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_SYMMETRIC;
  1050. vAtt.isAbstract = UA_FALSE;
  1051. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_ISABSTRACT;
  1052. ADDNODES_PACK_AND_SEND(adReq,vAtt,REFERENCETYPE);
  1053. if(adRes->responseHeader.serviceResult != UA_STATUSCODE_GOOD || adRes->resultsSize == 0)
  1054. retval = adRes->responseHeader.serviceResult;
  1055. retval |= adRes->results[0].statusCode;
  1056. if(createdNodeId != NULL)
  1057. UA_NodeId_copy(&adRes->results[0].addedNodeId, createdNodeId);
  1058. UA_AddNodesResponse_delete(adRes);
  1059. return retval;
  1060. }
  1061. UA_StatusCode UA_Client_addObjectTypeNode(UA_Client *client, UA_NodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName,
  1062. UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
  1063. UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition, UA_Boolean isAbstract,
  1064. UA_NodeId *createdNodeId) {
  1065. UA_AddNodesRequest adReq;
  1066. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1067. UA_AddNodesRequest_init(&adReq);
  1068. UA_AddNodesResponse *adRes = UA_AddNodesResponse_new();
  1069. UA_AddNodesResponse_init(adRes);
  1070. UA_ObjectTypeAttributes vAtt;
  1071. UA_ObjectTypeAttributes_init(&vAtt);
  1072. adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
  1073. UA_AddNodesItem_init(adReq.nodesToAdd);
  1074. // Default node properties and attributes
  1075. ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
  1076. // Specific to referencetypes
  1077. adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_OBJECTTYPE;
  1078. vAtt.isAbstract = isAbstract;
  1079. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_ISABSTRACT;
  1080. ADDNODES_PACK_AND_SEND(adReq,vAtt,OBJECTTYPE);
  1081. if(adRes->responseHeader.serviceResult != UA_STATUSCODE_GOOD || adRes->resultsSize == 0)
  1082. retval = adRes->responseHeader.serviceResult;
  1083. retval |= adRes->results[0].statusCode;
  1084. if(createdNodeId != NULL)
  1085. UA_NodeId_copy(&adRes->results[0].addedNodeId, createdNodeId);
  1086. UA_AddNodesResponse_delete(adRes);
  1087. return retval;
  1088. }
  1089. UA_StatusCode
  1090. UA_Client_forEachChildNodeCall(UA_Client *client, UA_NodeId parentNodeId, UA_NodeIteratorCallback callback, void *handle) {
  1091. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1092. UA_BrowseRequest brq;
  1093. UA_BrowseRequest_init(&brq);
  1094. UA_BrowseResponse brs;
  1095. UA_BrowseResponse_init(&brs);
  1096. brq.nodesToBrowseSize = 1;
  1097. brq.requestedMaxReferencesPerNode = 0;
  1098. brq.nodesToBrowse = UA_BrowseDescription_new();
  1099. brq.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_BOTH;
  1100. brq.nodesToBrowse[0].includeSubtypes = UA_TRUE;
  1101. UA_NodeId_copy(&parentNodeId, &brq.nodesToBrowse[0].nodeId);
  1102. brq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL;
  1103. brs = UA_Client_browse(client, &brq);
  1104. UA_BrowseRequest_deleteMembers(&brq);
  1105. if (brs.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
  1106. UA_BrowseResponse_deleteMembers(&brq);
  1107. return brs.responseHeader.serviceResult;
  1108. }
  1109. if (brs.resultsSize < 1) {
  1110. UA_BrowseResponse_deleteMembers(&brq);
  1111. return UA_STATUSCODE_GOOD;
  1112. }
  1113. if (brs.results[0].statusCode != UA_STATUSCODE_GOOD) {
  1114. UA_BrowseResponse_deleteMembers(&brq);
  1115. return brs.results[0].statusCode;
  1116. }
  1117. UA_Boolean isInverse;
  1118. UA_NodeId *childId = UA_NodeId_new();
  1119. UA_NodeId *refTypeId = UA_NodeId_new();
  1120. for (int i = 0; i < brs.results[0].referencesSize; i++) {
  1121. isInverse = UA_FALSE;
  1122. if (brs.results[0].references[i].isForward == UA_FALSE)
  1123. isInverse = UA_TRUE;
  1124. UA_NodeId_copy(&brs.results[0].references[i].nodeId.nodeId, childId);
  1125. UA_NodeId_copy(&brs.results[0].references[i].referenceTypeId, refTypeId);
  1126. //UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId
  1127. callback(*childId, isInverse, *refTypeId, handle);
  1128. UA_NodeId_deleteMembers(childId);
  1129. UA_NodeId_deleteMembers(refTypeId);
  1130. }
  1131. UA_NodeId_delete(childId);
  1132. UA_NodeId_delete(refTypeId);
  1133. UA_BrowseResponse_deleteMembers(&brs);
  1134. return retval;
  1135. }
  1136. #include "server/ua_nodes.h"
  1137. UA_StatusCode
  1138. UA_Client_copyBaseAttributes(UA_Client *client, UA_ReadResponse *readResponseSrc, void *dst) {
  1139. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1140. UA_Node *target = (UA_Node *) dst;
  1141. if (readResponseSrc->results[0].value.data != UA_NULL)
  1142. retval |= UA_NodeId_copy((UA_NodeId *) readResponseSrc->results[0].value.data, &target->nodeId);
  1143. if (readResponseSrc->results[1].value.data != UA_NULL)
  1144. retval |= UA_NodeClass_copy((UA_NodeClass *) readResponseSrc->results[1].value.data, &target->nodeClass);
  1145. if (readResponseSrc->results[2].value.data != UA_NULL)
  1146. retval |= UA_QualifiedName_copy((UA_QualifiedName *) readResponseSrc->results[2].value.data, &target->browseName);
  1147. if (readResponseSrc->results[3].value.data != UA_NULL)
  1148. retval |= UA_LocalizedText_copy((UA_LocalizedText *) readResponseSrc->results[3].value.data, &target->displayName);
  1149. if (readResponseSrc->results[4].value.data != UA_NULL)
  1150. retval |= UA_LocalizedText_copy((UA_LocalizedText *) readResponseSrc->results[4].value.data, &target->description);
  1151. if (readResponseSrc->results[5].value.data != UA_NULL)
  1152. retval |= UA_UInt32_copy((UA_UInt32 *) readResponseSrc->results[5].value.data, &target->writeMask);
  1153. if (readResponseSrc->results[6].value.data != UA_NULL)
  1154. retval |= UA_UInt32_copy((UA_UInt32 *) readResponseSrc->results[6].value.data, &target->userWriteMask);
  1155. target->referencesSize = 0;
  1156. target->references = UA_NULL;
  1157. UA_BrowseRequest *brq = UA_BrowseRequest_new();
  1158. UA_BrowseResponse brs;
  1159. UA_BrowseResult_init(&brs);
  1160. brq->nodesToBrowseSize = 1;
  1161. brq->requestedMaxReferencesPerNode = 0;
  1162. brq->nodesToBrowse = UA_BrowseDescription_new();
  1163. brq->nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_BOTH;
  1164. brq->nodesToBrowse[0].includeSubtypes = UA_TRUE;
  1165. UA_NodeId_copy((UA_NodeId *) readResponseSrc->results[0].value.data, &brq->nodesToBrowse[0].nodeId);
  1166. brq->nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL;
  1167. brs = UA_Client_browse(client, brq);
  1168. UA_BrowseRequest_delete(brq);
  1169. if (brs.responseHeader.serviceResult!= UA_STATUSCODE_GOOD || brs.resultsSize != 1) {
  1170. UA_BrowseResponse_deleteMembers(&brs);
  1171. return retval;
  1172. }
  1173. if (brs.results[0].statusCode != UA_STATUSCODE_GOOD) {
  1174. UA_BrowseResponse_deleteMembers(&brs);
  1175. return retval;
  1176. }
  1177. /* typedef struct {
  1178. U A_NodeId referenceTypeId; *
  1179. UA_Boolean isInverse;
  1180. UA_ExpandedNodeId targetId; */
  1181. target->referencesSize = brs.results[0].referencesSize;
  1182. target->references = (UA_ReferenceNode *) UA_malloc(sizeof(UA_ReferenceNode) * brs.results[0].referencesSize);
  1183. for (int i=0; i<brs.results[0].referencesSize; i++) {
  1184. target->references[i].isInverse = UA_FALSE;
  1185. if (brs.results[0].references->isForward == UA_FALSE)
  1186. target->references[i].isInverse = UA_TRUE;
  1187. UA_NodeId_copy(&brs.results[0].references->nodeId.nodeId, &target->references[i].referenceTypeId);
  1188. UA_ExpandedNodeId_init(&target->references[i].targetId);
  1189. UA_NodeId_copy(&brs.results[0].references->referenceTypeId, &target->references[i].targetId.nodeId);
  1190. }
  1191. UA_BrowseResponse_deleteMembers(&brs);
  1192. return retval;
  1193. }
  1194. UA_StatusCode
  1195. UA_Client_appendObjectNodeAttributes(UA_Client *client, void *dst) {
  1196. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1197. UA_ObjectNode *target = (UA_ObjectNode *) dst;
  1198. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1199. UA_ReadResponse rrs;
  1200. /* Read node attributes:
  1201. UA_ATTRIBUTEID_EVENTNOTIFIER = 12
  1202. */
  1203. rrq->nodesToReadSize = 1;
  1204. rrq->nodesToRead = (UA_ReadValueId*) UA_malloc(sizeof(UA_ReadValueId) * rrq->nodesToReadSize);
  1205. for(int i = 0; i < rrq->nodesToReadSize; i++) {
  1206. UA_ReadValueId_init(&rrq->nodesToRead[i]);
  1207. rrq->nodesToRead[i].attributeId = (UA_UInt32 ) i+12;
  1208. UA_NodeId_copy(&target->nodeId, &rrq->nodesToRead[i].nodeId);
  1209. }
  1210. rrs = UA_Client_read(client, rrq);
  1211. if (rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  1212. retval = rrs.responseHeader.serviceResult;
  1213. if (rrs.resultsSize != rrq->nodesToReadSize)
  1214. retval = rrs.responseHeader.serviceResult;
  1215. UA_ReadRequest_delete(rrq);
  1216. if (!(retval == UA_STATUSCODE_GOOD))
  1217. return retval;
  1218. if (rrs.results[0].value.data != NULL)
  1219. UA_Byte_copy((UA_Byte *) rrs.results[0].value.data, &target->eventNotifier);
  1220. UA_ReadResponse_deleteMembers(&rrs);
  1221. return retval;
  1222. }
  1223. UA_StatusCode
  1224. UA_Client_appendObjectTypeNodeAttributes(UA_Client *client, void *dst) {
  1225. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1226. UA_ObjectTypeNode *target = (UA_ObjectTypeNode *) dst;
  1227. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1228. UA_ReadResponse rrs;
  1229. /* Read node attributes:
  1230. * UA_ATTRIBUTEID_ISABSTRACT = 8,
  1231. */
  1232. rrq->nodesToReadSize = 1;
  1233. rrq->nodesToRead = (UA_ReadValueId*) UA_malloc(sizeof(UA_ReadValueId) * rrq->nodesToReadSize);
  1234. for(int i = 0; i < rrq->nodesToReadSize; i++) {
  1235. UA_ReadValueId_init(&rrq->nodesToRead[i]);
  1236. rrq->nodesToRead[i].attributeId = (UA_UInt32 ) i+8;
  1237. UA_NodeId_copy(&target->nodeId, &rrq->nodesToRead[i].nodeId);
  1238. }
  1239. rrs = UA_Client_read(client, rrq);
  1240. if (rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  1241. retval = rrs.responseHeader.serviceResult;
  1242. if (rrs.resultsSize != rrq->nodesToReadSize)
  1243. retval = rrs.responseHeader.serviceResult;
  1244. UA_ReadRequest_delete(rrq);
  1245. if (!(retval == UA_STATUSCODE_GOOD))
  1246. return retval;
  1247. if (rrs.results[0].value.data != NULL)
  1248. UA_Boolean_copy((UA_Boolean *) rrs.results[0].value.data, &target->isAbstract);
  1249. UA_ReadResponse_deleteMembers(&rrs);
  1250. return retval;
  1251. }
  1252. UA_StatusCode
  1253. UA_Client_appendVariableNodeAttributes(UA_Client *client, void *dst) {
  1254. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1255. UA_VariableNode *target = (UA_VariableNode *) dst;
  1256. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1257. UA_ReadResponse rrs;
  1258. /* Read node attributes:
  1259. UA_ATTRIBUTEID_VALUE = 13,
  1260. UA_ATTRIBUTEID_DATATYPE = 14, // Req. but not used (is in variant)
  1261. UA_ATTRIBUTEID_ARRAYDIMENSIONS = 16, // Req. but not used (is in variant)
  1262. UA_ATTRIBUTEID_VALUERANK = 15,
  1263. UA_ATTRIBUTEID_ACCESSLEVEL = 17,
  1264. UA_ATTRIBUTEID_USERACCESSLEVEL = 18,
  1265. UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL = 19,
  1266. UA_ATTRIBUTEID_HISTORIZING = 20,
  1267. */
  1268. rrq->nodesToReadSize = 8;
  1269. rrq->nodesToRead = (UA_ReadValueId*) UA_malloc(sizeof(UA_ReadValueId) * rrq->nodesToReadSize);
  1270. for(int i = 0; i < rrq->nodesToReadSize; i++) {
  1271. UA_ReadValueId_init(&rrq->nodesToRead[i]);
  1272. rrq->nodesToRead[i].attributeId = (UA_UInt32 ) i+13;
  1273. UA_NodeId_copy(&target->nodeId, &rrq->nodesToRead[i].nodeId);
  1274. }
  1275. rrs = UA_Client_read(client, rrq);
  1276. if (rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  1277. retval = rrs.responseHeader.serviceResult;
  1278. if (rrs.resultsSize != rrq->nodesToReadSize)
  1279. retval = rrs.responseHeader.serviceResult;
  1280. UA_ReadRequest_delete(rrq);
  1281. if (!(retval == UA_STATUSCODE_GOOD))
  1282. return retval;
  1283. if (rrs.results[0].value.data != NULL)
  1284. UA_Variant_copy((UA_Variant *) &rrs.results[0].value, &target->value.variant);
  1285. if (rrs.results[3].value.data != NULL)
  1286. UA_Int32_copy((UA_Int32 *) rrs.results[3].value.data, &target->valueRank);
  1287. if (rrs.results[4].value.data != NULL)
  1288. UA_Byte_copy((UA_Byte *) rrs.results[4].value.data, &target->accessLevel);
  1289. if (rrs.results[5].value.data != NULL)
  1290. UA_Byte_copy((UA_Byte *) rrs.results[5].value.data, &target->userAccessLevel);
  1291. if (rrs.results[6].value.data != NULL)
  1292. UA_Double_copy((UA_Double *) rrs.results[6].value.data, &target->minimumSamplingInterval);
  1293. if (rrs.results[7].value.data != NULL)
  1294. UA_Boolean_copy((UA_Boolean *) rrs.results[7].value.data, &target->historizing);
  1295. UA_ReadResponse_deleteMembers(&rrs);
  1296. return retval;
  1297. }
  1298. UA_StatusCode
  1299. UA_Client_appendVariableTypeNodeAttributes(UA_Client *client, void *dst) {
  1300. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1301. UA_VariableTypeNode *target = (UA_VariableTypeNode *) dst;
  1302. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1303. UA_ReadResponse rrs;
  1304. /* Read node attributes:
  1305. UA_ATTRIBUTEID_ISABSTRACT = 8,
  1306. UA_ATTRIBUTEID_VALUE = 13,
  1307. UA_ATTRIBUTEID_DATATYPE = 14, // Req. but not used (is in variant)
  1308. UA_ATTRIBUTEID_ARRAYDIMENSIONS = 16, // Req. but not used (is in variant)
  1309. UA_ATTRIBUTEID_VALUERANK = 15,
  1310. */
  1311. rrq->nodesToReadSize = 8;
  1312. rrq->nodesToRead = (UA_ReadValueId*) UA_malloc(sizeof(UA_ReadValueId) * rrq->nodesToReadSize);
  1313. for(int i = 0; i < rrq->nodesToReadSize; i++) {
  1314. UA_ReadValueId_init(&rrq->nodesToRead[i]);
  1315. rrq->nodesToRead[i].attributeId = (UA_UInt32 ) i+13;
  1316. UA_NodeId_copy(&target->nodeId, &rrq->nodesToRead[i].nodeId);
  1317. }
  1318. rrq->nodesToRead[0].attributeId = UA_ATTRIBUTEID_ISABSTRACT;
  1319. rrs = UA_Client_read(client, rrq);
  1320. if (rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  1321. retval = rrs.responseHeader.serviceResult;
  1322. if (rrs.resultsSize != rrq->nodesToReadSize)
  1323. retval = rrs.responseHeader.serviceResult;
  1324. UA_ReadRequest_delete(rrq);
  1325. if (!(retval == UA_STATUSCODE_GOOD))
  1326. return retval;
  1327. if (rrs.results[0].value.data != NULL)
  1328. UA_Boolean_copy((UA_Boolean *) rrs.results[0].value.data, &target->isAbstract);
  1329. if (rrs.results[1].value.data != NULL)
  1330. UA_Variant_copy((UA_Variant *) &rrs.results[1].value, &target->value.variant);
  1331. if (rrs.results[2].value.data != NULL)
  1332. UA_Int32_copy((UA_Int32 *) rrs.results[2].value.data, &target->valueRank);
  1333. UA_ReadResponse_deleteMembers(&rrs);
  1334. return retval;
  1335. }
  1336. UA_StatusCode
  1337. UA_Client_appendReferenceTypeNodeAttributes(UA_Client *client, void *dst) {
  1338. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1339. UA_ReferenceTypeNode *target = (UA_ReferenceTypeNode *) dst;
  1340. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1341. UA_ReadResponse rrs;
  1342. /* Read node attributes:
  1343. UA_ATTRIBUTEID_SYMMETRIC = 9,
  1344. UA_ATTRIBUTEID_INVERSENAME = 10,
  1345. * UA_ATTRIBUTEID_ISABSTRACT = 8,
  1346. */
  1347. rrq->nodesToReadSize = 3;
  1348. rrq->nodesToRead = (UA_ReadValueId*) UA_malloc(sizeof(UA_ReadValueId) * rrq->nodesToReadSize);
  1349. for(int i = 0; i < rrq->nodesToReadSize; i++) {
  1350. UA_ReadValueId_init(&rrq->nodesToRead[i]);
  1351. rrq->nodesToRead[i].attributeId = (UA_UInt32 ) i+8;
  1352. UA_NodeId_copy(&target->nodeId, &rrq->nodesToRead[i].nodeId);
  1353. }
  1354. rrs = UA_Client_read(client, rrq);
  1355. if (rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  1356. retval = rrs.responseHeader.serviceResult;
  1357. if (rrs.resultsSize != rrq->nodesToReadSize)
  1358. retval = rrs.responseHeader.serviceResult;
  1359. UA_ReadRequest_delete(rrq);
  1360. if (!(retval == UA_STATUSCODE_GOOD))
  1361. return retval;
  1362. if (rrs.results[0].value.data != NULL)
  1363. UA_Boolean_copy((UA_Boolean *) rrs.results[0].value.data, &target->isAbstract);
  1364. if (rrs.results[1].value.data != NULL)
  1365. UA_Boolean_copy((UA_Boolean *) rrs.results[1].value.data, &target->symmetric);
  1366. if (rrs.results[2].value.data != NULL)
  1367. UA_LocalizedText_copy((UA_LocalizedText *) rrs.results[2].value.data, &target->inverseName);
  1368. UA_ReadResponse_deleteMembers(&rrs);
  1369. return retval;
  1370. }
  1371. UA_StatusCode
  1372. UA_Client_appendViewNodeAttributes(UA_Client *client, void *dst) {
  1373. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1374. UA_ViewNode *target = (UA_ViewNode *) dst;
  1375. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1376. UA_ReadResponse rrs;
  1377. /* Read node attributes:
  1378. UA_ATTRIBUTEID_CONTAINSNOLOOPS = 11,
  1379. UA_ATTRIBUTEID_EVENTNOTIFIER = 12,
  1380. */
  1381. rrq->nodesToReadSize = 2;
  1382. rrq->nodesToRead = (UA_ReadValueId*) UA_malloc(sizeof(UA_ReadValueId) * rrq->nodesToReadSize);
  1383. for(int i = 0; i < rrq->nodesToReadSize; i++) {
  1384. UA_ReadValueId_init(&rrq->nodesToRead[i]);
  1385. rrq->nodesToRead[i].attributeId = (UA_UInt32 ) i+11;
  1386. UA_NodeId_copy(&target->nodeId, &rrq->nodesToRead[i].nodeId);
  1387. }
  1388. rrs = UA_Client_read(client, rrq);
  1389. if (rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  1390. retval = rrs.responseHeader.serviceResult;
  1391. if (rrs.resultsSize != rrq->nodesToReadSize)
  1392. retval = rrs.responseHeader.serviceResult;
  1393. UA_ReadRequest_delete(rrq);
  1394. if (!(retval == UA_STATUSCODE_GOOD))
  1395. return retval;
  1396. if (rrs.results[0].value.data != NULL)
  1397. UA_Boolean_copy((UA_Boolean *) rrs.results[0].value.data, &target->containsNoLoops);
  1398. if (rrs.results[1].value.data != NULL)
  1399. UA_Byte_copy((UA_Byte *) rrs.results[1].value.data, &target->eventNotifier);
  1400. UA_ReadResponse_deleteMembers(&rrs);
  1401. return retval;
  1402. }
  1403. UA_StatusCode
  1404. UA_Client_appendDataTypeNodeAttributes(UA_Client *client, void *dst) {
  1405. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1406. UA_DataTypeNode *target = (UA_DataTypeNode *) dst;
  1407. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1408. UA_ReadResponse rrs;
  1409. /* Read node attributes:
  1410. * UA_ATTRIBUTEID_ISABSTRACT = 8,
  1411. */
  1412. rrq->nodesToReadSize = 1;
  1413. rrq->nodesToRead = (UA_ReadValueId*) UA_malloc(sizeof(UA_ReadValueId) * rrq->nodesToReadSize);
  1414. for(int i = 0; i < rrq->nodesToReadSize; i++) {
  1415. UA_ReadValueId_init(&rrq->nodesToRead[i]);
  1416. rrq->nodesToRead[i].attributeId = (UA_UInt32 ) i+8;
  1417. UA_NodeId_copy(&target->nodeId, &rrq->nodesToRead[i].nodeId);
  1418. }
  1419. rrs = UA_Client_read(client, rrq);
  1420. if (rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  1421. retval = rrs.responseHeader.serviceResult;
  1422. if (rrs.resultsSize != rrq->nodesToReadSize)
  1423. retval = rrs.responseHeader.serviceResult;
  1424. UA_ReadRequest_delete(rrq);
  1425. if (!(retval == UA_STATUSCODE_GOOD))
  1426. return retval;
  1427. if (rrs.results[0].value.data != NULL)
  1428. UA_Boolean_copy((UA_Boolean *) rrs.results[0].value.data, &target->isAbstract);
  1429. UA_ReadResponse_deleteMembers(&rrs);
  1430. return retval;
  1431. }
  1432. UA_StatusCode UA_Client_appendMethodNodeAttributes(UA_Client *client, void *dst) {
  1433. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1434. UA_MethodNode *target = (UA_MethodNode *) dst;
  1435. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1436. UA_ReadResponse rrs;
  1437. /* Read node attributes:
  1438. * UA_ATTRIBUTEID_USEREXECUTABLE = 22
  1439. * UA_ATTRIBUTEID_EXECUTABLE = 21,
  1440. */
  1441. rrq->nodesToReadSize = 2;
  1442. rrq->nodesToRead = (UA_ReadValueId*) UA_malloc(sizeof(UA_ReadValueId) * rrq->nodesToReadSize);
  1443. for(int i = 0; i < rrq->nodesToReadSize; i++) {
  1444. UA_ReadValueId_init(&rrq->nodesToRead[i]);
  1445. rrq->nodesToRead[i].attributeId = (UA_UInt32 ) i+21;
  1446. UA_NodeId_copy(&target->nodeId, &rrq->nodesToRead[i].nodeId);
  1447. }
  1448. rrs = UA_Client_read(client, rrq);
  1449. if (rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  1450. retval = rrs.responseHeader.serviceResult;
  1451. if (rrs.resultsSize != rrq->nodesToReadSize)
  1452. retval = rrs.responseHeader.serviceResult;
  1453. UA_ReadRequest_delete(rrq);
  1454. if (!(retval == UA_STATUSCODE_GOOD))
  1455. return retval;
  1456. if (rrs.results[0].value.data != NULL)
  1457. UA_Boolean_copy((UA_Boolean *) rrs.results[0].value.data, &target->executable);
  1458. if (rrs.results[1].value.data != NULL)
  1459. UA_Boolean_copy((UA_Boolean *) rrs.results[1].value.data, &target->userExecutable);
  1460. UA_ReadResponse_deleteMembers(&rrs);
  1461. return retval;
  1462. }
  1463. UA_StatusCode
  1464. UA_Client_getNodeCopy(UA_Client *client, UA_NodeId nodeId, void **copyInto) {
  1465. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1466. UA_ReadResponse rrs;
  1467. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1468. *copyInto = UA_NULL;
  1469. /* Read default node attributes:
  1470. UA_ATTRIBUTEID_NODEID = 1,
  1471. UA_ATTRIBUTEID_NODECLASS = 2,
  1472. UA_ATTRIBUTEID_BROWSENAME = 3,
  1473. UA_ATTRIBUTEID_DISPLAYNAME = 4,
  1474. UA_ATTRIBUTEID_DESCRIPTION = 5,
  1475. UA_ATTRIBUTEID_WRITEMASK = 6,
  1476. UA_ATTRIBUTEID_USERWRITEMASK = 7,
  1477. */
  1478. rrq->nodesToReadSize = 7;
  1479. rrq->nodesToRead = (UA_ReadValueId*) UA_malloc(sizeof(UA_ReadValueId) * rrq->nodesToReadSize);
  1480. for(int i = 0; i < rrq->nodesToReadSize; i++) {
  1481. UA_ReadValueId_init(&rrq->nodesToRead[i]);
  1482. rrq->nodesToRead[i].attributeId = (UA_UInt32 ) i+1;
  1483. UA_NodeId_copy(&nodeId, &rrq->nodesToRead[i].nodeId);
  1484. }
  1485. rrs = UA_Client_read(client, rrq);
  1486. if (rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
  1487. UA_ReadRequest_delete(rrq);
  1488. return rrs.responseHeader.serviceResult;
  1489. }
  1490. if (rrs.resultsSize != rrq->nodesToReadSize) {
  1491. UA_ReadRequest_delete(rrq);
  1492. return rrs.responseHeader.serviceResult;
  1493. }
  1494. UA_ReadRequest_delete(rrq);
  1495. UA_UInt32 *nodeClass = rrs.results[1].value.data;
  1496. switch(*nodeClass) {
  1497. case UA_NODECLASS_OBJECT:
  1498. *copyInto = UA_ObjectNode_new();
  1499. retval |= UA_Client_copyBaseAttributes(client, &rrs, *copyInto);
  1500. retval |= UA_Client_appendObjectNodeAttributes(client, *copyInto);
  1501. break;
  1502. case UA_NODECLASS_OBJECTTYPE:
  1503. *copyInto = UA_ObjectTypeNode_new();
  1504. retval |= UA_Client_copyBaseAttributes(client, &rrs, *copyInto);
  1505. retval |= UA_Client_appendObjectTypeNodeAttributes(client, *copyInto);
  1506. break;
  1507. case UA_NODECLASS_VARIABLE:
  1508. *copyInto = UA_VariableNode_new();
  1509. retval |= UA_Client_copyBaseAttributes(client, &rrs, *copyInto);
  1510. retval |= UA_Client_appendVariableNodeAttributes(client, *copyInto);
  1511. break;
  1512. case UA_NODECLASS_VARIABLETYPE:
  1513. *copyInto = UA_VariableTypeNode_new();
  1514. retval |= UA_Client_copyBaseAttributes(client, &rrs, *copyInto);
  1515. retval |= UA_Client_appendVariableTypeNodeAttributes(client, *copyInto);
  1516. break;
  1517. case UA_NODECLASS_REFERENCETYPE:
  1518. *copyInto = UA_ReferenceTypeNode_new();
  1519. retval |= UA_Client_copyBaseAttributes(client, &rrs, *copyInto);
  1520. retval |= UA_Client_appendReferenceTypeNodeAttributes(client, *copyInto);
  1521. break;
  1522. case UA_NODECLASS_METHOD:
  1523. *copyInto = UA_MethodNode_new();
  1524. retval |= UA_Client_copyBaseAttributes(client, &rrs, *copyInto);
  1525. retval |= UA_Client_appendMethodNodeAttributes(client, *copyInto);
  1526. break;
  1527. case UA_NODECLASS_VIEW:
  1528. *copyInto = UA_ViewNode_new();
  1529. retval |= UA_Client_copyBaseAttributes(client, &rrs, *copyInto);
  1530. retval |= UA_Client_appendViewNodeAttributes(client, *copyInto);
  1531. break;
  1532. case UA_NODECLASS_DATATYPE:
  1533. *copyInto = UA_DataTypeNode_new();
  1534. retval |= UA_Client_copyBaseAttributes(client, &rrs, *copyInto);
  1535. retval |= UA_Client_appendDataTypeNodeAttributes(client, *copyInto);
  1536. break;
  1537. default:
  1538. UA_ReadResponse_deleteMembers(&rrs);
  1539. return UA_STATUSCODE_BADNODECLASSINVALID;
  1540. }
  1541. UA_ReadResponse_deleteMembers(&rrs);
  1542. return retval;
  1543. }
  1544. UA_StatusCode UA_Client_deleteNodeCopy(UA_Client *client, void **node) {
  1545. return UA_Server_deleteNodeCopy(UA_NULL, node);
  1546. }
  1547. #define SETATTRIBUTE_COPYTYPEVALUE(TYPE) \
  1548. wrq->nodesToWrite[0].value.value.data = UA_##TYPE##_new(); \
  1549. UA_##TYPE##_copy((UA_##TYPE *) value, (UA_##TYPE *) wrq->nodesToWrite[0].value.value.data);
  1550. UA_StatusCode
  1551. UA_Client_setAttributeValue(UA_Client *client, UA_NodeId nodeId, UA_AttributeId attributeId, void *value) {
  1552. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1553. UA_WriteRequest *wrq = UA_WriteRequest_new();
  1554. UA_WriteResponse wrs;
  1555. UA_WriteResponse_init(&wrs);
  1556. wrq->nodesToWriteSize = 1;
  1557. wrq->nodesToWrite = UA_WriteValue_new();
  1558. UA_NodeId_copy(&nodeId, &wrq->nodesToWrite[0].nodeId);
  1559. wrq->nodesToWrite[0].attributeId = attributeId;
  1560. wrq->nodesToWrite[0].value.hasValue = UA_TRUE;
  1561. wrq->nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA;
  1562. switch(attributeId) {
  1563. case UA_ATTRIBUTEID_NODEID:
  1564. UA_WriteRequest_delete(wrq);
  1565. UA_WriteResponse_deleteMembers(&wrs);
  1566. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1567. break;
  1568. case UA_ATTRIBUTEID_NODECLASS:
  1569. UA_WriteRequest_delete(wrq);
  1570. UA_WriteResponse_deleteMembers(&wrs);
  1571. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1572. break;
  1573. case UA_ATTRIBUTEID_BROWSENAME:
  1574. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME];
  1575. SETATTRIBUTE_COPYTYPEVALUE(QualifiedName);
  1576. break;
  1577. case UA_ATTRIBUTEID_DISPLAYNAME:
  1578. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
  1579. SETATTRIBUTE_COPYTYPEVALUE(LocalizedText);
  1580. break;
  1581. case UA_ATTRIBUTEID_DESCRIPTION:
  1582. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
  1583. SETATTRIBUTE_COPYTYPEVALUE(LocalizedText);
  1584. break;
  1585. case UA_ATTRIBUTEID_WRITEMASK:
  1586. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_UINT32];
  1587. SETATTRIBUTE_COPYTYPEVALUE(UInt32);
  1588. break;
  1589. case UA_ATTRIBUTEID_USERWRITEMASK:
  1590. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_UINT32];
  1591. SETATTRIBUTE_COPYTYPEVALUE(UInt32);
  1592. break;
  1593. case UA_ATTRIBUTEID_ISABSTRACT:
  1594. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
  1595. SETATTRIBUTE_COPYTYPEVALUE(Boolean);
  1596. break;
  1597. case UA_ATTRIBUTEID_SYMMETRIC:
  1598. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
  1599. SETATTRIBUTE_COPYTYPEVALUE(Boolean);
  1600. break;
  1601. case UA_ATTRIBUTEID_INVERSENAME:
  1602. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
  1603. SETATTRIBUTE_COPYTYPEVALUE(LocalizedText);
  1604. break;
  1605. case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
  1606. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
  1607. SETATTRIBUTE_COPYTYPEVALUE(Boolean);
  1608. break;
  1609. case UA_ATTRIBUTEID_EVENTNOTIFIER:
  1610. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BYTE];
  1611. SETATTRIBUTE_COPYTYPEVALUE(Byte);
  1612. break;
  1613. case UA_ATTRIBUTEID_VALUE:
  1614. UA_Variant_copy((UA_Variant *) value, (UA_Variant *) &wrq->nodesToWrite[0].value.value);
  1615. break;
  1616. case UA_ATTRIBUTEID_DATATYPE:
  1617. UA_WriteRequest_delete(wrq);
  1618. UA_WriteResponse_deleteMembers(&wrs);
  1619. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1620. break;
  1621. case UA_ATTRIBUTEID_VALUERANK:
  1622. UA_WriteRequest_delete(wrq);
  1623. UA_WriteResponse_deleteMembers(&wrs);
  1624. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1625. break;
  1626. case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
  1627. UA_WriteRequest_delete(wrq);
  1628. UA_WriteResponse_deleteMembers(&wrs);
  1629. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1630. break;
  1631. case UA_ATTRIBUTEID_ACCESSLEVEL:
  1632. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_UINT32];
  1633. SETATTRIBUTE_COPYTYPEVALUE(Byte);
  1634. break;
  1635. case UA_ATTRIBUTEID_USERACCESSLEVEL:
  1636. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_UINT32];
  1637. SETATTRIBUTE_COPYTYPEVALUE(Byte);
  1638. break;
  1639. case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
  1640. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_DOUBLE];
  1641. SETATTRIBUTE_COPYTYPEVALUE(Double);
  1642. break;
  1643. case UA_ATTRIBUTEID_HISTORIZING:
  1644. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
  1645. SETATTRIBUTE_COPYTYPEVALUE(Boolean);
  1646. break;
  1647. case UA_ATTRIBUTEID_EXECUTABLE:
  1648. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
  1649. SETATTRIBUTE_COPYTYPEVALUE(Boolean);
  1650. break;
  1651. case UA_ATTRIBUTEID_USEREXECUTABLE:
  1652. wrq->nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
  1653. SETATTRIBUTE_COPYTYPEVALUE(Boolean);
  1654. break;
  1655. default:
  1656. UA_WriteRequest_delete(wrq);
  1657. UA_WriteResponse_deleteMembers(&wrs);
  1658. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1659. }
  1660. wrs = UA_Client_write(client, wrq);
  1661. UA_WriteRequest_delete(wrq);
  1662. if (wrs.responseHeader.serviceResult)
  1663. return wrs.responseHeader.serviceResult;
  1664. if (wrs.resultsSize != 1)
  1665. return wrs.responseHeader.serviceResult;
  1666. retval = wrs.results[0];
  1667. UA_WriteResponse_deleteMembers(&wrs);
  1668. return retval;
  1669. }
  1670. #define GETATTRIBUTE_COPYTYPEVALUE(TYPE) \
  1671. if (rrs.results[0].hasValue == UA_TRUE) { \
  1672. *value = (void *) UA_##TYPE##_new(); \
  1673. UA_##TYPE##_copy((UA_##TYPE *) rrs.results[0].value.data, (UA_##TYPE *) *value ); \
  1674. }
  1675. UA_StatusCode UA_EXPORT
  1676. UA_Client_getAttributeValue(UA_Client *client, UA_NodeId nodeId, UA_AttributeId attributeId, void **value) {
  1677. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1678. UA_ReadRequest *rrq = UA_ReadRequest_new();
  1679. UA_ReadResponse rrs;
  1680. UA_ReadResponse_init(&rrs);
  1681. *value = UA_NULL;
  1682. rrq->timestampsToReturn = UA_TIMESTAMPSTORETURN_NEITHER;
  1683. rrq->nodesToReadSize = 1;
  1684. rrq->nodesToRead = UA_ReadValueId_new();
  1685. rrq->nodesToRead[0].attributeId = attributeId;
  1686. UA_NodeId_copy(&nodeId, &rrq->nodesToRead[0].nodeId);
  1687. rrs = UA_Client_read(client, rrq);
  1688. UA_ReadRequest_delete(rrq);
  1689. if(rrs.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  1690. return rrs.responseHeader.serviceResult;
  1691. if(rrs.resultsSize < 1)
  1692. return rrs.responseHeader.serviceResult;
  1693. if (rrs.results[0].status != UA_STATUSCODE_GOOD)
  1694. return rrs.results[0].status;
  1695. switch(attributeId) {
  1696. case UA_ATTRIBUTEID_NODEID:
  1697. GETATTRIBUTE_COPYTYPEVALUE(NodeId)
  1698. break;
  1699. case UA_ATTRIBUTEID_NODECLASS:
  1700. GETATTRIBUTE_COPYTYPEVALUE(NodeClass)
  1701. break;
  1702. case UA_ATTRIBUTEID_BROWSENAME:
  1703. GETATTRIBUTE_COPYTYPEVALUE(QualifiedName)
  1704. break;
  1705. case UA_ATTRIBUTEID_DISPLAYNAME:
  1706. GETATTRIBUTE_COPYTYPEVALUE(LocalizedText)
  1707. break;
  1708. case UA_ATTRIBUTEID_DESCRIPTION:
  1709. GETATTRIBUTE_COPYTYPEVALUE(LocalizedText)
  1710. break;
  1711. case UA_ATTRIBUTEID_WRITEMASK:
  1712. GETATTRIBUTE_COPYTYPEVALUE(UInt32)
  1713. break;
  1714. case UA_ATTRIBUTEID_USERWRITEMASK:
  1715. GETATTRIBUTE_COPYTYPEVALUE(UInt32)
  1716. break;
  1717. case UA_ATTRIBUTEID_ISABSTRACT:
  1718. GETATTRIBUTE_COPYTYPEVALUE(Boolean)
  1719. break;
  1720. case UA_ATTRIBUTEID_SYMMETRIC:
  1721. GETATTRIBUTE_COPYTYPEVALUE(Boolean)
  1722. break;
  1723. case UA_ATTRIBUTEID_INVERSENAME:
  1724. GETATTRIBUTE_COPYTYPEVALUE(LocalizedText)
  1725. break;
  1726. case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
  1727. GETATTRIBUTE_COPYTYPEVALUE(Boolean)
  1728. break;
  1729. case UA_ATTRIBUTEID_EVENTNOTIFIER:
  1730. GETATTRIBUTE_COPYTYPEVALUE(Byte)
  1731. break;
  1732. case UA_ATTRIBUTEID_VALUE:
  1733. GETATTRIBUTE_COPYTYPEVALUE(Variant)
  1734. break;
  1735. case UA_ATTRIBUTEID_DATATYPE:
  1736. *value = UA_NULL;
  1737. UA_ReadResponse_deleteMembers(&rrs);
  1738. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1739. break;
  1740. case UA_ATTRIBUTEID_VALUERANK:
  1741. *value = UA_NULL;
  1742. UA_ReadResponse_deleteMembers(&rrs);
  1743. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1744. break;
  1745. case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
  1746. *value = UA_NULL;
  1747. UA_ReadResponse_deleteMembers(&rrs);
  1748. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1749. break;
  1750. case UA_ATTRIBUTEID_ACCESSLEVEL:
  1751. GETATTRIBUTE_COPYTYPEVALUE(Byte)
  1752. break;
  1753. case UA_ATTRIBUTEID_USERACCESSLEVEL:
  1754. GETATTRIBUTE_COPYTYPEVALUE(Byte)
  1755. break;
  1756. case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
  1757. GETATTRIBUTE_COPYTYPEVALUE(Double)
  1758. break;
  1759. case UA_ATTRIBUTEID_HISTORIZING:
  1760. GETATTRIBUTE_COPYTYPEVALUE(Boolean)
  1761. break;
  1762. case UA_ATTRIBUTEID_EXECUTABLE:
  1763. GETATTRIBUTE_COPYTYPEVALUE(Boolean)
  1764. break;
  1765. case UA_ATTRIBUTEID_USEREXECUTABLE:
  1766. GETATTRIBUTE_COPYTYPEVALUE(Boolean)
  1767. break;
  1768. default:
  1769. *value = UA_NULL;
  1770. UA_ReadResponse_deleteMembers(&rrs);
  1771. return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  1772. }
  1773. UA_ReadResponse_deleteMembers(&rrs);
  1774. return retval;
  1775. }