/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2017 (c) Stefan Profanter, fortiss GmbH */ #ifndef UA_PLUGIN_NETWORK_H_ #define UA_PLUGIN_NETWORK_H_ #ifdef __cplusplus extern "C" { #endif #include "ua_server.h" #include "ua_plugin_log.h" /* Forward declarations */ struct UA_Connection; typedef struct UA_Connection UA_Connection; struct UA_SecureChannel; typedef struct UA_SecureChannel UA_SecureChannel; struct UA_ServerNetworkLayer; typedef struct UA_ServerNetworkLayer UA_ServerNetworkLayer; /** * .. _networking: * * Networking Plugin API * ===================== * * Connection * ---------- * Client-server connections are represented by a `UA_Connection`. The * connection is stateful and stores partially received messages, and so on. In * addition, the connection contains function pointers to the underlying * networking implementation. An example for this is the `send` function. So the * connection encapsulates all the required networking functionality. This lets * users on embedded (or otherwise exotic) systems implement their own * networking plugins with a clear interface to the main open62541 library. */ typedef struct { UA_UInt32 protocolVersion; UA_UInt32 sendBufferSize; UA_UInt32 recvBufferSize; UA_UInt32 maxMessageSize; UA_UInt32 maxChunkCount; } UA_ConnectionConfig; typedef enum { UA_CONNECTION_CLOSED, /* The socket has been closed and the connection * will be deleted */ UA_CONNECTION_OPENING, /* The socket is open, but the HEL/ACK handshake * is not done */ UA_CONNECTION_ESTABLISHED /* The socket is open and the connection * configured */ } UA_ConnectionState; struct UA_Connection { UA_ConnectionState state; UA_ConnectionConfig localConf; UA_ConnectionConfig remoteConf; UA_SecureChannel *channel; /* The securechannel that is attached to * this connection */ UA_Int32 sockfd; /* Most connectivity solutions run on * sockets. Having the socket id here * simplifies the design. */ UA_DateTime openingDate; /* The date the connection was created */ void *handle; /* A pointer to internal data */ UA_ByteString incompleteMessage; /* A half-received message (TCP is a * streaming protocol) is stored here */ /* Get a buffer for sending */ UA_StatusCode (*getSendBuffer)(UA_Connection *connection, size_t length, UA_ByteString *buf); /* Release the send buffer manually */ void (*releaseSendBuffer)(UA_Connection *connection, UA_ByteString *buf); /* Sends a message over the connection. The message buffer is always freed, * even if sending fails. * * @param connection The connection * @param buf The message buffer * @return Returns an error code or UA_STATUSCODE_GOOD. */ UA_StatusCode (*send)(UA_Connection *connection, UA_ByteString *buf); /* Receive a message from the remote connection * * @param connection The connection * @param response The response string. It is allocated by the connection * and needs to be freed with connection->releaseBuffer * @param timeout Timeout of the recv operation in milliseconds * @return Returns UA_STATUSCODE_BADCOMMUNICATIONERROR if the recv operation * can be repeated, UA_STATUSCODE_GOOD if it succeeded and * UA_STATUSCODE_BADCONNECTIONCLOSED if the connection was * closed. */ UA_StatusCode (*recv)(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout); /* Release the buffer of a received message */ void (*releaseRecvBuffer)(UA_Connection *connection, UA_ByteString *buf); /* Close the connection. The network layer closes the socket. This is picked * up during the next 'listen' and the connection is freed in the network * layer. */ void (*close)(UA_Connection *connection); /* To be called only from within the server (and not the network layer). * Frees up the connection's memory. */ void (*free)(UA_Connection *connection); }; /* Cleans up half-received messages, and so on. Called from connection->free. */ void UA_EXPORT UA_Connection_deleteMembers(UA_Connection *connection); /** * Server Network Layer * -------------------- * The server exposes two functions to interact with remote clients: * `processBinaryMessage` and `removeConnection`. These functions are called by * the server network layer. * * It is the job of the server network layer to listen on a TCP socket, to * accept new connections, to call the server with received messages and to * signal closed connections to the server. * * The network layer is part of the server config. So users can provide a custom * implementation if the provided example does not fit their architecture. The * network layer is invoked only from the server's main loop. So the network * layer does not need to be thread-safe. If the networklayer receives a * positive duration for blocking listening, the server's main loop will block * until a message is received or the duration times out. */ /* Process a binary message (TCP packet). The message can contain partial * chunks. (TCP is a streaming protocol and packets may be split/merge during * transport.) After processing, the message is freed with * connection->releaseRecvBuffer. */ void UA_EXPORT UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *message); /* The server internally cleans up the connection and then calls * connection->free. */ void UA_EXPORT UA_Server_removeConnection(UA_Server *server, UA_Connection *connection); struct UA_ServerNetworkLayer { void *handle; /* Internal data */ UA_String discoveryUrl; /* Start listening on the networklayer. * * @param nl The network layer * @return Returns UA_STATUSCODE_GOOD or an error code. */ UA_StatusCode (*start)(UA_ServerNetworkLayer *nl, const UA_String *customHostname); /* Listen for new and closed connections and arriving packets. Calls * UA_Server_processBinaryMessage for the arriving packets. Closed * connections are picked up here and forwarded to * UA_Server_removeConnection where they are cleaned up and freed. * * @param nl The network layer * @param server The server for processing the incoming packets and for * closing connections. * @param timeout The timeout during which an event must arrive in * milliseconds * @return A statuscode for the status of the network layer. */ UA_StatusCode (*listen)(UA_ServerNetworkLayer *nl, UA_Server *server, UA_UInt16 timeout); /* Close the network socket and all open connections. Afterwards, the * network layer can be safely deleted. * * @param nl The network layer * @param server The server that processes the incoming packets and for * closing connections before deleting them. * @return A statuscode for the status of the closing operation. */ void (*stop)(UA_ServerNetworkLayer *nl, UA_Server *server); /* Deletes the network layer context. Call only after stopping. */ void (*deleteMembers)(UA_ServerNetworkLayer *nl); }; /** * Client Network Layer * -------------------- * The client has only a single connection used for sending and receiving binary * messages. */ /* @param localConf the connection config for this client * @param endpointUrl to where to connect * @param timeout in ms until the connection try times out if remote not reachable * @param logger the logger to use */ typedef UA_Connection (*UA_ConnectClientConnection)(UA_ConnectionConfig localConf, const char *endpointUrl, const UA_UInt32 timeout, UA_Logger logger); /** * Endpoint URL Parser * ------------------- * The endpoint URL parser is generally useful for the implementation of network * layer plugins. */ /* Split the given endpoint url into hostname, port and path. All arguments must * be non-NULL. EndpointUrls have the form "opc.tcp://hostname:port/path", port * and path may be omitted (together with the prefix colon and slash). * * @param endpointUrl The endpoint URL. * @param outHostname Set to the parsed hostname. The string points into the * original endpointUrl, so no memory is allocated. If an IPv6 address is * given, hostname contains e.g. '[2001:0db8:85a3::8a2e:0370:7334]' * @param outPort Set to the port of the url or left unchanged. * @param outPath Set to the path if one is present in the endpointUrl. * Starting or trailing '/' are NOT included in the path. The string * points into the original endpointUrl, so no memory is allocated. * @return Returns UA_STATUSCODE_BADTCPENDPOINTURLINVALID if parsing failed. */ UA_StatusCode UA_EXPORT UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, UA_UInt16 *outPort, UA_String *outPath); #ifdef __cplusplus } // extern "C" #endif #endif /* UA_PLUGIN_NETWORK_H_ */