ua_client_connect.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "ua_client.h"
  5. #include "ua_client_internal.h"
  6. #include "ua_transport_generated.h"
  7. #include "ua_transport_generated_handling.h"
  8. #include "ua_transport_generated_encoding_binary.h"
  9. #include "ua_types_encoding_binary.h"
  10. #include "ua_types_generated_encoding_binary.h"
  11. #define UA_MINMESSAGESIZE 8192
  12. /********************/
  13. /* Set client state */
  14. /********************/
  15. static void
  16. setClientState(UA_Client *client, UA_ClientState state)
  17. {
  18. if(client->state != state) {
  19. client->state = state;
  20. if(client->config.stateCallback)
  21. client->config.stateCallback(client, client->state);
  22. }
  23. }
  24. /***********************/
  25. /* Open the Connection */
  26. /***********************/
  27. static UA_StatusCode
  28. processACKResponse(void *application, UA_Connection *connection, UA_ByteString *chunk) {
  29. UA_Client *client = (UA_Client*)application;
  30. /* Decode the message */
  31. size_t offset = 0;
  32. UA_StatusCode retval;
  33. UA_TcpMessageHeader messageHeader;
  34. UA_TcpAcknowledgeMessage ackMessage;
  35. retval = UA_TcpMessageHeader_decodeBinary(chunk, &offset, &messageHeader);
  36. retval |= UA_TcpAcknowledgeMessage_decodeBinary(chunk, &offset, &ackMessage);
  37. if(retval != UA_STATUSCODE_GOOD) {
  38. UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK,
  39. "Decoding ACK message failed");
  40. return retval;
  41. }
  42. /* Store remote connection settings and adjust local configuration to not
  43. * exceed the limits */
  44. UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_NETWORK, "Received ACK message");
  45. connection->remoteConf.maxChunkCount = ackMessage.maxChunkCount; /* may be zero -> unlimited */
  46. connection->remoteConf.maxMessageSize = ackMessage.maxMessageSize; /* may be zero -> unlimited */
  47. connection->remoteConf.protocolVersion = ackMessage.protocolVersion;
  48. connection->remoteConf.sendBufferSize = ackMessage.sendBufferSize;
  49. connection->remoteConf.recvBufferSize = ackMessage.receiveBufferSize;
  50. if(connection->remoteConf.recvBufferSize < connection->localConf.sendBufferSize)
  51. connection->localConf.sendBufferSize = connection->remoteConf.recvBufferSize;
  52. if(connection->remoteConf.sendBufferSize < connection->localConf.recvBufferSize)
  53. connection->localConf.recvBufferSize = connection->remoteConf.sendBufferSize;
  54. connection->state = UA_CONNECTION_ESTABLISHED;
  55. return UA_STATUSCODE_GOOD;
  56. }
  57. static UA_StatusCode
  58. HelAckHandshake(UA_Client *client) {
  59. /* Get a buffer */
  60. UA_ByteString message;
  61. UA_Connection *conn = &client->connection;
  62. UA_StatusCode retval = conn->getSendBuffer(conn, UA_MINMESSAGESIZE, &message);
  63. if(retval != UA_STATUSCODE_GOOD)
  64. return retval;
  65. /* Prepare the HEL message and encode at offset 8 */
  66. UA_TcpHelloMessage hello;
  67. UA_String_copy(&client->endpointUrl, &hello.endpointUrl); /* must be less than 4096 bytes */
  68. hello.maxChunkCount = conn->localConf.maxChunkCount;
  69. hello.maxMessageSize = conn->localConf.maxMessageSize;
  70. hello.protocolVersion = conn->localConf.protocolVersion;
  71. hello.receiveBufferSize = conn->localConf.recvBufferSize;
  72. hello.sendBufferSize = conn->localConf.sendBufferSize;
  73. UA_Byte *bufPos = &message.data[8]; /* skip the header */
  74. const UA_Byte *bufEnd = &message.data[message.length];
  75. retval = UA_TcpHelloMessage_encodeBinary(&hello, &bufPos, &bufEnd);
  76. UA_TcpHelloMessage_deleteMembers(&hello);
  77. /* Encode the message header at offset 0 */
  78. UA_TcpMessageHeader messageHeader;
  79. messageHeader.messageTypeAndChunkType = UA_CHUNKTYPE_FINAL + UA_MESSAGETYPE_HEL;
  80. messageHeader.messageSize = (UA_UInt32)((uintptr_t)bufPos - (uintptr_t)message.data);
  81. bufPos = message.data;
  82. retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &bufPos, &bufEnd);
  83. if(retval != UA_STATUSCODE_GOOD) {
  84. conn->releaseSendBuffer(conn, &message);
  85. return retval;
  86. }
  87. /* Send the HEL message */
  88. message.length = messageHeader.messageSize;
  89. retval = conn->send(conn, &message);
  90. if(retval != UA_STATUSCODE_GOOD) {
  91. UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK,
  92. "Sending HEL failed");
  93. return retval;
  94. }
  95. UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_NETWORK,
  96. "Sent HEL message");
  97. /* Loop until we have a complete chunk */
  98. retval = UA_Connection_receiveChunksBlocking(conn, client, processACKResponse,
  99. client->config.timeout);
  100. if(retval != UA_STATUSCODE_GOOD) {
  101. UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK,
  102. "Receiving ACK message failed");
  103. if(retval == UA_STATUSCODE_BADCONNECTIONCLOSED)
  104. client->state = UA_CLIENTSTATE_DISCONNECTED;
  105. UA_Client_close(client);
  106. }
  107. return retval;
  108. }
  109. static void
  110. processDecodedOPNResponse(UA_Client *client, UA_OpenSecureChannelResponse *response) {
  111. /* Replace the token */
  112. UA_ChannelSecurityToken_deleteMembers(&client->channel.securityToken);
  113. client->channel.securityToken = response->securityToken;
  114. UA_ChannelSecurityToken_init(&response->securityToken);
  115. /* Replace the nonce */
  116. UA_ByteString_deleteMembers(&client->channel.remoteNonce);
  117. client->channel.remoteNonce = response->serverNonce;
  118. UA_ByteString_init(&response->serverNonce);
  119. if(client->channel.state == UA_SECURECHANNELSTATE_OPEN)
  120. UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
  121. "SecureChannel in the server renewed");
  122. else
  123. UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
  124. "Opened SecureChannel acknowledged by the server");
  125. /* Response.securityToken.revisedLifetime is UInt32 we need to cast it to
  126. * DateTime=Int64 we take 75% of lifetime to start renewing as described in
  127. * standard */
  128. client->channel.state = UA_SECURECHANNELSTATE_OPEN;
  129. client->nextChannelRenewal = UA_DateTime_nowMonotonic() + (UA_DateTime)
  130. (client->channel.securityToken.revisedLifetime * (UA_Double)UA_DATETIME_MSEC * 0.75);
  131. }
  132. static UA_StatusCode
  133. openSecureChannel(UA_Client *client, UA_Boolean renew) {
  134. /* Check if sc is still valid */
  135. if(renew && client->nextChannelRenewal > UA_DateTime_nowMonotonic())
  136. return UA_STATUSCODE_GOOD;
  137. UA_Connection *conn = &client->connection;
  138. if(conn->state != UA_CONNECTION_ESTABLISHED)
  139. return UA_STATUSCODE_BADSERVERNOTCONNECTED;
  140. /* Prepare the OpenSecureChannelRequest */
  141. UA_OpenSecureChannelRequest opnSecRq;
  142. UA_OpenSecureChannelRequest_init(&opnSecRq);
  143. opnSecRq.requestHeader.timestamp = UA_DateTime_now();
  144. opnSecRq.requestHeader.authenticationToken = client->authenticationToken;
  145. if(renew) {
  146. opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW;
  147. UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
  148. "Requesting to renew the SecureChannel");
  149. } else {
  150. opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
  151. UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
  152. "Requesting to open a SecureChannel");
  153. }
  154. opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
  155. opnSecRq.clientNonce = client->channel.localNonce;
  156. opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
  157. /* Send the OPN message */
  158. UA_UInt32 requestId = ++client->requestId;
  159. UA_StatusCode retval =
  160. UA_SecureChannel_sendAsymmetricOPNMessage(&client->channel, requestId, &opnSecRq,
  161. &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST]);
  162. if(retval != UA_STATUSCODE_GOOD) {
  163. UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
  164. "Sending OPN message failed with error %s", UA_StatusCode_name(retval));
  165. UA_Client_close(client);
  166. return retval;
  167. }
  168. UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "OPN message sent");
  169. /* Receive / decrypt / decode the OPN response. Process async services in
  170. * the background until the OPN response arrives. */
  171. UA_OpenSecureChannelResponse response;
  172. retval = receiveServiceResponse(client, &response,
  173. &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE],
  174. UA_DateTime_nowMonotonic() +
  175. ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC),
  176. &requestId);
  177. if(retval != UA_STATUSCODE_GOOD) {
  178. UA_Client_close(client);
  179. return retval;
  180. }
  181. processDecodedOPNResponse(client, &response);
  182. UA_OpenSecureChannelResponse_deleteMembers(&response);
  183. return retval;
  184. }
  185. static UA_StatusCode
  186. activateSession(UA_Client *client) {
  187. UA_ActivateSessionRequest request;
  188. UA_ActivateSessionRequest_init(&request);
  189. request.requestHeader.requestHandle = ++client->requestHandle;
  190. request.requestHeader.timestamp = UA_DateTime_now();
  191. request.requestHeader.timeoutHint = 600000;
  192. //manual ExtensionObject encoding of the identityToken
  193. if(client->authenticationMethod == UA_CLIENTAUTHENTICATION_NONE) {
  194. UA_AnonymousIdentityToken* identityToken = UA_AnonymousIdentityToken_new();
  195. UA_AnonymousIdentityToken_init(identityToken);
  196. UA_String_copy(&client->token.policyId, &identityToken->policyId);
  197. request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED;
  198. request.userIdentityToken.content.decoded.type = &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN];
  199. request.userIdentityToken.content.decoded.data = identityToken;
  200. } else {
  201. UA_UserNameIdentityToken* identityToken = UA_UserNameIdentityToken_new();
  202. UA_UserNameIdentityToken_init(identityToken);
  203. UA_String_copy(&client->token.policyId, &identityToken->policyId);
  204. UA_String_copy(&client->username, &identityToken->userName);
  205. UA_String_copy(&client->password, &identityToken->password);
  206. request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED;
  207. request.userIdentityToken.content.decoded.type = &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN];
  208. request.userIdentityToken.content.decoded.data = identityToken;
  209. }
  210. UA_ActivateSessionResponse response;
  211. __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
  212. &response, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]);
  213. if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
  214. UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT,
  215. "ActivateSession failed with error code %s",
  216. UA_StatusCode_name(response.responseHeader.serviceResult));
  217. }
  218. UA_StatusCode retval = response.responseHeader.serviceResult;
  219. UA_ActivateSessionRequest_deleteMembers(&request);
  220. UA_ActivateSessionResponse_deleteMembers(&response);
  221. return retval;
  222. }
  223. /* Gets a list of endpoints. Memory is allocated for endpointDescription array */
  224. UA_StatusCode
  225. UA_Client_getEndpointsInternal(UA_Client *client, size_t* endpointDescriptionsSize,
  226. UA_EndpointDescription** endpointDescriptions) {
  227. UA_GetEndpointsRequest request;
  228. UA_GetEndpointsRequest_init(&request);
  229. request.requestHeader.timestamp = UA_DateTime_now();
  230. request.requestHeader.timeoutHint = 10000;
  231. // assume the endpointurl outlives the service call
  232. request.endpointUrl = client->endpointUrl;
  233. UA_GetEndpointsResponse response;
  234. __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
  235. &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);
  236. if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
  237. UA_StatusCode retval = response.responseHeader.serviceResult;
  238. UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT,
  239. "GetEndpointRequest failed with error code %s",
  240. UA_StatusCode_name(retval));
  241. UA_GetEndpointsResponse_deleteMembers(&response);
  242. return retval;
  243. }
  244. *endpointDescriptions = response.endpoints;
  245. *endpointDescriptionsSize = response.endpointsSize;
  246. response.endpoints = NULL;
  247. response.endpointsSize = 0;
  248. UA_GetEndpointsResponse_deleteMembers(&response);
  249. return UA_STATUSCODE_GOOD;
  250. }
  251. static UA_StatusCode
  252. getEndpoints(UA_Client *client) {
  253. UA_EndpointDescription* endpointArray = NULL;
  254. size_t endpointArraySize = 0;
  255. UA_StatusCode retval =
  256. UA_Client_getEndpointsInternal(client, &endpointArraySize, &endpointArray);
  257. if(retval != UA_STATUSCODE_GOOD)
  258. return retval;
  259. UA_Boolean endpointFound = false;
  260. UA_Boolean tokenFound = false;
  261. UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
  262. UA_String binaryTransport = UA_STRING("http://opcfoundation.org/UA-Profile/"
  263. "Transport/uatcp-uasc-uabinary");
  264. // TODO: compare endpoint information with client->endpointUri
  265. for(size_t i = 0; i < endpointArraySize; ++i) {
  266. UA_EndpointDescription* endpoint = &endpointArray[i];
  267. /* look out for binary transport endpoints */
  268. /* Note: Siemens returns empty ProfileUrl, we will accept it as binary */
  269. if(endpoint->transportProfileUri.length != 0 &&
  270. !UA_String_equal(&endpoint->transportProfileUri, &binaryTransport))
  271. continue;
  272. /* look out for an endpoint without security */
  273. if(!UA_String_equal(&endpoint->securityPolicyUri, &securityNone))
  274. continue;
  275. /* endpoint with no security found */
  276. endpointFound = true;
  277. /* look for a user token policy with an anonymous token */
  278. for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) {
  279. UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j];
  280. /* Usertokens also have a security policy... */
  281. if(userToken->securityPolicyUri.length > 0 &&
  282. !UA_String_equal(&userToken->securityPolicyUri, &securityNone))
  283. continue;
  284. /* UA_CLIENTAUTHENTICATION_NONE == UA_USERTOKENTYPE_ANONYMOUS
  285. * UA_CLIENTAUTHENTICATION_USERNAME == UA_USERTOKENTYPE_USERNAME
  286. * TODO: Check equivalence for other types when adding the support */
  287. if((int)client->authenticationMethod != (int)userToken->tokenType)
  288. continue;
  289. /* Endpoint with matching usertokenpolicy found */
  290. tokenFound = true;
  291. UA_UserTokenPolicy_deleteMembers(&client->token);
  292. UA_UserTokenPolicy_copy(userToken, &client->token);
  293. break;
  294. }
  295. }
  296. UA_Array_delete(endpointArray, endpointArraySize,
  297. &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
  298. if(!endpointFound) {
  299. UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT,
  300. "No suitable endpoint found");
  301. retval = UA_STATUSCODE_BADINTERNALERROR;
  302. } else if(!tokenFound) {
  303. UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT,
  304. "No suitable UserTokenPolicy found for the possible endpoints");
  305. retval = UA_STATUSCODE_BADINTERNALERROR;
  306. }
  307. return retval;
  308. }
  309. static UA_StatusCode
  310. createSession(UA_Client *client) {
  311. UA_CreateSessionRequest request;
  312. UA_CreateSessionRequest_init(&request);
  313. request.requestHeader.timestamp = UA_DateTime_now();
  314. request.requestHeader.timeoutHint = 10000;
  315. UA_ByteString_copy(&client->channel.localNonce, &request.clientNonce);
  316. request.requestedSessionTimeout = 1200000;
  317. request.maxResponseMessageSize = UA_INT32_MAX;
  318. UA_String_copy(&client->endpointUrl, &request.endpointUrl);
  319. UA_CreateSessionResponse response;
  320. __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
  321. &response, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]);
  322. UA_NodeId_copy(&response.authenticationToken, &client->authenticationToken);
  323. UA_StatusCode retval = response.responseHeader.serviceResult;
  324. UA_CreateSessionRequest_deleteMembers(&request);
  325. UA_CreateSessionResponse_deleteMembers(&response);
  326. return retval;
  327. }
  328. UA_StatusCode
  329. UA_Client_connectInternal(UA_Client *client, const char *endpointUrl,
  330. UA_Boolean endpointsHandshake, UA_Boolean createNewSession) {
  331. if(client->state >= UA_CLIENTSTATE_CONNECTED)
  332. return UA_STATUSCODE_GOOD;
  333. UA_ChannelSecurityToken_init(&client->channel.securityToken);
  334. client->channel.state = UA_SECURECHANNELSTATE_FRESH;
  335. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  336. client->connection =
  337. client->config.connectionFunc(client->config.localConnectionConfig,
  338. endpointUrl, client->config.timeout);
  339. if(client->connection.state != UA_CONNECTION_OPENING) {
  340. retval = UA_STATUSCODE_BADCONNECTIONCLOSED;
  341. goto cleanup;
  342. }
  343. UA_String_deleteMembers(&client->endpointUrl);
  344. client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
  345. if(!client->endpointUrl.data) {
  346. retval = UA_STATUSCODE_BADOUTOFMEMORY;
  347. goto cleanup;
  348. }
  349. /* Open a TCP connection */
  350. client->connection.localConf = client->config.localConnectionConfig;
  351. retval = HelAckHandshake(client);
  352. if(retval != UA_STATUSCODE_GOOD)
  353. goto cleanup;
  354. setClientState(client, UA_CLIENTSTATE_CONNECTED);
  355. /* Open a SecureChannel. TODO: Select with endpoint */
  356. client->channel.connection = &client->connection;
  357. retval = openSecureChannel(client, false);
  358. if(retval != UA_STATUSCODE_GOOD)
  359. goto cleanup;
  360. setClientState(client, UA_CLIENTSTATE_SECURECHANNEL);
  361. /* Try to activate an existing Session for this SecureChannel */
  362. if((!UA_NodeId_equal(&client->authenticationToken, &UA_NODEID_NULL)) && (createNewSession)) {
  363. retval = activateSession(client);
  364. if(retval == UA_STATUSCODE_BADSESSIONIDINVALID) {
  365. /* Could not recover an old session. Remove authenticationToken */
  366. UA_NodeId_deleteMembers(&client->authenticationToken);
  367. } else {
  368. if(retval != UA_STATUSCODE_GOOD)
  369. goto cleanup;
  370. setClientState(client, UA_CLIENTSTATE_SESSION_RENEWED);
  371. return retval;
  372. }
  373. } else {
  374. UA_NodeId_deleteMembers(&client->authenticationToken);
  375. }
  376. /* Get Endpoints */
  377. if(endpointsHandshake) {
  378. retval = getEndpoints(client);
  379. if(retval != UA_STATUSCODE_GOOD)
  380. goto cleanup;
  381. }
  382. /* Create the Session for this SecureChannel */
  383. if(createNewSession) {
  384. retval = createSession(client);
  385. if(retval != UA_STATUSCODE_GOOD)
  386. goto cleanup;
  387. #ifdef UA_ENABLE_SUBSCRIPTIONS
  388. /* A new session has been created. We need to clean up the subscriptions */
  389. UA_Client_Subscriptions_clean(client);
  390. #endif
  391. retval = activateSession(client);
  392. if(retval != UA_STATUSCODE_GOOD)
  393. goto cleanup;
  394. setClientState(client, UA_CLIENTSTATE_SESSION);
  395. }
  396. return retval;
  397. cleanup:
  398. UA_Client_close(client);
  399. return retval;
  400. }
  401. UA_StatusCode
  402. UA_Client_connect(UA_Client *client, const char *endpointUrl) {
  403. return UA_Client_connectInternal(client, endpointUrl, UA_TRUE, UA_TRUE);
  404. }
  405. UA_StatusCode
  406. UA_Client_connect_username(UA_Client *client, const char *endpointUrl,
  407. const char *username, const char *password) {
  408. client->authenticationMethod = UA_CLIENTAUTHENTICATION_USERNAME;
  409. client->username = UA_STRING_ALLOC(username);
  410. client->password = UA_STRING_ALLOC(password);
  411. return UA_Client_connect(client, endpointUrl);
  412. }
  413. UA_StatusCode
  414. UA_Client_manuallyRenewSecureChannel(UA_Client *client) {
  415. UA_StatusCode retval = openSecureChannel(client, true);
  416. if(retval != UA_STATUSCODE_GOOD)
  417. UA_Client_close(client);
  418. return retval;
  419. }
  420. /************************/
  421. /* Close the Connection */
  422. /************************/
  423. static void
  424. sendCloseSession(UA_Client *client) {
  425. UA_CloseSessionRequest request;
  426. UA_CloseSessionRequest_init(&request);
  427. request.requestHeader.timestamp = UA_DateTime_now();
  428. request.requestHeader.timeoutHint = 10000;
  429. request.deleteSubscriptions = true;
  430. UA_CloseSessionResponse response;
  431. __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
  432. &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]);
  433. UA_CloseSessionRequest_deleteMembers(&request);
  434. UA_CloseSessionResponse_deleteMembers(&response);
  435. }
  436. static void
  437. sendCloseSecureChannel(UA_Client *client) {
  438. UA_SecureChannel *channel = &client->channel;
  439. UA_CloseSecureChannelRequest request;
  440. UA_CloseSecureChannelRequest_init(&request);
  441. request.requestHeader.requestHandle = ++client->requestHandle;
  442. request.requestHeader.timestamp = UA_DateTime_now();
  443. request.requestHeader.timeoutHint = 10000;
  444. request.requestHeader.authenticationToken = client->authenticationToken;
  445. UA_SecureChannel_sendSymmetricMessage(channel, ++client->requestId,
  446. UA_MESSAGETYPE_CLO, &request,
  447. &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST]);
  448. UA_CloseSecureChannelRequest_deleteMembers(&request);
  449. UA_SecureChannel_deleteMembersCleanup(&client->channel);
  450. }
  451. UA_StatusCode
  452. UA_Client_disconnect(UA_Client *client) {
  453. /* Is a session established? */
  454. if(client->state >= UA_CLIENTSTATE_SESSION) {
  455. client->state = UA_CLIENTSTATE_SECURECHANNEL;
  456. sendCloseSession(client);
  457. }
  458. UA_NodeId_deleteMembers(&client->authenticationToken);
  459. client->requestHandle = 0;
  460. /* Is a secure channel established? */
  461. if(client->state >= UA_CLIENTSTATE_SECURECHANNEL) {
  462. client->state = UA_CLIENTSTATE_CONNECTED;
  463. sendCloseSecureChannel(client);
  464. }
  465. /* Close the TCP connection */
  466. if(client->connection.state != UA_CONNECTION_CLOSED)
  467. client->connection.close(&client->connection);
  468. setClientState(client, UA_CLIENTSTATE_DISCONNECTED);
  469. return UA_STATUSCODE_GOOD;
  470. }
  471. UA_StatusCode
  472. UA_Client_close(UA_Client *client) {
  473. client->requestHandle = 0;
  474. if(client->state >= UA_CLIENTSTATE_SECURECHANNEL)
  475. UA_SecureChannel_deleteMembersCleanup(&client->channel);
  476. /* Close the TCP connection */
  477. if(client->connection.state != UA_CONNECTION_CLOSED)
  478. client->connection.close(&client->connection);
  479. setClientState(client, UA_CLIENTSTATE_DISCONNECTED);
  480. return UA_STATUSCODE_GOOD;
  481. }