ua_client_connect.c 24 KB

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