ua_client_connect.c 22 KB

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