static UA_StatusCode argConformsToDefinition(UA_CallMethodRequest *rs, const UA_VariableNode *argDefinition) { if(argDefinition->value.variant.type != &UA_TYPES[UA_TYPES_ARGUMENT] && argDefinition->value.variant.type != &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) return UA_STATUSCODE_BADINTERNALERROR; if(rs->inputArgumentsSize < argDefinition->value.variant.arrayLength) return UA_STATUSCODE_BADARGUMENTSMISSING; if(rs->inputArgumentsSize > argDefinition->value.variant.arrayLength) return UA_STATUSCODE_BADINVALIDARGUMENT; const UA_ExtensionObject *thisArgDefExtObj; UA_Variant *var; UA_Argument arg; size_t decodingOffset = 0; UA_StatusCode retval = UA_STATUSCODE_GOOD; UA_NodeId ArgumentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ARGUMENT + UA_ENCODINGOFFSET_BINARY); for(int i = 0; i<rs->inputArgumentsSize; i++) { var = &rs->inputArguments[i]; if(argDefinition->value.variant.type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) { thisArgDefExtObj = &((const UA_ExtensionObject *) (argDefinition->value.variant.data))[i]; decodingOffset = 0; if(!UA_NodeId_equal(&ArgumentNodeId, &thisArgDefExtObj->typeId)) return UA_STATUSCODE_BADINTERNALERROR; UA_decodeBinary(&thisArgDefExtObj->body, &decodingOffset, &arg, &UA_TYPES[UA_TYPES_ARGUMENT]); } else if(argDefinition->value.variant.type == &UA_TYPES[UA_TYPES_ARGUMENT]) arg = ((UA_Argument *) argDefinition->value.variant.data)[i]; retval |= statisfySignature(var, arg); } return retval; }
END_TEST START_TEST(decodeComplexTypeFromRandomBufferShallSurvive) { // given UA_ByteString msg1; UA_Int32 retval = UA_STATUSCODE_GOOD; UA_Int32 buflen = 256; retval = UA_ByteString_allocBuffer(&msg1, buflen); // fixed size #ifdef _WIN32 srand(42); #else srandom(42); #endif // when for(int n = 0;n < RANDOM_TESTS;n++) { for(UA_Int32 i = 0;i < buflen;i++) { #ifdef _WIN32 UA_UInt32 rnd; rnd = rand(); msg1.data[i] = rnd; #else msg1.data[i] = (UA_Byte)random(); // when #endif } size_t pos = 0; void *obj1 = UA_new(&UA_TYPES[_i]); retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i], 0, NULL); UA_delete(obj1, &UA_TYPES[_i]); } // finally UA_ByteString_deleteMembers(&msg1); }
END_TEST START_TEST(encodeShallYieldDecode) { /* floating point types may change the representaton due to several possible NaN values. */ if(_i != UA_TYPES_FLOAT || _i != UA_TYPES_DOUBLE || _i != UA_TYPES_CREATESESSIONREQUEST || _i != UA_TYPES_CREATESESSIONRESPONSE || _i != UA_TYPES_VARIABLEATTRIBUTES || _i != UA_TYPES_READREQUEST || _i != UA_TYPES_MONITORINGPARAMETERS || _i != UA_TYPES_MONITOREDITEMCREATERESULT || _i != UA_TYPES_CREATESUBSCRIPTIONREQUEST || _i != UA_TYPES_CREATESUBSCRIPTIONRESPONSE) return; // given UA_ByteString msg1, msg2; void *obj1 = UA_new(&UA_TYPES[_i]); UA_StatusCode retval = UA_ByteString_allocBuffer(&msg1, 65000); // fixed buf size ck_assert_int_eq(retval, UA_STATUSCODE_GOOD); UA_Byte *pos = msg1.data; const UA_Byte *end = &msg1.data[msg1.length]; retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &pos, &end, NULL, NULL); if(retval != UA_STATUSCODE_GOOD) { UA_delete(obj1, &UA_TYPES[_i]); UA_ByteString_deleteMembers(&msg1); return; } // when void *obj2 = UA_new(&UA_TYPES[_i]); size_t offset = 0; retval = UA_decodeBinary(&msg1, &offset, obj2, &UA_TYPES[_i], 0, NULL); ck_assert_msg(retval == UA_STATUSCODE_GOOD, "could not decode idx=%d,nodeid=%i", _i, UA_TYPES[_i].typeId.identifier.numeric); ck_assert(!memcmp(obj1, obj2, UA_TYPES[_i].memSize)); // bit identical decoding retval = UA_ByteString_allocBuffer(&msg2, 65000); ck_assert_int_eq(retval, UA_STATUSCODE_GOOD); pos = msg2.data; end = &msg2.data[msg2.length]; retval = UA_encodeBinary(obj2, &UA_TYPES[_i], &pos, &end, NULL, NULL); ck_assert_int_eq(retval, UA_STATUSCODE_GOOD); // then msg1.length = offset; msg2.length = offset; ck_assert_msg(UA_ByteString_equal(&msg1, &msg2) == true, "messages differ idx=%d,nodeid=%i", _i, UA_TYPES[_i].typeId.identifier.numeric); // finally UA_delete(obj1, &UA_TYPES[_i]); UA_delete(obj2, &UA_TYPES[_i]); UA_ByteString_deleteMembers(&msg1); UA_ByteString_deleteMembers(&msg2); }
END_TEST #define RANDOM_TESTS 1000 START_TEST(decodeScalarBasicTypeFromRandomBufferShallSucceed) { // given void *obj1 = NULL; UA_ByteString msg1; UA_Int32 retval = UA_STATUSCODE_GOOD; UA_Int32 buflen = 256; retval = UA_ByteString_allocBuffer(&msg1, buflen); // fixed size #ifdef _WIN32 srand(42); #else srandom(42); #endif for(int n = 0;n < RANDOM_TESTS;n++) { for(UA_Int32 i = 0;i < buflen;i++) { #ifdef _WIN32 UA_UInt32 rnd; rnd = rand(); msg1.data[i] = rnd; #else msg1.data[i] = (UA_Byte)random(); // when #endif } size_t pos = 0; obj1 = UA_new(&UA_TYPES[_i]); retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i], 0, NULL); //then ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Decoding %d from random buffer", UA_TYPES[_i].typeId.identifier.numeric); // finally UA_delete(obj1, &UA_TYPES[_i]); } UA_ByteString_deleteMembers(&msg1); }
END_TEST START_TEST(decodeShallFailWithTruncatedBufferButSurvive) { //Skip test for void* if (_i == UA_TYPES_DISCOVERYCONFIGURATION || _i == UA_TYPES_FILTEROPERAND || _i == UA_TYPES_MONITORINGFILTER || _i == UA_TYPES_UNION || _i == UA_TYPES_HISTORYREADDETAILS || _i == UA_TYPES_NOTIFICATIONDATA || _i == UA_TYPES_MONITORINGFILTERRESULT) return; // given UA_ByteString msg1; void *obj1 = UA_new(&UA_TYPES[_i]); UA_StatusCode retval = UA_ByteString_allocBuffer(&msg1, 65000); // fixed buf size UA_Byte *pos = msg1.data; const UA_Byte *end = &msg1.data[msg1.length]; retval |= UA_encodeBinary(obj1, &UA_TYPES[_i], &pos, &end, NULL, NULL); UA_delete(obj1, &UA_TYPES[_i]); if(retval != UA_STATUSCODE_GOOD) { UA_ByteString_deleteMembers(&msg1); return; // e.g. variants cannot be encoded after an init without failing (no datatype set) } size_t half = (uintptr_t)(pos - msg1.data) / 2; msg1.length = half; // when void *obj2 = UA_new(&UA_TYPES[_i]); size_t offset = 0; retval = UA_decodeBinary(&msg1, &offset, obj2, &UA_TYPES[_i], 0, NULL); ck_assert_int_ne(retval, UA_STATUSCODE_GOOD); UA_delete(obj2, &UA_TYPES[_i]); UA_ByteString_deleteMembers(&msg1); }
int main(int argc, char** argv) { signal(SIGINT, stopHandler); /* catches ctrl-c */ UA_ServerConfig config = UA_ServerConfig_standard; UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, logger); config.logger = Logger_Stdout; config.networkLayers = &nl; config.networkLayersSize = 1; UA_Server *server = UA_Server_new(config); /* add a variable node to the address space */ UA_VariableAttributes attr; UA_VariableAttributes_init(&attr); UA_Int32 myInteger = 42; UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]); attr.description = UA_LOCALIZEDTEXT("en_US","the answer"); attr.displayName = UA_LOCALIZEDTEXT("en_US","the answer"); UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer"); UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId, myIntegerName, UA_NODEID_NULL, attr, NULL, NULL); UA_ReadRequest request; UA_ReadRequest_init(&request); UA_ReadValueId rvi; rvi.nodeId = myIntegerNodeId; rvi.attributeId = UA_ATTRIBUTEID_VALUE; rvi.indexRange = UA_STRING_NULL; rvi.dataEncoding = UA_QUALIFIEDNAME(0, "DefaultBinary"); request.timestampsToReturn = UA_TIMESTAMPSTORETURN_NEITHER; request.nodesToReadSize = 1; request.nodesToRead = &rvi; UA_StatusCode retval = UA_STATUSCODE_GOOD; UA_ByteString request_msg; retval |= UA_ByteString_allocBuffer(&request_msg, 1000); UA_ByteString response_msg; retval |= UA_ByteString_allocBuffer(&response_msg, 1000); size_t offset = 0; retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_READREQUEST], &request_msg, &offset); clock_t begin, end; begin = clock(); UA_ReadRequest rq; UA_ReadResponse rr; for(int i = 0; i < 900000; i++) { offset = 0; retval |= UA_decodeBinary(&request_msg, &offset, &rq, &UA_TYPES[UA_TYPES_READREQUEST]); UA_ReadResponse_init(&rr); Service_Read(server, &adminSession, &rq, &rr); offset = 0; retval |= UA_encodeBinary(&rr, &UA_TYPES[UA_TYPES_READRESPONSE], &response_msg, &offset); UA_ReadRequest_deleteMembers(&rq); UA_ReadResponse_deleteMembers(&rr); } end = clock(); double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; printf("duration was %f s\n", time_spent); printf("retval is %i\n", retval); UA_ByteString_deleteMembers(&request_msg); UA_ByteString_deleteMembers(&response_msg); retval |= UA_Server_run(server, &running); UA_Server_delete(server); nl.deleteMembers(&nl); return (int)retval; }
void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *requestType, void *response, const UA_DataType *responseType) { /* Requests always begin witih a RequestHeader, therefore we can cast. */ UA_RequestHeader *request = (void*)(uintptr_t)r; UA_StatusCode retval = UA_STATUSCODE_GOOD; UA_init(response, responseType); UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response; /* make sure we have a valid session */ retval = UA_Client_manuallyRenewSecureChannel(client); if(retval != UA_STATUSCODE_GOOD) { respHeader->serviceResult = retval; client->state = UA_CLIENTSTATE_ERRORED; return; } /* handling request parameters */ UA_NodeId_copy(&client->authenticationToken, &request->authenticationToken); request->timestamp = UA_DateTime_now(); request->requestHandle = ++client->requestHandle; /* Send the request */ UA_UInt32 requestId = ++client->requestId; UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT, "Sending a request of type %i", requestType->typeId.identifier.numeric); retval = UA_SecureChannel_sendBinaryMessage(&client->channel, requestId, request, requestType); if(retval) { if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE; else respHeader->serviceResult = retval; client->state = UA_CLIENTSTATE_ERRORED; return; } /* Retrieve the response */ // Todo: push this into the generic securechannel implementation for client and server UA_ByteString reply; UA_ByteString_init(&reply); do { retval = client->connection.recv(&client->connection, &reply, client->config.timeout); if(retval != UA_STATUSCODE_GOOD) { respHeader->serviceResult = retval; client->state = UA_CLIENTSTATE_ERRORED; return; } } while(!reply.data); size_t offset = 0; UA_SecureConversationMessageHeader msgHeader; retval |= UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &msgHeader); UA_SymmetricAlgorithmSecurityHeader symHeader; retval |= UA_SymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &symHeader); UA_SequenceHeader seqHeader; retval |= UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader); UA_NodeId responseId; retval |= UA_NodeId_decodeBinary(&reply, &offset, &responseId); UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric + UA_ENCODINGOFFSET_BINARY); 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) { if(responseId.identifier.numeric != UA_NS0ID_SERVICEFAULT + UA_ENCODINGOFFSET_BINARY) { UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "Reply answers the wrong request. Expected ns=%i,i=%i. But retrieved ns=%i,i=%i", expectedNodeId.namespaceIndex, expectedNodeId.identifier.numeric, responseId.namespaceIndex, responseId.identifier.numeric); respHeader->serviceResult = UA_STATUSCODE_BADINTERNALERROR; } else retval = UA_decodeBinary(&reply, &offset, respHeader, &UA_TYPES[UA_TYPES_SERVICEFAULT]); goto finish; } retval = UA_decodeBinary(&reply, &offset, response, responseType); if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) retval = UA_STATUSCODE_BADRESPONSETOOLARGE; finish: UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader); 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; respHeader->serviceResult = retval; } UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT, "Received a response of type %i", responseId.identifier.numeric); }
static void processMSG(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId, const UA_ByteString *msg) { /* At 0, the nodeid starts... */ size_t ppos = 0; size_t *offset = &ppos; /* Decode the nodeid */ UA_NodeId requestTypeId; UA_StatusCode retval = UA_NodeId_decodeBinary(msg, offset, &requestTypeId); if(retval != UA_STATUSCODE_GOOD) return; if(requestTypeId.identifierType != UA_NODEIDTYPE_NUMERIC) UA_NodeId_deleteMembers(&requestTypeId); /* leads to badserviceunsupported */ /* Store the start-position of the request */ size_t requestPos = *offset; /* Get the service pointers */ UA_Service service = NULL; const UA_DataType *requestType = NULL; const UA_DataType *responseType = NULL; UA_Boolean sessionRequired = true; getServicePointers(requestTypeId.identifier.numeric, &requestType, &responseType, &service, &sessionRequired); if(!requestType) { 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 %i", requestTypeId.identifier.numeric); } sendError(channel, msg, requestPos, &UA_TYPES[UA_TYPES_SERVICEFAULT], requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED); return; } UA_assert(responseType); #ifdef UA_ENABLE_NONSTANDARD_STATELESS /* Stateless extension: Sessions are optional */ sessionRequired = false; #endif /* Decode the request */ void *request = UA_alloca(requestType->memSize); UA_RequestHeader *requestHeader = (UA_RequestHeader*)request; retval = UA_decodeBinary(msg, offset, request, requestType); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Could not decode the request"); sendError(channel, msg, requestPos, responseType, requestId, retval); return; } /* Prepare the respone */ void *response = UA_alloca(responseType->memSize); UA_init(response, responseType); UA_Session *session = NULL; /* must be initialized before goto send_response */ /* CreateSession doesn't need a session */ if(requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]) { Service_CreateSession(server, channel, request, response); goto send_response; } /* Find the matching session */ session = UA_SecureChannel_getSession(channel, &requestHeader->authenticationToken); if(!session) session = UA_SessionManager_getSession(&server->sessionManager, &requestHeader->authenticationToken); if(requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST]) { if(!session) { UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Trying to activate a session that is " \ "not known in the server"); sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSESSIONIDINVALID); UA_deleteMembers(request, requestType); return; } Service_ActivateSession(server, channel, session, request, response); goto send_response; } /* Set an anonymous, inactive session for services that need no session */ UA_Session anonymousSession; if(!session) { if(sessionRequired) { UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Service request %i without a valid session", requestType->binaryEncodingId); sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSESSIONIDINVALID); UA_deleteMembers(request, requestType); return; } UA_Session_init(&anonymousSession); anonymousSession.sessionId = UA_NODEID_GUID(0, UA_GUID_NULL); anonymousSession.channel = channel; session = &anonymousSession; } /* Trying to use a non-activated session? */ if(sessionRequired && !session->activated) { UA_LOG_INFO_SESSION(server->config.logger, session, "Calling service %i on a non-activated session", requestType->binaryEncodingId); sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED); UA_SessionManager_removeSession(&server->sessionManager, &session->authenticationToken); UA_deleteMembers(request, requestType); return; } /* The session is bound to another channel */ if(session->channel != channel) { UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Client tries to use an obsolete securechannel"); sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSECURECHANNELIDINVALID); UA_deleteMembers(request, requestType); return; } /* Update the session lifetime */ UA_Session_updateLifetime(session); #ifdef UA_ENABLE_SUBSCRIPTIONS /* The publish request is not answered immediately */ if(requestType == &UA_TYPES[UA_TYPES_PUBLISHREQUEST]) { Service_Publish(server, session, request, requestId); UA_deleteMembers(request, requestType); return; } #endif /* Call the service */ UA_assert(service); /* For all services besides publish, the service pointer is non-NULL*/ service(server, session, request, response); send_response: /* Send the response */ ((UA_ResponseHeader*)response)->requestHandle = requestHeader->requestHandle; ((UA_ResponseHeader*)response)->timestamp = UA_DateTime_now(); retval = UA_SecureChannel_sendBinaryMessage(channel, requestId, response, responseType); if(retval != UA_STATUSCODE_GOOD) UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Could not send the message over " "the SecureChannel with error code 0x%08x", retval); /* Clean up */ UA_deleteMembers(request, requestType); UA_deleteMembers(response, responseType); }
static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) { /* If we cannot decode these, don't respond */ UA_UInt32 secureChannelId = 0; UA_UInt32 tokenId = 0; UA_SequenceHeader sequenceHeader; UA_NodeId requestTypeId; UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId); retval |= UA_UInt32_decodeBinary(msg, pos, &tokenId); retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader); retval = UA_NodeId_decodeBinary(msg, pos, &requestTypeId); if(retval != UA_STATUSCODE_GOOD) return; UA_SecureChannel *channel = connection->channel; UA_SecureChannel anonymousChannel; if(!channel) { UA_SecureChannel_init(&anonymousChannel); anonymousChannel.connection = connection; channel = &anonymousChannel; } /* Test if the secure channel is ok */ if(secureChannelId != channel->securityToken.channelId) return; if(tokenId != channel->securityToken.tokenId) { if(tokenId != channel->nextSecurityToken.tokenId) { /* close the securechannel but keep the connection open */ UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SECURECHANNEL, "Request with a wrong security token. Closing the SecureChannel %i.", channel->securityToken.channelId); Service_CloseSecureChannel(server, channel->securityToken.channelId); return; } UA_SecureChannel_revolveTokens(channel); } /* 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, sequenceHeader.requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED); return; } /* 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); if(!service) { /* The service is not supported */ if(requestTypeId.identifier.numeric==787) UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client requested a subscription that are not supported, " "the message will be skipped"); else UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Unknown request: NodeId(ns=%d, i=%d)", requestTypeId.namespaceIndex, requestTypeId.identifier.numeric); sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED); return; } /* Most services can only be called with a valid securechannel */ #ifndef EXTENSION_STATELESS if(channel == &anonymousChannel && requestType->typeIndex > UA_TYPES_OPENSECURECHANNELREQUEST) { sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSECURECHANNELIDINVALID); return; } #endif /* Decode the request */ void *request = UA_alloca(requestType->memSize); size_t oldpos = *pos; retval = UA_decodeBinary(msg, pos, request, requestType); if(retval != UA_STATUSCODE_GOOD) { sendError(channel, msg, oldpos, sequenceHeader.requestId, retval); return; } /* Find the matching session */ UA_Session *session = UA_SecureChannel_getSession(channel, &((UA_RequestHeader*)request)->authenticationToken); UA_Session anonymousSession; if(!session) { UA_Session_init(&anonymousSession); anonymousSession.channel = channel; anonymousSession.activated = UA_TRUE; session = &anonymousSession; } /* Test if the session is valid */ if(!session->activated && requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST) { UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service with a non-activated session"); sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED); return; } #ifndef EXTENSION_STATELESS if(session == &anonymousSession && requestType->typeIndex > UA_TYPES_ACTIVATESESSIONREQUEST) { UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service without a session"); sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONIDINVALID); return; } #endif /* Call the service */ UA_Session_updateLifetime(session); void *response = UA_alloca(responseType->memSize); UA_init(response, responseType); init_response_header(request, response); service(server, session, request, response); /* Send the response */ retval = UA_SecureChannel_sendBinaryMessage(channel, sequenceHeader.requestId, response, responseType); if(retval != UA_STATUSCODE_GOOD) { /* e.g. UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED */ sendError(channel, msg, oldpos, sequenceHeader.requestId, retval); } /* Clean up */ UA_deleteMembers(request, requestType); UA_deleteMembers(response, responseType); return; }