/* Takes the raw message from the network layer */ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *message) { UA_SecureChannel *channel = connection->channel; if(channel) { /* Assemble chunks in the securechannel and process complete messages */ UA_StatusCode retval = UA_SecureChannel_processChunks(channel, message, (UA_ProcessMessageCallback*)UA_Server_processSecureChannelMessage, server); if(retval != UA_STATUSCODE_GOOD) UA_LOG_TRACE_CHANNEL(server->config.logger, channel, "Procesing chunkgs resulted in error code 0x%08x", retval); } else { /* Process messages without a channel and no chunking */ size_t offset = 0; UA_TcpMessageHeader tcpMessageHeader; UA_StatusCode retval = UA_TcpMessageHeader_decodeBinary(message, &offset, &tcpMessageHeader); if(retval != UA_STATUSCODE_GOOD) { connection->close(connection); return; } /* Dispatch according to the message type */ switch(tcpMessageHeader.messageTypeAndChunkType & 0x00ffffff) { case UA_MESSAGETYPE_HEL: UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Process HEL message", connection->sockfd); processHEL(connection, message, &offset); break; case UA_MESSAGETYPE_OPN: { UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Process OPN message", connection->sockfd); UA_UInt32 channelId = 0; retval = UA_UInt32_decodeBinary(message, &offset, &channelId); if(retval != UA_STATUSCODE_GOOD) connection->close(connection); UA_ByteString offsetMessage = (UA_ByteString){ .data = message->data + 12, .length = message->length - 12}; processOPN(server, connection, channelId, &offsetMessage); break; } case UA_MESSAGETYPE_MSG: UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Processing a MSG message not possible " "without a SecureChannel", connection->sockfd); connection->close(connection); break; case UA_MESSAGETYPE_CLO: UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Processing a CLO message not possible " "without a SecureChannel", connection->sockfd); connection->close(connection); break; default: UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Unknown message type", connection->sockfd); connection->close(connection); } } }
UA_StatusCode UA_Client_connect_iterate(UA_Client *client) { UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Client connect iterate"); if (client->connection.state == UA_CONNECTION_ESTABLISHED){ if(client->state < UA_CLIENTSTATE_WAITING_FOR_ACK) { client->connectStatus = sendHELMessage(client); if(client->connectStatus == UA_STATUSCODE_GOOD) { setClientState(client, UA_CLIENTSTATE_WAITING_FOR_ACK); } else { client->connection.close(&client->connection); client->connection.free(&client->connection); } return client->connectStatus; } } /* If server is not connected */ if(client->connection.state == UA_CONNECTION_CLOSED) { client->connectStatus = UA_STATUSCODE_BADCONNECTIONCLOSED; UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_NETWORK, "No connection to server."); } if(client->connectStatus != UA_STATUSCODE_GOOD) { client->connection.close(&client->connection); client->connection.free(&client->connection); } return client->connectStatus; }
UA_StatusCode UA_Client_connect_async(UA_Client *client, const char *endpointUrl, UA_ClientAsyncServiceCallback callback, void *userdata) { UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Client internal async"); if(client->state >= UA_CLIENTSTATE_WAITING_FOR_ACK) return UA_STATUSCODE_GOOD; UA_ChannelSecurityToken_init(&client->channel.securityToken); client->channel.state = UA_SECURECHANNELSTATE_FRESH; client->endpointsHandshake = true; client->channel.sendSequenceNumber = 0; client->requestId = 0; UA_String_deleteMembers(&client->endpointUrl); client->endpointUrl = UA_STRING_ALLOC(endpointUrl); UA_StatusCode retval = UA_STATUSCODE_GOOD; client->connection = client->config.initConnectionFunc(client->config.localConnectionConfig, client->endpointUrl, client->config.timeout, &client->config.logger); if(client->connection.state != UA_CONNECTION_OPENING) { UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Could not init async connection"); retval = UA_STATUSCODE_BADCONNECTIONCLOSED; goto cleanup; } /* Set the channel SecurityMode if not done so far */ if(client->channel.securityMode == UA_MESSAGESECURITYMODE_INVALID) client->channel.securityMode = UA_MESSAGESECURITYMODE_NONE; /* Set the channel SecurityPolicy if not done so far */ if(!client->channel.securityPolicy) { UA_SecurityPolicy *sp = getSecurityPolicy(client, UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None")); if(!sp) { retval = UA_STATUSCODE_BADINTERNALERROR; goto cleanup; } UA_ByteString remoteCertificate = UA_BYTESTRING_NULL; retval = UA_SecureChannel_setSecurityPolicy(&client->channel, sp, &remoteCertificate); if(retval != UA_STATUSCODE_GOOD) goto cleanup; } client->asyncConnectCall.callback = callback; client->asyncConnectCall.userdata = userdata; if(!client->connection.connectCallbackID) { UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Adding async connection callback"); retval = UA_Client_addRepeatedCallback( client, client->config.pollConnectionFunc, &client->connection, 100.0, &client->connection.connectCallbackID); if(retval != UA_STATUSCODE_GOOD) goto cleanup; } retval = UA_SecureChannel_generateLocalNonce(&client->channel); if(retval != UA_STATUSCODE_GOOD) goto cleanup; /* Delete async service. TODO: Move this from connect to the disconnect/cleanup phase */ UA_Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSHUTDOWN); #ifdef UA_ENABLE_SUBSCRIPTIONS client->currentlyOutStandingPublishRequests = 0; #endif UA_NodeId_deleteMembers(&client->authenticationToken); /* Generate new local and remote key */ retval = UA_SecureChannel_generateNewKeys(&client->channel); if(retval != UA_STATUSCODE_GOOD) goto cleanup; return retval; cleanup: UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Failure during async connect"); UA_Client_disconnect(client); return retval; }