Просмотр исходного кода

start making session behavior compliant with CTT

Julius Pfrommer лет назад: 9
Родитель
Сommit
85f82c3e14

+ 12 - 8
plugins/networklayer_tcp.c

@@ -237,7 +237,7 @@ typedef struct {
     UA_ConnectionConfig conf;
     UA_UInt16 port;
     UA_Logger logger; // Set during start
-    
+
     /* open sockets and connections */
     UA_Int32 serversockfd;
     size_t mappingsSize;
@@ -291,7 +291,7 @@ ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
 #endif
     //cppcheck-suppress unreadVariable
     ServerNetworkLayerTCP *layer = connection->handle;
-    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Closing the connection",
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Force closing the connection",
                 connection->sockfd);
     /* only "shutdown" here. this triggers the select, where the socket is
        "closed" in the mainloop */
@@ -346,12 +346,13 @@ ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, UA_Logger logger) {
 #ifndef _MSC_VER
         du.length = (size_t)snprintf(discoveryUrl, 255, "opc.tcp://%s:%d", hostname, layer->port);
 #else
-        du.length = (size_t)_snprintf_s(discoveryUrl, 255, _TRUNCATE, "opc.tcp://%s:%d", hostname, layer->port);
+        du.length = (size_t)_snprintf_s(discoveryUrl, 255, _TRUNCATE,
+                                        "opc.tcp://%s:%d", hostname, layer->port);
 #endif
         du.data = (UA_Byte*)discoveryUrl;
     }
     UA_String_copy(&du, &nl->discoveryUrl);
-    
+
     /* open the server socket */
 #ifdef _WIN32
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
@@ -428,9 +429,10 @@ ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt1
     size_t j = 0;
     UA_ByteString buf = UA_BYTESTRING_NULL;
     for(size_t i = 0; i < layer->mappingsSize && j < (size_t)resultsize; i++) {
-        if(!UA_fd_isset(layer->mappings[i].sockfd, &errset) && !UA_fd_isset(layer->mappings[i].sockfd, &fdset)) {
+        if(!UA_fd_isset(layer->mappings[i].sockfd, &errset) &&
+           !UA_fd_isset(layer->mappings[i].sockfd, &fdset))
           continue;
-        }
+
         UA_StatusCode retval = socket_recv(layer->mappings[i].connection, &buf, 0);
         if(retval == UA_STATUSCODE_GOOD) {
             js[j].job.binaryMessage.connection = layer->mappings[i].connection;
@@ -439,6 +441,8 @@ ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt1
             j++;
         } else if (retval == UA_STATUSCODE_BADCONNECTIONCLOSED) {
             UA_Connection *c = layer->mappings[i].connection;
+            UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
+                        "Connection %i | Connection closed from remote", c->sockfd);
             /* the socket was closed from remote */
             js[j].type = UA_JOBTYPE_DETACHCONNECTION;
             js[j].job.closeConnection = layer->mappings[i].connection;
@@ -453,8 +457,8 @@ ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt1
     }
 
     if(j == 0) {
-    	free(js);
-    	js = NULL;
+        free(js);
+        js = NULL;
     }
 
     *jobs = js;

+ 15 - 15
src/server/ua_securechannel_manager.c

@@ -105,13 +105,11 @@ UA_SecureChannelManager_renew(UA_SecureChannelManager *cm, UA_Connection *conn,
     /* if no security token is already issued */
     if(channel->nextSecurityToken.tokenId == 0) {
         channel->nextSecurityToken.channelId = channel->securityToken.channelId;
-        //FIXME: UaExpert seems not to use the new tokenid
         channel->nextSecurityToken.tokenId = cm->lastTokenId++;
-        //channel->nextSecurityToken.tokenId = channel->securityToken.tokenId;
         channel->nextSecurityToken.createdAt = UA_DateTime_now();
         channel->nextSecurityToken.revisedLifetime =
-                (request->requestedLifetime > cm->server->config.maxSecurityTokenLifetime) ?
-                        cm->server->config.maxSecurityTokenLifetime : request->requestedLifetime;
+            (request->requestedLifetime > cm->server->config.maxSecurityTokenLifetime) ?
+            cm->server->config.maxSecurityTokenLifetime : request->requestedLifetime;
         /* lifetime 0 -> return the max lifetime */
         if(channel->nextSecurityToken.revisedLifetime == 0)
             channel->nextSecurityToken.revisedLifetime = cm->server->config.maxSecurityTokenLifetime;
@@ -138,18 +136,20 @@ UA_SecureChannel * UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_U
 UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
     channel_list_entry *entry;
     LIST_FOREACH(entry, &cm->channels, pointers) {
-        if(entry->channel.securityToken.channelId == channelId) {
-            LIST_REMOVE(entry, pointers);
-            UA_SecureChannel_deleteMembersCleanup(&entry->channel);
+        if(entry->channel.securityToken.channelId == channelId)
+            break;
+    }
+    if(!entry)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    LIST_REMOVE(entry, pointers);
+    UA_SecureChannel_deleteMembersCleanup(&entry->channel);
 #ifndef UA_ENABLE_MULTITHREADING
-            cm->currentChannelCount--;
-            UA_free(entry);
+    cm->currentChannelCount--;
+    UA_free(entry);
 #else
-            cm->currentChannelCount = uatomic_add_return(&cm->currentChannelCount, -1);
-            UA_Server_delayedFree(cm->server, entry);
+    cm->currentChannelCount = uatomic_add_return(&cm->currentChannelCount, -1);
+    UA_Server_delayedFree(cm->server, entry);
 #endif
-            return UA_STATUSCODE_GOOD;
-        }
-    }
-    return UA_STATUSCODE_BADINTERNALERROR;
+    return UA_STATUSCODE_GOOD;
 }

+ 112 - 90
src/server/ua_server_binary.c

@@ -17,19 +17,20 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
 }
 
 static void
-sendError(UA_SecureChannel *channel, const UA_ByteString *msg, size_t pos,
+sendError(UA_SecureChannel *channel, const UA_ByteString *msg, size_t pos, const UA_DataType *responseType,
           UA_UInt32 requestId, UA_StatusCode error) {
-    UA_RequestHeader p;
-    if(UA_RequestHeader_decodeBinary(msg, &pos, &p) != UA_STATUSCODE_GOOD)
+    UA_RequestHeader requestHeader;
+    UA_StatusCode retval = UA_RequestHeader_decodeBinary(msg, &pos, &requestHeader);
+    if(retval != UA_STATUSCODE_GOOD)
         return;
-    UA_ResponseHeader r;
-    UA_ResponseHeader_init(&r);
-    init_response_header(&p, &r);
-    r.serviceResult = error;
-    UA_SecureChannel_sendBinaryMessage(channel, requestId, &r,
-                                       &UA_TYPES[UA_TYPES_SERVICEFAULT]);
-    UA_RequestHeader_deleteMembers(&p);
-    UA_ResponseHeader_deleteMembers(&r);
+    void *response = UA_alloca(responseType->memSize);
+    UA_init(response, responseType);
+    UA_ResponseHeader *responseHeader = (UA_ResponseHeader*)response;
+    init_response_header(&requestHeader, responseHeader);
+    responseHeader->serviceResult = error;
+    UA_SecureChannel_sendBinaryMessage(channel, requestId, response, responseType);
+    UA_RequestHeader_deleteMembers(&requestHeader);
+    UA_ResponseHeader_deleteMembers(responseHeader);
 }
 
 /* Returns a complete decoded request (without securechannel headers + padding)
@@ -60,22 +61,26 @@ static UA_ByteString processChunk(UA_SecureChannel *channel, UA_Server *server,
 
 static void
 getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
-                   const UA_DataType **responseType, UA_Service *service) {
+                   const UA_DataType **responseType, UA_Service *service,
+                   UA_Boolean *requiresSession) {
     switch(requestTypeId - UA_ENCODINGOFFSET_BINARY) {
     case UA_NS0ID_GETENDPOINTSREQUEST:
         *service = (UA_Service)Service_GetEndpoints;
         *requestType = &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE];
+        *requiresSession = false;
         break;
     case UA_NS0ID_FINDSERVERSREQUEST:
         *service = (UA_Service)Service_FindServers;
         *requestType = &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE];
+        *requiresSession = false;
         break;
     case UA_NS0ID_CREATESESSIONREQUEST:
         *service = (UA_Service)Service_CreateSession;
         *requestType = &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE];
+        *requiresSession = false;
         break;
     case UA_NS0ID_ACTIVATESESSIONREQUEST:
         *service = (UA_Service)Service_ActivateSession;
@@ -244,8 +249,7 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size
 
     UA_ByteString ack_msg;
     UA_ByteString_init(&ack_msg);
-    if(connection->getSendBuffer(connection, connection->localConf.sendBufferSize,
-                                 &ack_msg) != UA_STATUSCODE_GOOD)
+    if(connection->getSendBuffer(connection, connection->localConf.sendBufferSize, &ack_msg) != UA_STATUSCODE_GOOD)
         return;
 
     size_t tmpPos = 0;
@@ -318,8 +322,7 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     respHeader.messageHeader.messageSize = 0;
     respHeader.secureChannelId = p.securityToken.channelId;
 
-    UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
-                                               UA_ENCODINGOFFSET_BINARY);
+    UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE + UA_ENCODINGOFFSET_BINARY);
 
     UA_ByteString resp_msg;
     UA_ByteString_init(&resp_msg);
@@ -356,81 +359,103 @@ processRequest(UA_SecureChannel *channel, UA_Server *server, UA_UInt32 requestId
     size_t ppos = 0;
     size_t *pos = &ppos;
 
+    /* Decode the nodeid */
     UA_NodeId requestTypeId;
     UA_StatusCode retval = UA_NodeId_decodeBinary(msg, pos, &requestTypeId);
-    if(retval != UA_STATUSCODE_GOOD) {
-        sendError(channel, msg, *pos, requestId, retval);
+    if(retval != UA_STATUSCODE_GOOD)
         return;
-    }
+
+    /* Store the start-position of the request */
+    size_t requestPos = *pos;
 
     /* Test if the service type nodeid has the right format */
     if(requestTypeId.identifierType != UA_NODEIDTYPE_NUMERIC ||
        requestTypeId.namespaceIndex != 0) {
         UA_NodeId_deleteMembers(&requestTypeId);
-        sendError(channel, msg, *pos, requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
-        return;
+        sendError(channel, msg, requestPos, &UA_TYPES[UA_TYPES_SERVICEFAULT], requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
     }
 
     /* Get the service pointers */
     UA_Service service = NULL;
     const UA_DataType *requestType = NULL;
     const UA_DataType *responseType = NULL;
-    getServicePointers(requestTypeId.identifier.numeric, &requestType, &responseType, &service);
+    UA_Boolean sessionRequired = true;
+    getServicePointers(requestTypeId.identifier.numeric, &requestType, &responseType, &service, &sessionRequired);
     if(!requestType) {
-        /* The service is not supported */
-        if(requestTypeId.identifier.numeric==787) {
-            UA_LOG_INFO_CHANNEL(server->config.logger, channel,
-                        "Client requested a subscription, but those are not enabled "
-                        "in the build. The message will be skipped");
+        if(requestTypeId.identifier.numeric == 787) {
+            UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Client requested a subscription, but those are not enabled in the build");
         } else {
-            UA_LOG_INFO_CHANNEL(server->config.logger, channel,
-                                "Unknown request: NodeId(ns=%d, i=%d)",
-                                requestTypeId.namespaceIndex, requestTypeId.identifier.numeric);
+            UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Unknown request %i", requestTypeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY);
         }
-        sendError(channel, msg, *pos, requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
+        sendError(channel, msg, requestPos, &UA_TYPES[UA_TYPES_SERVICEFAULT], requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
         return;
     }
+    UA_assert(responseType);
 
-    /* Most services can only be called with a valid securechannel */
-#ifndef UA_ENABLE_NONSTANDARD_STATELESS
-    if(channel->securityToken.channelId == 0 &&
-       requestType->typeIndex > UA_TYPES_OPENSECURECHANNELREQUEST) {
-        sendError(channel, msg, *pos, requestId, UA_STATUSCODE_BADSECURECHANNELIDINVALID);
-        return;
-    }
+#ifdef UA_ENABLE_NONSTANDARD_STATELESS
+    /* Stateless extension: Sessions are optional */
+    sessionRequired = false;
 #endif
 
     /* Decode the request */
     void *request = UA_alloca(requestType->memSize);
-    size_t oldpos = *pos;
+    UA_RequestHeader *requestHeader = (UA_RequestHeader*)request;
     retval = UA_decodeBinary(msg, pos, request, requestType);
     if(retval != UA_STATUSCODE_GOOD) {
-        sendError(channel, msg, oldpos, requestId, retval);
+        sendError(channel, msg, requestPos, &UA_TYPES[UA_TYPES_SERVICEFAULT], requestId, retval);
         return;
     }
 
+    /* Prepare the respone */
+    void *response = UA_alloca(responseType->memSize);
+    UA_init(response, responseType);
+
     /* Find the matching session */
-    UA_Session *session =
-        UA_SecureChannel_getSession(channel, &((UA_RequestHeader*)request)->authenticationToken);
+    UA_Session *session = UA_SecureChannel_getSession(channel, &requestHeader->authenticationToken);
+
+    /* CreateSession and ActivateSession don't need a session */
+    if(requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]) {
+        Service_CreateSession(server, channel, request, response);
+        goto send_response;
+    }
+    if(requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST]) {
+        /* Search in all sessions, not only those of the channel */
+        if(!session)
+            session = UA_SessionManager_getSession(&server->sessionManager, &requestHeader->authenticationToken);
+        if(!session) {
+            sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
+            UA_deleteMembers(request, requestType);
+            return;
+        }
+        Service_ActivateSession(server, channel, session, request, response);
+        goto send_response;
+    }
+
+    /* Test if the session is valid */
     UA_Session anonymousSession;
     if(!session) {
-        /* session id 0 -> anonymous session */
+        if(sessionRequired || !UA_NodeId_equal(&requestHeader->authenticationToken, &UA_NODEID_NULL)) {
+            UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Service request %i without a valid session",
+                                requestTypeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY);
+            sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
+            UA_deleteMembers(request, requestType);
+            return;
+        }
+
+        /* Set an anonymous, inactive session */
         UA_Session_init(&anonymousSession);
         anonymousSession.sessionId = UA_NODEID_NUMERIC(0,0);
         anonymousSession.channel = channel;
-        anonymousSession.activated = true;
         session = &anonymousSession;
     }
 
-    /* Test if the session is valid */
-    if(!session->activated &&
-       requestType->typeIndex != UA_TYPES_CREATESESSIONREQUEST &&
-       requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST &&
-       requestType->typeIndex != UA_TYPES_FINDSERVERSREQUEST &&
-       requestType->typeIndex != UA_TYPES_GETENDPOINTSREQUEST &&
-       requestType->typeIndex != UA_TYPES_OPENSECURECHANNELREQUEST) {
-        UA_LOG_INFO_SESSION(server->config.logger, session, "Service request on a non-activated session");
-        sendError(channel, msg, *pos, requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
+    /* Trying to use a non-activated session? */
+    if(!session->activated && sessionRequired) {
+        UA_LOG_INFO_SESSION(server->config.logger, session, "Calling service %i on a non-activated session",
+                            requestTypeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY);
+        sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
+        UA_SessionManager_removeSession(&server->sessionManager, &session->authenticationToken);
+        UA_deleteMembers(request, requestType);
         return;
     }
 
@@ -439,7 +464,7 @@ processRequest(UA_SecureChannel *channel, UA_Server *server, UA_UInt32 requestId
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS
     /* The publish request is not answered immediately */
-    if(requestTypeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY == UA_NS0ID_PUBLISHREQUEST) {
+    if(requestType == &UA_TYPES[UA_TYPES_PUBLISHREQUEST]) {
         Service_Publish(server, session, request, requestId);
         UA_deleteMembers(request, requestType);
         return;
@@ -447,18 +472,14 @@ processRequest(UA_SecureChannel *channel, UA_Server *server, UA_UInt32 requestId
 #endif
 
     /* Call the service */
-    UA_assert(service);
-    UA_assert(requestType);
-    UA_assert(responseType);
-    void *response = UA_alloca(responseType->memSize);
-    UA_init(response, responseType);
     service(server, session, request, response);
 
+ send_response:
     /* Send the response */
     init_response_header(request, response);
     retval = UA_SecureChannel_sendBinaryMessage(channel, requestId, response, responseType);
     if(retval != UA_STATUSCODE_GOOD)
-        sendError(channel, msg, oldpos, requestId, retval);
+        sendError(channel, msg, requestPos, &UA_TYPES[UA_TYPES_SERVICEFAULT], requestId, retval);
 
     /* Clean up */
     UA_deleteMembers(request, requestType);
@@ -470,28 +491,34 @@ static void
 processMSG(UA_Connection *connection, UA_Server *server, const UA_TcpMessageHeader *messageHeader,
            const UA_ByteString *msg, size_t *pos) {
     /* Decode the header */
-    UA_UInt32 secureChannelId = 0;
+    UA_UInt32 channelId = 0;
     UA_UInt32 tokenId = 0;
     UA_SequenceHeader sequenceHeader;
-    UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
+    UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &channelId);
     retval |= UA_UInt32_decodeBinary(msg, pos, &tokenId);
     retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader);
     if(retval != UA_STATUSCODE_GOOD)
         return;
 
-    /* Set the SecureChannel, channelid = 0 -> anonymous channel */
+    /* Get the SecureChannel */
     UA_SecureChannel *channel = connection->channel;
-    UA_SecureChannel anonymousChannel;
+    UA_SecureChannel anonymousChannel; /* use if no channel specified */
     if(!channel) {
         UA_SecureChannel_init(&anonymousChannel);
         anonymousChannel.connection = connection;
         channel = &anonymousChannel;
     }
-    if(secureChannelId != channel->securityToken.channelId) /* Not the channel we expected */
-        return;
+
+    /* Is the channel attached to connection? */
+    if(channelId != channel->securityToken.channelId) {
+        UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK,
+                    "Connection %i | Received MSG with the channel id not bound to the connection", connection->sockfd);
+        Service_CloseSecureChannel(server, channel);
+    }
+
+    /* Does the token match? */
     if(tokenId != channel->securityToken.tokenId) {
         if(tokenId != channel->nextSecurityToken.tokenId) {
-            /* close the securechannel but keep the connection open */
             UA_LOG_INFO_CHANNEL(server->config.logger, channel,
                                 "Request with a wrong security token. Closing the SecureChannel.");
             Service_CloseSecureChannel(server, channel);
@@ -505,13 +532,16 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_TcpMessageHead
     UA_ByteString request = processChunk(channel, server, messageHeader, sequenceHeader.requestId,
                                          msg, *pos, messageHeader->messageSize - 24, &deleteRequest);
     *pos += (messageHeader->messageSize - 24);
-    if(request.length == 0)
-        return;
+    if(request.length > 0) {
+        /* Process the request */
+        processRequest(channel, server, sequenceHeader.requestId, &request);
+        if(deleteRequest)
+            UA_ByteString_deleteMembers(&request);
+    }
 
-    /* Process the request */
-    processRequest(channel, server, sequenceHeader.requestId, &request);
-    if(deleteRequest)
-        UA_ByteString_deleteMembers(&request);
+    /* Clean up a possible anonymous channel */
+    if(channel == &anonymousChannel)
+        UA_SecureChannel_deleteMembersCleanup(channel);
 }
 
 /* CLO -> Close the secure channel */
@@ -553,14 +583,12 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
         /* Process the message */
         switch(tcpMessageHeader.messageTypeAndChunkType & 0x00ffffff) {
         case UA_MESSAGETYPE_HEL:
-            UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_NETWORK,
-                         "Connection %i | Process a HEL", connection->sockfd);
+            UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Process a HEL", connection->sockfd);
             processHEL(connection, msg, &pos);
             break;
 
         case UA_MESSAGETYPE_OPN:
-            UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_NETWORK,
-                         "Connection %i | Process a OPN", connection->sockfd);
+            UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Process a OPN", connection->sockfd);
             processOPN(connection, server, msg, &pos);
             break;
 
@@ -568,35 +596,29 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
 #ifndef UA_ENABLE_NONSTANDARD_STATELESS
             if(connection->state != UA_CONNECTION_ESTABLISHED) {
                 UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_NETWORK,
-                             "Connection %i | Received a MSG, but the connection is not established",
-                             connection->sockfd);
+                             "Connection %i | Received a MSG, but the connection is not established", connection->sockfd);
                 connection->close(connection);
                 return;
             }
 #endif
-            UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_NETWORK,
-                         "Connection %i | Process a MSG", connection->sockfd);
+            UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Process a MSG", connection->sockfd);
             processMSG(connection, server, &tcpMessageHeader, msg, &pos);
             break;
 
         case UA_MESSAGETYPE_CLO:
-            UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_NETWORK,
-                         "Connection %i | Process a CLO", connection->sockfd);
+            UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Process a CLO", connection->sockfd);
             processCLO(connection, server, msg, &pos);
-            connection->close(connection);
             return;
 
         default:
-            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK,
-                        "Connection %i | Unknown request type", connection->sockfd);
+            UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Unknown request type", connection->sockfd);
         }
 
         /* Loop to process the next message in the stream */
         if(pos != targetpos) {
-            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK,
-                        "Connection %i | Message was not entirely processed. "
-                        "Arrived at position %i, skip after the announced length to position %i",
-                        connection->sockfd, pos, targetpos);
+            UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Message was not entirely processed. "
+                         "Skip from position %i to position %i; message length is %i", connection->sockfd, pos, targetpos,
+                         msg->length);
             pos = targetpos;
         }
     } while(msg->length > pos);

+ 5 - 5
src/server/ua_server_internal.h

@@ -16,9 +16,9 @@
 /** Mapping of namespace-id and url to an external nodestore. For namespaces
     that have no mapping defined, the internal nodestore is used by default. */
 typedef struct UA_ExternalNamespace {
-	UA_UInt16 index;
-	UA_String url;
-	UA_ExternalNodeStore externalNodeStore;
+    UA_UInt16 index;
+    UA_String url;
+    UA_ExternalNodeStore externalNodeStore;
 } UA_ExternalNamespace;
 #endif
 
@@ -59,13 +59,13 @@ struct UA_Server {
     
 #ifdef UA_ENABLE_MULTITHREADING
     /* Dispatch queue head for the worker threads (the tail should not be in the same cache line) */
-	struct cds_wfcq_head dispatchQueue_head;
+    struct cds_wfcq_head dispatchQueue_head;
     UA_Worker *workers; /* there are nThread workers in a running server */
     struct cds_lfs_stack mainLoopJobs; /* Work that shall be executed only in the main loop and not
                                           by worker threads */
     struct DelayedJobs *delayedJobs;
     pthread_cond_t dispatchQueue_condition; /* so the workers don't spin if the queue is empty */
-	struct cds_wfcq_tail dispatchQueue_tail; /* Dispatch queue tail for the worker threads */
+    struct cds_wfcq_tail dispatchQueue_tail; /* Dispatch queue tail for the worker threads */
 #endif
 
     /* Config is the last element so that MSVC allows the usernamePasswordLogins

+ 3 - 3
src/server/ua_services.h

@@ -67,7 +67,7 @@ void Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel);
  * which is used to identify the Session in the audit logs and in the Server's
  * address space. The second is the authenticationToken which is used to
  * associate an incoming request with a Session. */
-void Service_CreateSession(UA_Server *server, UA_Session *session,
+void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
                            const UA_CreateSessionRequest *request,
                            UA_CreateSessionResponse *response);
 
@@ -76,8 +76,8 @@ void Service_CreateSession(UA_Server *server, UA_Session *session,
  * Session. This Service request shall be issued by the Client before it issues
  * any other Service request after CreateSession. Failure to do so shall cause
  * the Server to close the Session. */
-void Service_ActivateSession(UA_Server *server, UA_Session *session,
-                             const UA_ActivateSessionRequest *request,
+void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
+                             UA_Session *session, const UA_ActivateSessionRequest *request,
                              UA_ActivateSessionResponse *response);
 
 /* Used to terminate a Session. */

+ 26 - 36
src/server/ua_services_session.c

@@ -3,9 +3,8 @@
 #include "ua_session_manager.h"
 #include "ua_types_generated_encoding_binary.h"
 
-void Service_CreateSession(UA_Server *server, UA_Session *session, const UA_CreateSessionRequest *request,
-                           UA_CreateSessionResponse *response) {
-    UA_SecureChannel *channel = session->channel;
+void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
+                           const UA_CreateSessionRequest *request, UA_CreateSessionResponse *response) {
     if(channel->securityToken.channelId == 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID;
         return;
@@ -39,26 +38,15 @@ void Service_CreateSession(UA_Server *server, UA_Session *session, const UA_Crea
         UA_SessionManager_removeSession(&server->sessionManager, &newSession->authenticationToken);
          return;
     }
-    UA_LOG_DEBUG_SESSION(server->config.logger, newSession, "Session created");
+    UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Session %i created",
+                         newSession->sessionId.identifier.numeric);
 }
 
 void
-Service_ActivateSession(UA_Server *server, UA_Session *session, const UA_ActivateSessionRequest *request,
-                        UA_ActivateSessionResponse *response) {
-    UA_SecureChannel *channel = session->channel;
-    // make the channel know about the session
-    UA_Session *foundSession =
-        UA_SessionManager_getSession(&server->sessionManager, &request->requestHeader.authenticationToken);
-
-    if(!foundSession) {
-        response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
-        UA_LOG_INFO_CHANNEL(server->config.logger, channel, "ActivateSession: No "
-                            "session found for the authentication token");
-        return;
-    }
-
-    if(foundSession->validTill < UA_DateTime_now()) {
-        UA_LOG_INFO_SESSION(server->config.logger, foundSession, "ActivateSession: SecureChannel %i wants "
+Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, UA_Session *session,
+                        const UA_ActivateSessionRequest *request, UA_ActivateSessionResponse *response) {
+    if(session->validTill < UA_DateTime_now()) {
+        UA_LOG_INFO_SESSION(server->config.logger, session, "ActivateSession: SecureChannel %i wants "
                             "to activate, but the session has timed out", channel->securityToken.channelId);
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         return;
@@ -67,7 +55,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session, const UA_Activat
     if(request->userIdentityToken.encoding < UA_EXTENSIONOBJECT_DECODED ||
        (request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] &&
         request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN])) {
-        UA_LOG_INFO_SESSION(server->config.logger, foundSession, "ActivateSession: SecureChannel %i wants "
+        UA_LOG_INFO_SESSION(server->config.logger, session, "ActivateSession: SecureChannel %i wants "
                             "to activate, but the UserIdentify token is invalid",
                             channel->securityToken.channelId);
         response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
@@ -93,15 +81,17 @@ Service_ActivateSession(UA_Server *server, UA_Session *session, const UA_Activat
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
             return;
         }
-        if(foundSession->channel && foundSession->channel != channel) {
-            UA_LOG_INFO_SESSION(server->config.logger, foundSession,
+        if(session->channel && session->channel != channel) {
+            /* Close the old SecureChannel (this also detaches it) */
+            UA_LOG_INFO_SESSION(server->config.logger, session,
                                 "ActivateSession: Detach from old channel");
-            UA_SecureChannel_detachSession(foundSession->channel, foundSession);
+            UA_SecureChannelManager_close(&server->secureChannelManager,
+                                          session->channel->securityToken.channelId);
         }
-        UA_SecureChannel_attachSession(channel, foundSession);
-        foundSession->activated = true;
-        UA_Session_updateLifetime(foundSession);
-        UA_LOG_INFO_SESSION(server->config.logger, foundSession, "ActivateSession: Session activated");
+        UA_SecureChannel_attachSession(channel, session);
+        session->activated = true;
+        UA_Session_updateLifetime(session);
+        UA_LOG_INFO_SESSION(server->config.logger, session, "ActivateSession: Session activated");
         return;
     }
 
@@ -125,19 +115,19 @@ Service_ActivateSession(UA_Server *server, UA_Session *session, const UA_Activat
             if(!UA_String_equal(&token->userName, user) || !UA_String_equal(&token->password, pw))
                 continue;
             /* success - activate */
-            if(foundSession->channel && foundSession->channel != channel) {
-                UA_LOG_INFO_SESSION(server->config.logger, foundSession,
+            if(session->channel && session->channel != channel) {
+                UA_LOG_INFO_SESSION(server->config.logger, session,
                                     "ActivateSession: Detach from old channel");
-                UA_SecureChannel_detachSession(foundSession->channel, foundSession);
+                UA_SecureChannel_detachSession(session->channel, session);
             }
-            UA_SecureChannel_attachSession(channel, foundSession);
-            foundSession->activated = true;
-            UA_Session_updateLifetime(foundSession);
-            UA_LOG_INFO_SESSION(server->config.logger, foundSession, "ActivateSession: Session activated");
+            UA_SecureChannel_attachSession(channel, session);
+            session->activated = true;
+            UA_Session_updateLifetime(session);
+            UA_LOG_INFO_SESSION(server->config.logger, session, "ActivateSession: Session activated");
             return;
         }
         /* no match */
-        UA_LOG_INFO_SESSION(server->config.logger, foundSession,
+        UA_LOG_INFO_SESSION(server->config.logger, session,
                             "ActivateSession: Did not find matching username/password");
         response->responseHeader.serviceResult = UA_STATUSCODE_BADUSERACCESSDENIED;
         return;

+ 2 - 4
src/ua_securechannel.c

@@ -29,11 +29,9 @@ void UA_SecureChannel_deleteMembersCleanup(UA_SecureChannel *channel) {
     UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
     UA_ChannelSecurityToken_deleteMembers(&channel->nextSecurityToken);
     UA_Connection *c = channel->connection;
-    if(c) {
+    if(c)
         UA_Connection_detachSecureChannel(c);
-        if(c->close)
-            c->close(c);
-    }
+
     /* just remove the pointers and free the linked list (not the sessions) */
     struct SessionEntry *se, *temp;
     LIST_FOREACH_SAFE(se, &channel->sessions, pointers, temp) {