ua_client_connect.c 23 KB

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