|
@@ -1,5 +1,6 @@
|
|
|
#include "ua_util.h"
|
|
|
#include "ua_client.h"
|
|
|
+#include "ua_client_highlevel.h"
|
|
|
#include "ua_client_internal.h"
|
|
|
#include "ua_types_generated.h"
|
|
|
#include "ua_nodeids.h"
|
|
@@ -50,13 +51,30 @@ UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
|
|
|
return client;
|
|
|
}
|
|
|
|
|
|
-static void UA_Client_deleteMembers(UA_Client* client){
|
|
|
+static void UA_Client_deleteMembers(UA_Client* client) {
|
|
|
UA_Client_disconnect(client);
|
|
|
UA_Connection_deleteMembers(&client->connection);
|
|
|
UA_SecureChannel_deleteMembersCleanup(&client->channel);
|
|
|
if(client->endpointUrl.data)
|
|
|
UA_String_deleteMembers(&client->endpointUrl);
|
|
|
UA_UserTokenPolicy_deleteMembers(&client->token);
|
|
|
+#ifdef ENABLE_SUBSCRIPTIONS
|
|
|
+ UA_Client_NotificationsAckNumber *n, *tmp;
|
|
|
+ LIST_FOREACH_SAFE(n, &client->pendingNotificationsAcks, listEntry, tmp) {
|
|
|
+ LIST_REMOVE(n, listEntry);
|
|
|
+ free(n);
|
|
|
+ }
|
|
|
+ UA_Client_Subscription *sub, *tmps;
|
|
|
+ LIST_FOREACH_SAFE(sub, &client->subscriptions, listEntry, tmps) {
|
|
|
+ LIST_REMOVE(sub, listEntry);
|
|
|
+ UA_Client_MonitoredItem *mon, *tmpmon;
|
|
|
+ LIST_FOREACH_SAFE(mon, &sub->MonitoredItems, listEntry, tmpmon) {
|
|
|
+ UA_Client_Subscriptions_removeMonitoredItem(client, sub->SubscriptionID,
|
|
|
+ mon->MonitoredItemId);
|
|
|
+ }
|
|
|
+ free(sub);
|
|
|
+ }
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
void UA_Client_reset(UA_Client* client){
|
|
@@ -108,32 +126,38 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
|
|
|
message.length = messageHeader.messageSize;
|
|
|
retval = c->connection.send(&c->connection, &message);
|
|
|
if(retval != UA_STATUSCODE_GOOD) {
|
|
|
- UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Sending HEL failed");
|
|
|
+ UA_LOG_INFO(c->logger, UA_LOGCATEGORY_NETWORK, "Sending HEL failed");
|
|
|
return retval;
|
|
|
}
|
|
|
UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Sent HEL message");
|
|
|
|
|
|
UA_ByteString reply;
|
|
|
UA_ByteString_init(&reply);
|
|
|
+ UA_Boolean realloced = UA_FALSE;
|
|
|
do {
|
|
|
retval = c->connection.recv(&c->connection, &reply, c->config.timeout);
|
|
|
+ retval |= UA_Connection_completeMessages(&c->connection, &reply, &realloced);
|
|
|
if(retval != UA_STATUSCODE_GOOD) {
|
|
|
- UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Receiving ACK message failed");
|
|
|
+ UA_LOG_INFO(c->logger, UA_LOGCATEGORY_NETWORK, "Receiving ACK message failed");
|
|
|
return retval;
|
|
|
}
|
|
|
- } while(!reply.data);
|
|
|
+ } while(reply.length == 0);
|
|
|
|
|
|
offset = 0;
|
|
|
UA_TcpMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
|
|
|
UA_TcpAcknowledgeMessage ackMessage;
|
|
|
retval = UA_TcpAcknowledgeMessage_decodeBinary(&reply, &offset, &ackMessage);
|
|
|
- UA_ByteString_deleteMembers(&reply);
|
|
|
+ if(!realloced)
|
|
|
+ c->connection.releaseRecvBuffer(&c->connection, &reply);
|
|
|
+ else
|
|
|
+ UA_ByteString_deleteMembers(&reply);
|
|
|
+
|
|
|
if(retval != UA_STATUSCODE_GOOD) {
|
|
|
- UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Decoding ACK message failed");
|
|
|
+ UA_LOG_INFO(c->logger, UA_LOGCATEGORY_NETWORK, "Decoding ACK message failed");
|
|
|
return retval;
|
|
|
}
|
|
|
-
|
|
|
UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Received ACK message");
|
|
|
+
|
|
|
conn->remoteConf.maxChunkCount = ackMessage.maxChunkCount;
|
|
|
conn->remoteConf.maxMessageSize = ackMessage.maxMessageSize;
|
|
|
conn->remoteConf.protocolVersion = ackMessage.protocolVersion;
|
|
@@ -214,14 +238,16 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
|
|
|
|
|
|
UA_ByteString reply;
|
|
|
UA_ByteString_init(&reply);
|
|
|
+ UA_Boolean realloced = UA_FALSE;
|
|
|
do {
|
|
|
- retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
|
|
|
+ retval = c->recv(c, &reply, client->config.timeout);
|
|
|
+ retval |= UA_Connection_completeMessages(c, &reply, &realloced);
|
|
|
if(retval != UA_STATUSCODE_GOOD) {
|
|
|
UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL,
|
|
|
"Receiving OpenSecureChannelResponse failed");
|
|
|
return retval;
|
|
|
}
|
|
|
- } while(!reply.data);
|
|
|
+ } while(reply.length == 0);
|
|
|
|
|
|
offset = 0;
|
|
|
UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
|
|
@@ -242,10 +268,14 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
|
|
|
UA_OpenSecureChannelResponse response;
|
|
|
UA_OpenSecureChannelResponse_init(&response);
|
|
|
retval = UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response);
|
|
|
+ if(!realloced)
|
|
|
+ c->releaseRecvBuffer(c, &reply);
|
|
|
+ else
|
|
|
+ UA_ByteString_deleteMembers(&reply);
|
|
|
+
|
|
|
if(retval != UA_STATUSCODE_GOOD) {
|
|
|
UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL,
|
|
|
"Decoding OpenSecureChannelResponse failed");
|
|
|
- UA_ByteString_deleteMembers(&reply);
|
|
|
UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
|
|
|
UA_OpenSecureChannelResponse_init(&response);
|
|
|
response.responseHeader.serviceResult = retval;
|
|
@@ -253,7 +283,6 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
|
|
|
}
|
|
|
|
|
|
client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000;
|
|
|
- UA_ByteString_deleteMembers(&reply);
|
|
|
retval = response.responseHeader.serviceResult;
|
|
|
|
|
|
if(retval != UA_STATUSCODE_GOOD)
|
|
@@ -546,8 +575,10 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
|
|
|
// Todo: push this into the generic securechannel implementation for client and server
|
|
|
UA_ByteString reply;
|
|
|
UA_ByteString_init(&reply);
|
|
|
+ UA_Boolean realloced = UA_FALSE;
|
|
|
do {
|
|
|
retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
|
|
|
+ retval |= UA_Connection_completeMessages(&client->connection, &reply, &realloced);
|
|
|
if(retval != UA_STATUSCODE_GOOD) {
|
|
|
respHeader->serviceResult = retval;
|
|
|
client->state = UA_CLIENTSTATE_ERRORED;
|
|
@@ -567,9 +598,8 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
|
|
|
UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
|
|
|
UA_ENCODINGOFFSET_BINARY);
|
|
|
|
|
|
- if(retval != UA_STATUSCODE_GOOD) {
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
|
goto finish;
|
|
|
- }
|
|
|
|
|
|
/* Todo: we need to demux responses since a publish responses may come at any time */
|
|
|
if(!UA_NodeId_equal(&responseId, &expectedNodeId) || seqHeader.requestId != requestId) {
|
|
@@ -590,7 +620,10 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
|
|
|
|
|
|
finish:
|
|
|
UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
|
|
|
- UA_ByteString_deleteMembers(&reply);
|
|
|
+ if(!realloced)
|
|
|
+ client->connection.releaseRecvBuffer(&client->connection, &reply);
|
|
|
+ else
|
|
|
+ UA_ByteString_deleteMembers(&reply);
|
|
|
if(retval != UA_STATUSCODE_GOOD){
|
|
|
UA_LOG_INFO(client->logger, UA_LOGCATEGORY_CLIENT, "Error receiving the response");
|
|
|
client->state = UA_CLIENTSTATE_ERRORED;
|