ua_client.c 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  1. #include "ua_util.h"
  2. #include "ua_client.h"
  3. #include "ua_types_generated.h"
  4. #include "ua_nodeids.h"
  5. #include "ua_securechannel.h"
  6. #include "ua_types_encoding_binary.h"
  7. #include "ua_transport_generated.h"
  8. #include "ua_types_generated_encoding_binary.h"
  9. #include "ua_transport_generated_encoding_binary.h"
  10. #include "ua_client_internal.h"
  11. typedef enum {
  12. UA_CLIENTSTATE_READY,
  13. UA_CLIENTSTATE_CONNECTED,
  14. UA_CLIENTSTATE_ERRORED
  15. } UA_Client_State;
  16. struct UA_Client {
  17. /* State */ //maybe it should be visible to user
  18. UA_Client_State state;
  19. /* Connection */
  20. UA_Connection connection;
  21. UA_SecureChannel channel;
  22. UA_String endpointUrl;
  23. UA_UInt32 requestId;
  24. /* Session */
  25. UA_UserTokenPolicy token;
  26. UA_NodeId sessionId;
  27. UA_NodeId authenticationToken;
  28. #ifdef ENABLE_SUBSCRIPTIONS
  29. UA_Int32 monitoredItemHandles;
  30. LIST_HEAD(UA_ListOfUnacknowledgedNotificationNumbers, UA_Client_NotificationsAckNumber_s) pendingNotificationsAcks;
  31. LIST_HEAD(UA_ListOfClientSubscriptionItems, UA_Client_Subscription_s) subscriptions;
  32. #endif
  33. /* Config */
  34. UA_Logger logger;
  35. UA_ClientConfig config;
  36. UA_DateTime scExpiresAt;
  37. };
  38. const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard =
  39. { .timeout = 5 /* ms receive timout */, .secureChannelLifeTime = 30000, .timeToRenewSecureChannel = 2000,
  40. {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
  41. .maxMessageSize = 65536, .maxChunkCount = 1}};
  42. UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
  43. UA_Client *client = UA_calloc(1, sizeof(UA_Client));
  44. if(!client)
  45. return UA_NULL;
  46. UA_Client_init(client, config, logger);
  47. return client;
  48. }
  49. void UA_Client_reset(UA_Client* client){
  50. UA_Client_deleteMembers(client);
  51. UA_Client_init(client, client->config, client->logger);
  52. }
  53. void UA_Client_init(UA_Client* client, UA_ClientConfig config, UA_Logger logger){
  54. client->state = UA_CLIENTSTATE_READY;
  55. UA_Connection_init(&client->connection);
  56. UA_SecureChannel_init(&client->channel);
  57. client->channel.connection = &client->connection;
  58. UA_String_init(&client->endpointUrl);
  59. client->requestId = 0;
  60. UA_NodeId_init(&client->authenticationToken);
  61. client->logger = logger;
  62. client->config = config;
  63. client->scExpiresAt = 0;
  64. #ifdef ENABLE_SUBSCRIPTIONS
  65. client->monitoredItemHandles = 0;
  66. LIST_INIT(&client->pendingNotificationsAcks);
  67. LIST_INIT(&client->subscriptions);
  68. #endif
  69. }
  70. void UA_Client_deleteMembers(UA_Client* client){
  71. if(client->state == UA_CLIENTSTATE_READY) //initialized client has no dynamic memory allocated
  72. return;
  73. UA_Connection_deleteMembers(&client->connection);
  74. UA_SecureChannel_deleteMembersCleanup(&client->channel);
  75. if(client->endpointUrl.data)
  76. UA_String_deleteMembers(&client->endpointUrl);
  77. UA_UserTokenPolicy_deleteMembers(&client->token);
  78. }
  79. void UA_Client_delete(UA_Client* client){
  80. if(client->state != UA_CLIENTSTATE_READY)
  81. UA_Client_deleteMembers(client);
  82. UA_free(client);
  83. }
  84. static UA_StatusCode HelAckHandshake(UA_Client *c) {
  85. UA_TcpMessageHeader messageHeader;
  86. messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_HELF;
  87. UA_TcpHelloMessage hello;
  88. UA_String_copy(&c->endpointUrl, &hello.endpointUrl); /* must be less than 4096 bytes */
  89. UA_Connection *conn = &c->connection;
  90. hello.maxChunkCount = conn->localConf.maxChunkCount;
  91. hello.maxMessageSize = conn->localConf.maxMessageSize;
  92. hello.protocolVersion = conn->localConf.protocolVersion;
  93. hello.receiveBufferSize = conn->localConf.recvBufferSize;
  94. hello.sendBufferSize = conn->localConf.sendBufferSize;
  95. UA_ByteString message;
  96. UA_StatusCode retval = c->connection.getSendBuffer(&c->connection, c->connection.remoteConf.recvBufferSize, &message);
  97. if(retval != UA_STATUSCODE_GOOD)
  98. return retval;
  99. size_t offset = 8;
  100. retval |= UA_TcpHelloMessage_encodeBinary(&hello, &message, &offset);
  101. messageHeader.messageSize = offset;
  102. offset = 0;
  103. retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &message, &offset);
  104. UA_TcpHelloMessage_deleteMembers(&hello);
  105. if(retval != UA_STATUSCODE_GOOD) {
  106. c->connection.releaseSendBuffer(&c->connection, &message);
  107. return retval;
  108. }
  109. message.length = messageHeader.messageSize;
  110. retval = c->connection.send(&c->connection, &message);
  111. if(retval != UA_STATUSCODE_GOOD)
  112. return retval;
  113. UA_ByteString reply;
  114. UA_ByteString_init(&reply);
  115. do {
  116. retval = c->connection.recv(&c->connection, &reply, c->config.timeout);
  117. if(retval != UA_STATUSCODE_GOOD)
  118. return retval;
  119. } while(!reply.data);
  120. offset = 0;
  121. UA_TcpMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
  122. UA_TcpAcknowledgeMessage ackMessage;
  123. retval = UA_TcpAcknowledgeMessage_decodeBinary(&reply, &offset, &ackMessage);
  124. UA_ByteString_deleteMembers(&reply);
  125. if(retval != UA_STATUSCODE_GOOD)
  126. return retval;
  127. conn->remoteConf.maxChunkCount = ackMessage.maxChunkCount;
  128. conn->remoteConf.maxMessageSize = ackMessage.maxMessageSize;
  129. conn->remoteConf.protocolVersion = ackMessage.protocolVersion;
  130. conn->remoteConf.recvBufferSize = ackMessage.receiveBufferSize;
  131. conn->remoteConf.sendBufferSize = ackMessage.sendBufferSize;
  132. conn->state = UA_CONNECTION_ESTABLISHED;
  133. return UA_STATUSCODE_GOOD;
  134. }
  135. static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
  136. /* Check if sc is still valid */
  137. if(renew && client->scExpiresAt - UA_DateTime_now() > client->config.timeToRenewSecureChannel * 10000 ){
  138. return UA_STATUSCODE_GOOD;
  139. }
  140. UA_SecureConversationMessageHeader messageHeader;
  141. messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
  142. messageHeader.secureChannelId = 0;
  143. UA_SequenceHeader seqHeader;
  144. seqHeader.sequenceNumber = ++client->channel.sequenceNumber;
  145. seqHeader.requestId = ++client->requestId;
  146. UA_AsymmetricAlgorithmSecurityHeader asymHeader;
  147. UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader);
  148. asymHeader.securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
  149. /* id of opensecurechannelrequest */
  150. UA_NodeId requestType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
  151. UA_OpenSecureChannelRequest opnSecRq;
  152. UA_OpenSecureChannelRequest_init(&opnSecRq);
  153. opnSecRq.requestHeader.timestamp = UA_DateTime_now();
  154. opnSecRq.requestHeader.authenticationToken = client->authenticationToken;
  155. opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
  156. if(renew) {
  157. opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW;
  158. } else {
  159. opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
  160. UA_SecureChannel_generateNonce(&client->channel.clientNonce);
  161. UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce);
  162. opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
  163. }
  164. UA_ByteString message;
  165. UA_Connection *c = &client->connection;
  166. UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message);
  167. if(retval != UA_STATUSCODE_GOOD) {
  168. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
  169. UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
  170. return retval;
  171. }
  172. size_t offset = 12;
  173. retval = UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &message, &offset);
  174. retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
  175. retval |= UA_NodeId_encodeBinary(&requestType, &message, &offset);
  176. retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset);
  177. messageHeader.messageHeader.messageSize = offset;
  178. offset = 0;
  179. retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &message, &offset);
  180. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
  181. UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
  182. if(retval != UA_STATUSCODE_GOOD) {
  183. client->connection.releaseSendBuffer(&client->connection, &message);
  184. return retval;
  185. }
  186. message.length = messageHeader.messageHeader.messageSize;
  187. retval = client->connection.send(&client->connection, &message);
  188. if(retval != UA_STATUSCODE_GOOD)
  189. return retval;
  190. UA_ByteString reply;
  191. UA_ByteString_init(&reply);
  192. do {
  193. retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
  194. if(retval != UA_STATUSCODE_GOOD)
  195. return retval;
  196. } while(!reply.data);
  197. offset = 0;
  198. UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
  199. UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &asymHeader);
  200. UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
  201. UA_NodeId_decodeBinary(&reply, &offset, &requestType);
  202. UA_NodeId expectedRequest = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
  203. UA_ENCODINGOFFSET_BINARY);
  204. if(!UA_NodeId_equal(&requestType, &expectedRequest)) {
  205. UA_ByteString_deleteMembers(&reply);
  206. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
  207. UA_NodeId_deleteMembers(&requestType);
  208. UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT,
  209. "Reply answers the wrong request. Expected OpenSecureChannelResponse.");
  210. return UA_STATUSCODE_BADINTERNALERROR;
  211. }
  212. UA_OpenSecureChannelResponse response;
  213. UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response);
  214. client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000;
  215. UA_ByteString_deleteMembers(&reply);
  216. retval = response.responseHeader.serviceResult;
  217. if(!renew && retval == UA_STATUSCODE_GOOD) {
  218. UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel.securityToken);
  219. UA_ByteString_deleteMembers(&client->channel.serverNonce); // if the handshake is repeated
  220. UA_ByteString_copy(&response.serverNonce, &client->channel.serverNonce);
  221. }
  222. UA_OpenSecureChannelResponse_deleteMembers(&response);
  223. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
  224. return retval;
  225. }
  226. /** If the request fails, then the response is cast to UA_ResponseHeader (at the beginning of every
  227. response) and filled with the appropriate error code */
  228. static void synchronousRequest(UA_Client *client, void *request, const UA_DataType *requestType,
  229. void *response, const UA_DataType *responseType) {
  230. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  231. if(!response)
  232. return;
  233. UA_init(response, responseType);
  234. UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response;
  235. //make sure we have a valid session
  236. retval = UA_Client_renewSecureChannel(client);
  237. if(retval != UA_STATUSCODE_GOOD) {
  238. respHeader->serviceResult = retval;
  239. client->state = UA_CLIENTSTATE_ERRORED;
  240. return;
  241. }
  242. /* Copy authenticationToken token to request header */
  243. typedef struct {
  244. UA_RequestHeader requestHeader;
  245. } headerOnlyRequest;
  246. /* The cast is valid, since all requests start with a requestHeader */
  247. UA_NodeId_copy(&client->authenticationToken, &((headerOnlyRequest*)request)->requestHeader.authenticationToken);
  248. /* Send the request */
  249. UA_UInt32 requestId = ++client->requestId;
  250. retval = UA_SecureChannel_sendBinaryMessage(&client->channel, requestId,
  251. request, requestType);
  252. if(retval) {
  253. if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED)
  254. respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE;
  255. else
  256. respHeader->serviceResult = retval;
  257. client->state = UA_CLIENTSTATE_ERRORED;
  258. return;
  259. }
  260. /* Retrieve the response */
  261. // Todo: push this into the generic securechannel implementation for client and server
  262. UA_ByteString reply;
  263. UA_ByteString_init(&reply);
  264. do {
  265. retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
  266. if(retval != UA_STATUSCODE_GOOD) {
  267. respHeader->serviceResult = retval;
  268. client->state = UA_CLIENTSTATE_ERRORED;
  269. return;
  270. }
  271. } while(!reply.data);
  272. size_t offset = 0;
  273. UA_SecureConversationMessageHeader msgHeader;
  274. retval |= UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &msgHeader);
  275. UA_SymmetricAlgorithmSecurityHeader symHeader;
  276. retval |= UA_SymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &symHeader);
  277. UA_SequenceHeader seqHeader;
  278. retval |= UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
  279. UA_NodeId responseId;
  280. retval |= UA_NodeId_decodeBinary(&reply, &offset, &responseId);
  281. UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
  282. UA_ENCODINGOFFSET_BINARY);
  283. if(retval != UA_STATUSCODE_GOOD)
  284. goto finish;
  285. /* Todo: we need to demux responses since a publish responses may come at any time */
  286. if(!UA_NodeId_equal(&responseId, &expectedNodeId) || seqHeader.requestId != requestId) {
  287. if(responseId.identifier.numeric != UA_NS0ID_SERVICEFAULT + UA_ENCODINGOFFSET_BINARY) {
  288. UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT,
  289. "Reply answers the wrong request. Expected ns=%i,i=%i. But retrieved ns=%i,i=%i",
  290. expectedNodeId.namespaceIndex, expectedNodeId.identifier.numeric,
  291. responseId.namespaceIndex, responseId.identifier.numeric);
  292. respHeader->serviceResult = UA_STATUSCODE_BADINTERNALERROR;
  293. } else
  294. retval = UA_decodeBinary(&reply, &offset, respHeader, &UA_TYPES[UA_TYPES_SERVICEFAULT]);
  295. goto finish;
  296. }
  297. retval = UA_decodeBinary(&reply, &offset, response, responseType);
  298. if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED)
  299. retval = UA_STATUSCODE_BADRESPONSETOOLARGE;
  300. finish:
  301. UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
  302. UA_ByteString_deleteMembers(&reply);
  303. if(retval != UA_STATUSCODE_GOOD){
  304. client->state = UA_CLIENTSTATE_ERRORED;
  305. respHeader->serviceResult = retval;
  306. }
  307. }
  308. static UA_StatusCode ActivateSession(UA_Client *client) {
  309. UA_ActivateSessionRequest request;
  310. UA_ActivateSessionRequest_init(&request);
  311. request.requestHeader.requestHandle = 2; //TODO: is it a magic number?
  312. request.requestHeader.authenticationToken = client->authenticationToken;
  313. request.requestHeader.timestamp = UA_DateTime_now();
  314. request.requestHeader.timeoutHint = 10000;
  315. UA_AnonymousIdentityToken identityToken;
  316. UA_AnonymousIdentityToken_init(&identityToken);
  317. UA_String_copy(&client->token.policyId, &identityToken.policyId);
  318. //manual ExtensionObject encoding of the identityToken
  319. request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
  320. request.userIdentityToken.typeId = UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN].typeId;
  321. request.userIdentityToken.typeId.identifier.numeric+=UA_ENCODINGOFFSET_BINARY;
  322. if (identityToken.policyId.length >= 0)
  323. UA_ByteString_newMembers(&request.userIdentityToken.body, identityToken.policyId.length+4);
  324. else {
  325. identityToken.policyId.length = -1;
  326. UA_ByteString_newMembers(&request.userIdentityToken.body, 4);
  327. }
  328. size_t offset = 0;
  329. UA_ByteString_encodeBinary(&identityToken.policyId,&request.userIdentityToken.body,&offset);
  330. UA_ActivateSessionResponse response;
  331. synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
  332. &response, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]);
  333. UA_AnonymousIdentityToken_deleteMembers(&identityToken);
  334. UA_ActivateSessionRequest_deleteMembers(&request);
  335. UA_ActivateSessionResponse_deleteMembers(&response);
  336. return response.responseHeader.serviceResult; // not deleted
  337. }
  338. static UA_StatusCode EndpointsHandshake(UA_Client *client) {
  339. UA_GetEndpointsRequest request;
  340. UA_GetEndpointsRequest_init(&request);
  341. UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
  342. request.requestHeader.timestamp = UA_DateTime_now();
  343. request.requestHeader.timeoutHint = 10000;
  344. UA_String_copy(&client->endpointUrl, &request.endpointUrl);
  345. request.profileUrisSize = 1;
  346. request.profileUris = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], request.profileUrisSize);
  347. *request.profileUris = UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
  348. UA_GetEndpointsResponse response;
  349. UA_GetEndpointsResponse_init(&response);
  350. synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
  351. &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);
  352. UA_Boolean endpointFound = UA_FALSE;
  353. UA_Boolean tokenFound = UA_FALSE;
  354. for(UA_Int32 i=0; i<response.endpointsSize; ++i){
  355. UA_EndpointDescription* endpoint = &response.endpoints[i];
  356. /* look out for an endpoint without security */
  357. if(!UA_String_equal(&endpoint->securityPolicyUri,
  358. &UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None")))
  359. continue;
  360. endpointFound = UA_TRUE;
  361. /* endpoint with no security found */
  362. /* look for a user token policy with an anonymous token */
  363. for(UA_Int32 j=0; j<endpoint->userIdentityTokensSize; ++j) {
  364. UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j];
  365. if(userToken->tokenType != UA_USERTOKENTYPE_ANONYMOUS)
  366. continue;
  367. tokenFound = UA_TRUE;
  368. UA_UserTokenPolicy_copy(userToken, &client->token);
  369. break;
  370. }
  371. }
  372. UA_GetEndpointsRequest_deleteMembers(&request);
  373. UA_GetEndpointsResponse_deleteMembers(&response);
  374. if(!endpointFound){
  375. UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No suitable endpoint found");
  376. return UA_STATUSCODE_BADINTERNALERROR;
  377. }
  378. if(!tokenFound){
  379. UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No anonymous token found");
  380. return UA_STATUSCODE_BADINTERNALERROR;
  381. }
  382. return response.responseHeader.serviceResult;
  383. }
  384. static UA_StatusCode SessionHandshake(UA_Client *client) {
  385. UA_CreateSessionRequest request;
  386. UA_CreateSessionRequest_init(&request);
  387. // todo: is this needed for all requests?
  388. UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
  389. request.requestHeader.timestamp = UA_DateTime_now();
  390. request.requestHeader.timeoutHint = 10000;
  391. UA_ByteString_copy(&client->channel.clientNonce, &request.clientNonce);
  392. request.requestedSessionTimeout = 1200000;
  393. request.maxResponseMessageSize = UA_INT32_MAX;
  394. UA_CreateSessionResponse response;
  395. UA_CreateSessionResponse_init(&response);
  396. synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
  397. &response, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]);
  398. UA_NodeId_copy(&response.authenticationToken, &client->authenticationToken);
  399. UA_CreateSessionRequest_deleteMembers(&request);
  400. UA_CreateSessionResponse_deleteMembers(&response);
  401. return response.responseHeader.serviceResult; // not deleted
  402. }
  403. static UA_StatusCode CloseSession(UA_Client *client) {
  404. UA_CloseSessionRequest request;
  405. UA_CloseSessionRequest_init(&request);
  406. request.requestHeader.timestamp = UA_DateTime_now();
  407. request.requestHeader.timeoutHint = 10000;
  408. request.deleteSubscriptions = UA_TRUE;
  409. UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
  410. UA_CloseSessionResponse response;
  411. synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
  412. &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]);
  413. UA_CloseSessionRequest_deleteMembers(&request);
  414. UA_CloseSessionResponse_deleteMembers(&response);
  415. return response.responseHeader.serviceResult; // not deleted
  416. }
  417. static UA_StatusCode CloseSecureChannel(UA_Client *client) {
  418. UA_SecureChannel *channel = &client->channel;
  419. UA_CloseSecureChannelRequest request;
  420. UA_CloseSecureChannelRequest_init(&request);
  421. request.requestHeader.requestHandle = 1; //TODO: magic number?
  422. request.requestHeader.timestamp = UA_DateTime_now();
  423. request.requestHeader.timeoutHint = 10000;
  424. request.requestHeader.authenticationToken = client->authenticationToken;
  425. UA_SecureConversationMessageHeader msgHeader;
  426. msgHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_CLOF;
  427. msgHeader.secureChannelId = client->channel.securityToken.channelId;
  428. UA_SymmetricAlgorithmSecurityHeader symHeader;
  429. symHeader.tokenId = channel->securityToken.tokenId;
  430. UA_SequenceHeader seqHeader;
  431. seqHeader.sequenceNumber = ++channel->sequenceNumber;
  432. seqHeader.requestId = ++client->requestId;
  433. UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CLOSESECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
  434. UA_ByteString message;
  435. UA_Connection *c = &client->connection;
  436. UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message);
  437. if(retval != UA_STATUSCODE_GOOD)
  438. return retval;
  439. size_t offset = 12;
  440. retval |= UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symHeader, &message, &offset);
  441. retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
  442. retval |= UA_NodeId_encodeBinary(&typeId, &message, &offset);
  443. retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST], &message, &offset);
  444. msgHeader.messageHeader.messageSize = offset;
  445. offset = 0;
  446. retval |= UA_SecureConversationMessageHeader_encodeBinary(&msgHeader, &message, &offset);
  447. if(retval != UA_STATUSCODE_GOOD) {
  448. client->connection.releaseSendBuffer(&client->connection, &message);
  449. return retval;
  450. }
  451. message.length = msgHeader.messageHeader.messageSize;
  452. retval = client->connection.send(&client->connection, &message);
  453. return retval;
  454. }
  455. /*************************/
  456. /* User-Facing Functions */
  457. /*************************/
  458. UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc, char *endpointUrl) {
  459. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  460. /** make the function more convenient to the end-user **/
  461. if(client->state == UA_CLIENTSTATE_CONNECTED){
  462. UA_Client_disconnect(client);
  463. }
  464. if(client->state == UA_CLIENTSTATE_ERRORED){
  465. UA_Client_reset(client);
  466. }
  467. client->connection = connectFunc(UA_ConnectionConfig_standard, endpointUrl, client->logger);
  468. if(client->connection.state != UA_CONNECTION_OPENING){
  469. retval = UA_STATUSCODE_BADCONNECTIONCLOSED;
  470. goto cleanup;
  471. }
  472. client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
  473. if(client->endpointUrl.length < 0){
  474. retval = UA_STATUSCODE_BADOUTOFMEMORY;
  475. goto cleanup;
  476. }
  477. client->connection.localConf = client->config.localConnectionConfig;
  478. retval = HelAckHandshake(client);
  479. if(retval == UA_STATUSCODE_GOOD)
  480. retval = SecureChannelHandshake(client, UA_FALSE);
  481. if(retval == UA_STATUSCODE_GOOD)
  482. retval = EndpointsHandshake(client);
  483. if(retval == UA_STATUSCODE_GOOD)
  484. retval = SessionHandshake(client);
  485. if(retval == UA_STATUSCODE_GOOD)
  486. retval = ActivateSession(client);
  487. if(retval == UA_STATUSCODE_GOOD){
  488. client->connection.state = UA_CONNECTION_ESTABLISHED;
  489. client->state = UA_CLIENTSTATE_CONNECTED;
  490. }else{
  491. goto cleanup;
  492. }
  493. return retval;
  494. cleanup:
  495. client->state = UA_CLIENTSTATE_ERRORED;
  496. UA_Client_reset(client);
  497. return retval;
  498. }
  499. UA_StatusCode UA_Client_disconnect(UA_Client *client) {
  500. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  501. if(client->channel.connection->state == UA_CONNECTION_ESTABLISHED){
  502. retval = CloseSession(client);
  503. if(retval == UA_STATUSCODE_GOOD)
  504. retval = CloseSecureChannel(client);
  505. }
  506. UA_Client_reset(client);
  507. return retval;
  508. }
  509. UA_StatusCode UA_Client_renewSecureChannel(UA_Client *client) {
  510. return SecureChannelHandshake(client, UA_TRUE);
  511. }
  512. UA_ReadResponse UA_Client_read(UA_Client *client, UA_ReadRequest *request) {
  513. UA_ReadResponse response;
  514. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_READREQUEST], &response,
  515. &UA_TYPES[UA_TYPES_READRESPONSE]);
  516. return response;
  517. }
  518. UA_WriteResponse UA_Client_write(UA_Client *client, UA_WriteRequest *request) {
  519. UA_WriteResponse response;
  520. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_WRITEREQUEST], &response,
  521. &UA_TYPES[UA_TYPES_WRITERESPONSE]);
  522. return response;
  523. }
  524. UA_BrowseResponse UA_Client_browse(UA_Client *client, UA_BrowseRequest *request) {
  525. UA_BrowseResponse response;
  526. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
  527. &UA_TYPES[UA_TYPES_BROWSERESPONSE]);
  528. return response;
  529. }
  530. UA_BrowseNextResponse UA_Client_browseNext(UA_Client *client, UA_BrowseNextRequest *request) {
  531. UA_BrowseNextResponse response;
  532. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], &response,
  533. &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]);
  534. return response;
  535. }
  536. UA_TranslateBrowsePathsToNodeIdsResponse
  537. UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
  538. UA_TranslateBrowsePathsToNodeIdsRequest *request) {
  539. UA_TranslateBrowsePathsToNodeIdsResponse response;
  540. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST],
  541. &response, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]);
  542. return response;
  543. }
  544. UA_AddNodesResponse UA_Client_addNodes(UA_Client *client, UA_AddNodesRequest *request) {
  545. UA_AddNodesResponse response;
  546. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_ADDNODESREQUEST],
  547. &response, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]);
  548. return response;
  549. }
  550. UA_AddReferencesResponse UA_Client_addReferences(UA_Client *client, UA_AddReferencesRequest *request) {
  551. UA_AddReferencesResponse response;
  552. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST],
  553. &response, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]);
  554. return response;
  555. }
  556. UA_DeleteNodesResponse UA_Client_deleteNodes(UA_Client *client, UA_DeleteNodesRequest *request) {
  557. UA_DeleteNodesResponse response;
  558. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETENODESREQUEST],
  559. &response, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]);
  560. return response;
  561. }
  562. UA_DeleteReferencesResponse UA_Client_deleteReferences(UA_Client *client, UA_DeleteReferencesRequest *request) {
  563. UA_DeleteReferencesResponse response;
  564. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST],
  565. &response, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]);
  566. return response;
  567. }
  568. #ifdef ENABLE_SUBSCRIPTIONS
  569. UA_CreateSubscriptionResponse UA_Client_createSubscription(UA_Client *client, UA_CreateSubscriptionRequest *request) {
  570. UA_CreateSubscriptionResponse response;
  571. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST],
  572. &response, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]);
  573. return response;
  574. }
  575. UA_DeleteSubscriptionsResponse UA_Client_deleteSubscriptions(UA_Client *client, UA_DeleteSubscriptionsRequest *request) {
  576. UA_DeleteSubscriptionsResponse response;
  577. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST],
  578. &response, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]);
  579. return response;
  580. }
  581. UA_ModifySubscriptionResponse UA_Client_modifySubscription(UA_Client *client, UA_ModifySubscriptionRequest *request) {
  582. UA_ModifySubscriptionResponse response;
  583. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST],
  584. &response, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]);
  585. return response;
  586. }
  587. UA_CreateMonitoredItemsResponse UA_Client_createMonitoredItems(UA_Client *client, UA_CreateMonitoredItemsRequest *request) {
  588. UA_CreateMonitoredItemsResponse response;
  589. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST],
  590. &response, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]);
  591. return response;
  592. }
  593. UA_DeleteMonitoredItemsResponse UA_Client_deleteMonitoredItems(UA_Client *client, UA_DeleteMonitoredItemsRequest *request) {
  594. UA_DeleteMonitoredItemsResponse response;
  595. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST],
  596. &response, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]);
  597. return response;
  598. }
  599. UA_PublishResponse UA_Client_publish(UA_Client *client, UA_PublishRequest *request) {
  600. UA_PublishResponse response;
  601. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_PUBLISHREQUEST],
  602. &response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
  603. return response;
  604. }
  605. UA_Int32 UA_Client_newSubscription(UA_Client *client, UA_Int32 publishInterval) {
  606. UA_Int32 retval;
  607. UA_CreateSubscriptionRequest aReq;
  608. UA_CreateSubscriptionResponse aRes;
  609. UA_CreateSubscriptionRequest_init(&aReq);
  610. UA_CreateSubscriptionResponse_init(&aRes);
  611. aReq.maxNotificationsPerPublish = 10;
  612. aReq.priority = 0;
  613. aReq.publishingEnabled = UA_TRUE;
  614. aReq.requestedLifetimeCount = 100;
  615. aReq.requestedMaxKeepAliveCount = 10;
  616. aReq.requestedPublishingInterval = publishInterval;
  617. aRes = UA_Client_createSubscription(client, &aReq);
  618. if (aRes.responseHeader.serviceResult == UA_STATUSCODE_GOOD) {
  619. UA_Client_Subscription *newSub = UA_malloc(sizeof(UA_Client_Subscription));
  620. LIST_INIT(&newSub->MonitoredItems);
  621. newSub->LifeTime = aRes.revisedLifetimeCount;
  622. newSub->KeepAliveCount = aRes.revisedMaxKeepAliveCount;
  623. newSub->PublishingInterval = aRes.revisedPublishingInterval;
  624. newSub->SubscriptionID = aRes.subscriptionId;
  625. newSub->NotificationsPerPublish = aReq.maxNotificationsPerPublish;
  626. newSub->Priority = aReq.priority;
  627. retval = newSub->SubscriptionID;
  628. LIST_INSERT_HEAD(&(client->subscriptions), newSub, listEntry);
  629. } else
  630. retval = 0;
  631. UA_CreateSubscriptionResponse_deleteMembers(&aRes);
  632. UA_CreateSubscriptionRequest_deleteMembers(&aReq);
  633. return retval;
  634. }
  635. UA_StatusCode UA_Client_removeSubscription(UA_Client *client, UA_UInt32 subscriptionId) {
  636. UA_Client_Subscription *sub;
  637. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  638. LIST_FOREACH(sub, &(client->subscriptions), listEntry) {
  639. if (sub->SubscriptionID == subscriptionId)
  640. break;
  641. }
  642. // Problem? We do not have this subscription registeres. Maybe the server should
  643. // be consulted at this point?
  644. if (sub == NULL)
  645. return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
  646. UA_DeleteSubscriptionsRequest request;
  647. UA_DeleteSubscriptionsResponse response;
  648. UA_DeleteSubscriptionsRequest_init(&request);
  649. UA_DeleteSubscriptionsResponse_init(&response);
  650. request.subscriptionIdsSize=1;
  651. request.subscriptionIds = (UA_UInt32 *) UA_malloc(sizeof(UA_UInt32));
  652. *(request.subscriptionIds) = sub->SubscriptionID;
  653. UA_Client_MonitoredItem *mon, *tmpmon;
  654. LIST_FOREACH_SAFE(mon, &(sub->MonitoredItems), listEntry, tmpmon) {
  655. retval |= UA_Client_unMonitorItemChanges(client, sub->SubscriptionID, mon->MonitoredItemId);
  656. }
  657. if (retval != UA_STATUSCODE_GOOD){
  658. UA_DeleteSubscriptionsRequest_deleteMembers(&request);
  659. return retval;
  660. }
  661. response = UA_Client_deleteSubscriptions(client, &request);
  662. if (response.resultsSize > 0)
  663. retval = response.results[0];
  664. else
  665. retval = response.responseHeader.serviceResult;
  666. if (retval == UA_STATUSCODE_GOOD) {
  667. LIST_REMOVE(sub, listEntry);
  668. UA_free(sub);
  669. }
  670. UA_DeleteSubscriptionsRequest_deleteMembers(&request);
  671. UA_DeleteSubscriptionsResponse_deleteMembers(&response);
  672. return retval;
  673. }
  674. UA_UInt32 UA_Client_monitorItemChanges(UA_Client *client, UA_UInt32 subscriptionId,
  675. UA_NodeId nodeId, UA_UInt32 attributeID, void *handlingFunction) {
  676. UA_Client_Subscription *sub;
  677. UA_StatusCode retval = 0;
  678. LIST_FOREACH(sub, &(client->subscriptions), listEntry) {
  679. if (sub->SubscriptionID == subscriptionId)
  680. break;
  681. }
  682. // Maybe the same problem as in DeleteSubscription... ask the server?
  683. if (sub == NULL)
  684. return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
  685. UA_CreateMonitoredItemsRequest request;
  686. UA_CreateMonitoredItemsResponse response;
  687. UA_CreateMonitoredItemsRequest_init(&request);
  688. UA_CreateMonitoredItemsResponse_init(&response);
  689. request.subscriptionId = subscriptionId;
  690. request.itemsToCreateSize = 1;
  691. request.itemsToCreate = UA_MonitoredItemCreateRequest_new();
  692. UA_NodeId_copy(&nodeId, &((request.itemsToCreate[0]).itemToMonitor.nodeId));
  693. (request.itemsToCreate[0]).itemToMonitor.attributeId = attributeID;
  694. (request.itemsToCreate[0]).monitoringMode = UA_MONITORINGMODE_REPORTING;
  695. (request.itemsToCreate[0]).requestedParameters.clientHandle = ++(client->monitoredItemHandles);
  696. (request.itemsToCreate[0]).requestedParameters.samplingInterval = sub->PublishingInterval;
  697. (request.itemsToCreate[0]).requestedParameters.discardOldest = UA_TRUE;
  698. (request.itemsToCreate[0]).requestedParameters.queueSize = 1;
  699. // Filter can be left void for now, only changes are supported (UA_Expert does the same with changeItems)
  700. response = UA_Client_createMonitoredItems(client, &request);
  701. // slight misuse of retval here to check if the deletion was successfull.
  702. if (response.resultsSize == 0)
  703. retval = response.responseHeader.serviceResult;
  704. else
  705. retval = response.results[0].statusCode;
  706. if (retval == UA_STATUSCODE_GOOD) {
  707. UA_Client_MonitoredItem *newMon = (UA_Client_MonitoredItem *) UA_malloc(sizeof(UA_Client_MonitoredItem));
  708. newMon->MonitoringMode = UA_MONITORINGMODE_REPORTING;
  709. UA_NodeId_copy(&nodeId, &(newMon->monitoredNodeId));
  710. newMon->AttributeID = attributeID;
  711. newMon->ClientHandle = client->monitoredItemHandles;
  712. newMon->SamplingInterval = sub->PublishingInterval;
  713. newMon->QueueSize = 1;
  714. newMon->DiscardOldest = UA_TRUE;
  715. newMon->handler = handlingFunction;
  716. newMon->MonitoredItemId = response.results[0].monitoredItemId;
  717. LIST_INSERT_HEAD(&(sub->MonitoredItems), newMon, listEntry);
  718. retval = newMon->MonitoredItemId ;
  719. }
  720. else {
  721. retval = 0;
  722. }
  723. UA_CreateMonitoredItemsRequest_deleteMembers(&request);
  724. UA_CreateMonitoredItemsResponse_deleteMembers(&response);
  725. return retval;
  726. }
  727. UA_StatusCode UA_Client_unMonitorItemChanges(UA_Client *client, UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId ) {
  728. UA_Client_Subscription *sub;
  729. UA_StatusCode retval = 0;
  730. LIST_FOREACH(sub, &(client->subscriptions), listEntry) {
  731. if (sub->SubscriptionID == subscriptionId)
  732. break;
  733. }
  734. // Maybe the same problem as in DeleteSubscription... ask the server?
  735. if (sub == NULL)
  736. return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
  737. UA_Client_MonitoredItem *mon, *tmpmon;
  738. LIST_FOREACH_SAFE(mon, &(sub->MonitoredItems), listEntry, tmpmon) {
  739. if (mon->MonitoredItemId == monitoredItemId)
  740. break;
  741. }
  742. // Also... ask the server?
  743. if(mon==NULL) {
  744. return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
  745. }
  746. UA_DeleteMonitoredItemsRequest request;
  747. UA_DeleteMonitoredItemsResponse response;
  748. UA_DeleteMonitoredItemsRequest_init(&request);
  749. UA_DeleteMonitoredItemsResponse_init(&response);
  750. request.subscriptionId = sub->SubscriptionID;
  751. request.monitoredItemIdsSize = 1;
  752. request.monitoredItemIds = (UA_UInt32 *) UA_malloc(sizeof(UA_UInt32));
  753. request.monitoredItemIds[0] = mon->MonitoredItemId;
  754. response = UA_Client_deleteMonitoredItems(client, &request);
  755. if (response.resultsSize > 1)
  756. retval = response.results[0];
  757. else
  758. retval = response.responseHeader.serviceResult;
  759. if (retval == 0) {
  760. LIST_REMOVE(mon, listEntry);
  761. UA_NodeId_deleteMembers(&mon->monitoredNodeId);
  762. UA_free(mon);
  763. }
  764. UA_DeleteMonitoredItemsRequest_deleteMembers(&request);
  765. UA_DeleteMonitoredItemsResponse_deleteMembers(&response);
  766. return retval;
  767. }
  768. UA_Boolean UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response) {
  769. UA_Client_Subscription *sub;
  770. UA_Client_MonitoredItem *mon;
  771. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  772. if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  773. return UA_FALSE;
  774. // Check if the server has acknowledged any of our ACKS
  775. // Note that a list of serverside status codes may be send without valid publish data, i.e.
  776. // during keepalives or no data availability
  777. UA_Client_NotificationsAckNumber *tmpAck = client->pendingNotificationsAcks.lh_first;
  778. UA_Client_NotificationsAckNumber *nxtAck = tmpAck;
  779. for(int i=0; i<response.resultsSize && nxtAck != NULL; i++) {
  780. tmpAck = nxtAck;
  781. nxtAck = tmpAck->listEntry.le_next;
  782. if (response.results[i] == UA_STATUSCODE_GOOD || response.results[i] == UA_STATUSCODE_BADSEQUENCENUMBERINVALID) {
  783. LIST_REMOVE(tmpAck, listEntry);
  784. UA_free(tmpAck);
  785. }
  786. }
  787. if(response.subscriptionId == 0)
  788. return UA_FALSE;
  789. LIST_FOREACH(sub, &(client->subscriptions), listEntry) {
  790. if (sub->SubscriptionID == response.subscriptionId)
  791. break;
  792. }
  793. if (sub == NULL)
  794. return UA_FALSE;
  795. UA_NotificationMessage msg = response.notificationMessage;
  796. UA_DataChangeNotification dataChangeNotification;
  797. size_t decodingOffset = 0;
  798. for (int k=0; k<msg.notificationDataSize; k++) {
  799. if (msg.notificationData[k].encoding == UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING) {
  800. if (msg.notificationData[k].typeId.namespaceIndex == 0 && msg.notificationData[k].typeId.identifier.numeric == 811 ) {
  801. // This is a dataChangeNotification
  802. retval |= UA_DataChangeNotification_decodeBinary(&(msg.notificationData[k].body), &decodingOffset, &dataChangeNotification);
  803. UA_MonitoredItemNotification *mitemNot;
  804. for(int i=0; i<dataChangeNotification.monitoredItemsSize; i++) {
  805. mitemNot = &dataChangeNotification.monitoredItems[i];
  806. // find this client handle
  807. LIST_FOREACH(mon, &(sub->MonitoredItems), listEntry) {
  808. if (mon->ClientHandle == mitemNot->clientHandle) {
  809. mon->handler(mitemNot->clientHandle, &(mitemNot->value));
  810. break;
  811. }
  812. }
  813. }
  814. UA_DataChangeNotification_deleteMembers(&dataChangeNotification);
  815. }
  816. else if (msg.notificationData[k].typeId.namespaceIndex == 0 && msg.notificationData[k].typeId.identifier.numeric == 820 ) {
  817. //FIXME: This is a statusChangeNotification (not supported yet)
  818. continue;
  819. }
  820. else if (msg.notificationData[k].typeId.namespaceIndex == 0 && msg.notificationData[k].typeId.identifier.numeric == 916 ) {
  821. //FIXME: This is an EventNotification
  822. continue;
  823. }
  824. }
  825. }
  826. // We processed this message, add it to the list of pending acks (but make sure it's not in the list first)
  827. LIST_FOREACH(tmpAck, &(client->pendingNotificationsAcks), listEntry) {
  828. if (tmpAck->subAck.sequenceNumber == msg.sequenceNumber &&
  829. tmpAck->subAck.subscriptionId == response.subscriptionId)
  830. break;
  831. }
  832. if (tmpAck == NULL ){
  833. tmpAck = (UA_Client_NotificationsAckNumber *) UA_malloc(sizeof(UA_Client_NotificationsAckNumber));
  834. tmpAck->subAck.sequenceNumber = msg.sequenceNumber;
  835. tmpAck->subAck.subscriptionId = sub->SubscriptionID;
  836. tmpAck->listEntry.le_next = UA_NULL;
  837. tmpAck->listEntry.le_prev = UA_NULL;
  838. LIST_INSERT_HEAD(&(client->pendingNotificationsAcks), tmpAck, listEntry);
  839. }
  840. return response.moreNotifications;
  841. }
  842. void UA_Client_doPublish(UA_Client *client) {
  843. UA_PublishRequest request;
  844. UA_PublishResponse response;
  845. UA_Client_NotificationsAckNumber *ack;
  846. UA_Boolean moreNotifications = UA_TRUE;
  847. int index = 0 ;
  848. do {
  849. UA_PublishRequest_init(&request);
  850. UA_PublishResponse_init(&response);
  851. request.subscriptionAcknowledgementsSize = 0;
  852. LIST_FOREACH(ack, &(client->pendingNotificationsAcks), listEntry) {
  853. request.subscriptionAcknowledgementsSize++;
  854. }
  855. request.subscriptionAcknowledgements = (UA_SubscriptionAcknowledgement *) UA_malloc(sizeof(UA_SubscriptionAcknowledgement)*request.subscriptionAcknowledgementsSize);
  856. index = 0;
  857. LIST_FOREACH(ack, &(client->pendingNotificationsAcks), listEntry) {
  858. request.subscriptionAcknowledgements[index].sequenceNumber = ack->subAck.sequenceNumber;
  859. request.subscriptionAcknowledgements[index].subscriptionId = ack->subAck.subscriptionId;
  860. index++;
  861. }
  862. response = UA_Client_publish(client, &request);
  863. if (response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
  864. moreNotifications = UA_Client_processPublishRx(client, response);
  865. else
  866. moreNotifications = UA_FALSE;
  867. UA_PublishResponse_deleteMembers(&response);
  868. UA_PublishRequest_deleteMembers(&request);
  869. } while(moreNotifications == UA_TRUE);
  870. return;
  871. }
  872. #endif
  873. /**********************************/
  874. /* User-Facing Macros-Function */
  875. /**********************************/
  876. #ifdef ENABLE_METHODCALLS
  877. UA_CallResponse UA_Client_call(UA_Client *client, UA_CallRequest *request) {
  878. UA_CallResponse response;
  879. synchronousRequest(client, request, &UA_TYPES[UA_TYPES_CALLREQUEST],
  880. &response, &UA_TYPES[UA_TYPES_CALLRESPONSE]);
  881. return response;
  882. }
  883. UA_StatusCode UA_Client_CallServerMethod(UA_Client *client, UA_NodeId objectNodeId, UA_NodeId methodNodeId,
  884. UA_Int32 inputSize, const UA_Variant *input,
  885. UA_Int32 *outputSize, UA_Variant **output) {
  886. UA_CallRequest request;
  887. UA_CallRequest_init(&request);
  888. request.methodsToCallSize = 1;
  889. request.methodsToCall = UA_CallMethodRequest_new();
  890. if(!request.methodsToCall)
  891. return UA_STATUSCODE_BADOUTOFMEMORY;
  892. UA_CallMethodRequest *rq = &request.methodsToCall[0];
  893. UA_NodeId_copy(&methodNodeId, &rq->methodId);
  894. UA_NodeId_copy(&objectNodeId, &rq->objectId);
  895. rq->inputArguments = (void*)(uintptr_t)input; // cast const...
  896. rq->inputArgumentsSize = inputSize;
  897. UA_CallResponse response;
  898. response = UA_Client_call(client, &request);
  899. rq->inputArguments = UA_NULL;
  900. rq->inputArgumentsSize = -1;
  901. UA_CallRequest_deleteMembers(&request);
  902. UA_StatusCode retval = response.responseHeader.serviceResult;
  903. if(response.resultsSize > 0){
  904. retval |= response.results[0].statusCode;
  905. if(retval == UA_STATUSCODE_GOOD) {
  906. *output = response.results[0].outputArguments;
  907. *outputSize = response.results[0].outputArgumentsSize;
  908. response.results[0].outputArguments = UA_NULL;
  909. response.results[0].outputArgumentsSize = -1;
  910. }
  911. }
  912. UA_CallResponse_deleteMembers(&response);
  913. return retval;
  914. }
  915. #endif
  916. #define ADDNODES_COPYDEFAULTATTRIBUTES(REQUEST,ATTRIBUTES) do { \
  917. ATTRIBUTES.specifiedAttributes = 0; \
  918. if(! UA_LocalizedText_copy(&description, &(ATTRIBUTES.description))) \
  919. ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DESCRIPTION; \
  920. if(! UA_LocalizedText_copy(&displayName, &(ATTRIBUTES.displayName))) \
  921. ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DISPLAYNAME; \
  922. ATTRIBUTES.userWriteMask = userWriteMask; \
  923. ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_USERWRITEMASK; \
  924. ATTRIBUTES.writeMask = writeMask; \
  925. ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_WRITEMASK; \
  926. UA_QualifiedName_copy(&browseName, &(REQUEST.nodesToAdd[0].browseName)); \
  927. UA_ExpandedNodeId_copy(&parentNodeId, &(REQUEST.nodesToAdd[0].parentNodeId)); \
  928. UA_NodeId_copy(&referenceTypeId, &(REQUEST.nodesToAdd[0].referenceTypeId)); \
  929. UA_ExpandedNodeId_copy(&typeDefinition, &(REQUEST.nodesToAdd[0].typeDefinition)); \
  930. UA_ExpandedNodeId_copy(&reqId, &(REQUEST.nodesToAdd[0].requestedNewNodeId )); \
  931. REQUEST.nodesToAddSize = 1; \
  932. } while(0)
  933. #define ADDNODES_PACK_AND_SEND(PREQUEST,PATTRIBUTES,PNODETYPE) do { \
  934. PREQUEST.nodesToAdd[0].nodeAttributes.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING; \
  935. PREQUEST.nodesToAdd[0].nodeAttributes.typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_##PNODETYPE##ATTRIBUTES + UA_ENCODINGOFFSET_BINARY); \
  936. size_t encOffset = 0; \
  937. UA_ByteString_newMembers(&PREQUEST.nodesToAdd[0].nodeAttributes.body, client->connection.remoteConf.maxMessageSize); \
  938. UA_encodeBinary(&PATTRIBUTES,&UA_TYPES[UA_TYPES_##PNODETYPE##ATTRIBUTES], &(PREQUEST.nodesToAdd[0].nodeAttributes.body), &encOffset); \
  939. PREQUEST.nodesToAdd[0].nodeAttributes.body.length = encOffset; \
  940. *(adRes) = UA_Client_addNodes(client, &PREQUEST); \
  941. UA_AddNodesRequest_deleteMembers(&PREQUEST); \
  942. } while(0)
  943. /* NodeManagement */
  944. UA_AddNodesResponse *UA_Client_createObjectNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName,
  945. UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
  946. UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition ) {
  947. UA_AddNodesRequest adReq;
  948. UA_AddNodesRequest_init(&adReq);
  949. UA_AddNodesResponse *adRes;
  950. adRes = UA_AddNodesResponse_new();
  951. UA_AddNodesResponse_init(adRes);
  952. UA_ObjectAttributes vAtt;
  953. UA_ObjectAttributes_init(&vAtt);
  954. adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
  955. UA_AddNodesItem_init(adReq.nodesToAdd);
  956. // Default node properties and attributes
  957. ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
  958. // Specific to objects
  959. adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_OBJECT;
  960. vAtt.eventNotifier = 0;
  961. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_EVENTNOTIFIER;
  962. ADDNODES_PACK_AND_SEND(adReq,vAtt,OBJECT);
  963. return adRes;
  964. }
  965. UA_AddNodesResponse *UA_Client_createVariableNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName,
  966. UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
  967. UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition,
  968. UA_NodeId dataType, UA_Variant *value) {
  969. UA_AddNodesRequest adReq;
  970. UA_AddNodesRequest_init(&adReq);
  971. UA_AddNodesResponse *adRes;
  972. adRes = UA_AddNodesResponse_new();
  973. UA_AddNodesResponse_init(adRes);
  974. UA_VariableAttributes vAtt;
  975. UA_VariableAttributes_init(&vAtt);
  976. adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
  977. UA_AddNodesItem_init(adReq.nodesToAdd);
  978. // Default node properties and attributes
  979. ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
  980. // Specific to variables
  981. adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_VARIABLE;
  982. vAtt.accessLevel = 0;
  983. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_ACCESSLEVEL;
  984. vAtt.userAccessLevel = 0;
  985. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_USERACCESSLEVEL;
  986. vAtt.minimumSamplingInterval = 100;
  987. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL;
  988. vAtt.historizing = UA_FALSE;
  989. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_HISTORIZING;
  990. if (value != NULL) {
  991. UA_Variant_copy(value, &(vAtt.value));
  992. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE;
  993. vAtt.valueRank = -2;
  994. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUERANK;
  995. // These are defined by the variant
  996. //vAtt.arrayDimensionsSize = value->arrayDimensionsSize;
  997. //vAtt.arrayDimensions = NULL;
  998. }
  999. UA_NodeId_copy(&dataType, &(vAtt.dataType));
  1000. ADDNODES_PACK_AND_SEND(adReq,vAtt,VARIABLE);
  1001. return adRes;
  1002. }
  1003. UA_AddNodesResponse *UA_Client_createReferenceTypeNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName,
  1004. UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
  1005. UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition,
  1006. UA_LocalizedText inverseName ) {
  1007. UA_AddNodesRequest adReq;
  1008. UA_AddNodesRequest_init(&adReq);
  1009. UA_AddNodesResponse *adRes;
  1010. adRes = UA_AddNodesResponse_new();
  1011. UA_AddNodesResponse_init(adRes);
  1012. UA_ReferenceTypeAttributes vAtt;
  1013. UA_ReferenceTypeAttributes_init(&vAtt);
  1014. adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
  1015. UA_AddNodesItem_init(adReq.nodesToAdd);
  1016. // Default node properties and attributes
  1017. ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
  1018. // Specific to referencetypes
  1019. adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_REFERENCETYPE;
  1020. UA_LocalizedText_copy(&inverseName, &(vAtt.inverseName));
  1021. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_INVERSENAME;
  1022. vAtt.symmetric = UA_FALSE;
  1023. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_SYMMETRIC;
  1024. vAtt.isAbstract = UA_FALSE;
  1025. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_ISABSTRACT;
  1026. ADDNODES_PACK_AND_SEND(adReq,vAtt,REFERENCETYPE);
  1027. return adRes;
  1028. }
  1029. UA_AddNodesResponse *UA_Client_createObjectTypeNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName,
  1030. UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
  1031. UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition) {
  1032. UA_AddNodesRequest adReq;
  1033. UA_AddNodesRequest_init(&adReq);
  1034. UA_AddNodesResponse *adRes;
  1035. adRes = UA_AddNodesResponse_new();
  1036. UA_AddNodesResponse_init(adRes);
  1037. UA_ObjectTypeAttributes vAtt;
  1038. UA_ObjectTypeAttributes_init(&vAtt);
  1039. adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
  1040. UA_AddNodesItem_init(adReq.nodesToAdd);
  1041. // Default node properties and attributes
  1042. ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
  1043. // Specific to referencetypes
  1044. adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_OBJECTTYPE;
  1045. vAtt.isAbstract = UA_FALSE;
  1046. vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_ISABSTRACT;
  1047. ADDNODES_PACK_AND_SEND(adReq,vAtt,OBJECTTYPE);
  1048. return adRes;
  1049. }