|
@@ -19,10 +19,12 @@
|
|
|
#include <errno.h>
|
|
|
#ifdef _WIN32
|
|
|
# include <malloc.h>
|
|
|
+/* Fix redefinition of SLIST_ENTRY on mingw winnt.h */
|
|
|
# ifdef SLIST_ENTRY
|
|
|
-# undef SLIST_ENTRY /* Fix redefinition of SLIST_ENTRY on mingw winnt.h */
|
|
|
+# undef SLIST_ENTRY
|
|
|
# endif
|
|
|
-# define _WINSOCK_DEPRECATED_NO_WARNINGS /* inet_ntoa is deprecated on MSVC but used for compatibility */
|
|
|
+/* inet_ntoa is deprecated on MSVC but used for compatibility */
|
|
|
+# define _WINSOCK_DEPRECATED_NO_WARNINGS
|
|
|
# include <winsock2.h>
|
|
|
# include <ws2tcpip.h>
|
|
|
# define CLOSESOCKET(S) closesocket((SOCKET)S)
|
|
@@ -54,7 +56,9 @@
|
|
|
#endif
|
|
|
|
|
|
/* unsigned int for windows and workaround to a glibc bug */
|
|
|
-#if defined(_WIN32) || defined(__OpenBSD__) || (defined(__GNU_LIBRARY__) && (__GNU_LIBRARY__ <= 6) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 16))
|
|
|
+#if defined(_WIN32) || defined(__OpenBSD__) || \
|
|
|
+ (defined(__GNU_LIBRARY__) && (__GNU_LIBRARY__ <= 6) && \
|
|
|
+ (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 16))
|
|
|
# define UA_fd_set(fd, fds) FD_SET((unsigned int)fd, fds)
|
|
|
# define UA_fd_isset(fd, fds) FD_ISSET((unsigned int)fd, fds)
|
|
|
#else
|
|
@@ -86,7 +90,8 @@ socket_write(UA_Connection *connection, UA_ByteString *buf) {
|
|
|
/* If the OS throws EMSGSIZE, force a smaller packet size:
|
|
|
* size_t bytes_to_send = buf->length - nWritten > 1024 ? 1024 : buf->length - nWritten; */
|
|
|
size_t bytes_to_send = buf->length - nWritten;
|
|
|
- n = send((SOCKET)connection->sockfd, (const char*)buf->data + nWritten, WIN32_INT bytes_to_send, 0);
|
|
|
+ n = send((SOCKET)connection->sockfd, (const char*)buf->data + nWritten,
|
|
|
+ WIN32_INT bytes_to_send, 0);
|
|
|
#ifdef _WIN32
|
|
|
if(n < 0 && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
|
|
|
#else
|
|
@@ -120,12 +125,15 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
|
|
|
# ifdef __APPLE__
|
|
|
struct timeval tmptv = {(long int)(timeout_usec / 1000000), timeout_usec % 1000000};
|
|
|
# else
|
|
|
- struct timeval tmptv = {(long int)(timeout_usec / 1000000), (long int)(timeout_usec % 1000000)};
|
|
|
+ struct timeval tmptv = {(long int)(timeout_usec / 1000000),
|
|
|
+ (long int)(timeout_usec % 1000000)};
|
|
|
# endif
|
|
|
- int ret = setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tmptv, sizeof(struct timeval));
|
|
|
+ int ret = setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO,
|
|
|
+ (const char *)&tmptv, sizeof(struct timeval));
|
|
|
#else
|
|
|
DWORD timeout_dw = timeout;
|
|
|
- int ret = setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_dw, sizeof(DWORD));
|
|
|
+ int ret = setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO,
|
|
|
+ (const char*)&timeout_dw, sizeof(DWORD));
|
|
|
#endif
|
|
|
if(0 != ret) {
|
|
|
UA_ByteString_deleteMembers(response);
|
|
@@ -144,7 +152,8 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
|
|
|
#ifdef __APPLE__
|
|
|
struct timeval tmptv = {(long int)(timeout_usec / 1000000), timeout_usec % 1000000};
|
|
|
#else
|
|
|
- struct timeval tmptv = {(long int)(timeout_usec / 1000000), (long int)(timeout_usec % 1000000)};
|
|
|
+ struct timeval tmptv = {(long int)(timeout_usec / 1000000),
|
|
|
+ (long int)(timeout_usec % 1000000)};
|
|
|
#endif
|
|
|
UA_Int32 retval;
|
|
|
|
|
@@ -152,15 +161,18 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
|
|
|
UA_fd_set(connection->sockfd, &fdset);
|
|
|
retval = select(connection->sockfd+1, &fdset, NULL, NULL, &tmptv);
|
|
|
if(retval && UA_fd_isset(connection->sockfd, &fdset)) {
|
|
|
- ret = recv(connection->sockfd, (char*)response->data, connection->localConf.recvBufferSize, 0);
|
|
|
+ ret = recv(connection->sockfd, (char*)response->data,
|
|
|
+ connection->localConf.recvBufferSize, 0);
|
|
|
} else {
|
|
|
ret = 0;
|
|
|
}
|
|
|
} else {
|
|
|
- ret = recv(connection->sockfd, (char*)response->data, connection->localConf.recvBufferSize, 0);
|
|
|
+ ret = recv(connection->sockfd, (char*)response->data,
|
|
|
+ connection->localConf.recvBufferSize, 0);
|
|
|
}
|
|
|
#else
|
|
|
- ssize_t ret = recv(connection->sockfd, (char*)response->data, connection->localConf.recvBufferSize, 0);
|
|
|
+ ssize_t ret = recv(connection->sockfd, (char*)response->data,
|
|
|
+ connection->localConf.recvBufferSize, 0);
|
|
|
#endif
|
|
|
|
|
|
if(ret == 0) {
|
|
@@ -172,9 +184,11 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
|
|
|
UA_ByteString_deleteMembers(response);
|
|
|
#ifdef _WIN32
|
|
|
const int last_error = WSAGetLastError();
|
|
|
- #define TEST_RETRY (last_error == WSAEINTR || (timeout > 0) ? 0 : (last_error == WSAEWOULDBLOCK))
|
|
|
+ #define TEST_RETRY (last_error == WSAEINTR || (timeout > 0) ? \
|
|
|
+ 0 : (last_error == WSAEWOULDBLOCK))
|
|
|
#else
|
|
|
- #define TEST_RETRY (errno == EINTR || (timeout > 0) ? 0 : (errno == EAGAIN || errno == EWOULDBLOCK))
|
|
|
+ #define TEST_RETRY (errno == EINTR || (timeout > 0) ? \
|
|
|
+ 0 : (errno == EAGAIN || errno == EWOULDBLOCK))
|
|
|
#endif
|
|
|
if (TEST_RETRY)
|
|
|
return UA_STATUSCODE_GOOD; /* retry */
|
|
@@ -210,34 +224,37 @@ static void FreeConnectionCallback(UA_Server *server, void *ptr) {
|
|
|
/***************************/
|
|
|
|
|
|
/**
|
|
|
- * For the multithreaded mode, assume a single thread that periodically "gets work" from the network
|
|
|
- * layer. In addition, several worker threads are asynchronously calling into the callbacks of the
|
|
|
- * UA_Connection that holds a single connection.
|
|
|
+ * For the multithreaded mode, assume a single thread that periodically "gets
|
|
|
+ * work" from the network layer. In addition, several worker threads are
|
|
|
+ * asynchronously calling into the callbacks of the UA_Connection that holds a
|
|
|
+ * single connection.
|
|
|
*
|
|
|
- * Creating a connection: When "GetWork" encounters a new connection, it creates a UA_Connection
|
|
|
- * with the socket information. This is added to the mappings array that links sockets to
|
|
|
- * UA_Connection structs.
|
|
|
+ * Creating a connection: When "GetJobs" encounters a new connection, it creates
|
|
|
+ * a UA_Connection with the socket information. This is added to the mappings
|
|
|
+ * array that links sockets to UA_Connection structs.
|
|
|
*
|
|
|
- * Reading data: In "GetWork", we listen on the sockets in the mappings array. If data arrives (or
|
|
|
- * the connection closes), a WorkItem is created that carries the work and a pointer to the
|
|
|
- * connection.
|
|
|
+ * Reading data: In "GetJobs", we listen on the sockets in the mappings array.
|
|
|
+ * If data arrives (or the connection closes), a WorkItem is created that
|
|
|
+ * carries the work and a pointer to the connection.
|
|
|
*
|
|
|
- * Closing a connection: Closing can happen in two ways. Either it is triggered by the server in an
|
|
|
- * asynchronous callback. Or the connection is close by the client and this is detected in
|
|
|
- * "GetWork". The server needs to do some internal cleanups (close attached securechannels, etc.).
|
|
|
- * So even when a closed connection is detected in "GetWork", we trigger the server to close the
|
|
|
- * connection (with a WorkItem) and continue from the callback.
|
|
|
+ * Closing a connection: Closing can happen in two ways. Either it is triggered
|
|
|
+ * by the server in an asynchronous callback. Or the connection is close by the
|
|
|
+ * client and this is detected in "GetJobs". The server needs to do some
|
|
|
+ * internal cleanups (close attached securechannels, etc.). So even when a
|
|
|
+ * closed connection is detected in "GetJobs", we trigger the server to close
|
|
|
+ * the connection (with a WorkItem) and continue from the callback.
|
|
|
*
|
|
|
- * - Server calls close-callback: We close the socket, set the connection-state to closed and add
|
|
|
- * the connection to a linked list from which it is deleted later. The connection cannot be freed
|
|
|
- * right away since other threads might still be using it.
|
|
|
+ * - Server calls close-callback: We close the socket, set the connection-state
|
|
|
+ * to closed and add the connection to a linked list from which it is deleted
|
|
|
+ * later. The connection cannot be freed right away since other threads might
|
|
|
+ * still be using it.
|
|
|
*
|
|
|
- * - GetWork: We remove the connection from the mappings array. In the non-multithreaded case, the
|
|
|
- * connection is freed. For multithreading, we return a workitem that is delayed, i.e. that is
|
|
|
- * called only after all workitems created before are finished in all threads. This workitems
|
|
|
- * contains a callback that goes through the linked list of connections to be freed.
|
|
|
- *
|
|
|
- */
|
|
|
+ * - GetJobs: We remove the connection from the mappings array. In the
|
|
|
+ * non-multithreaded case, the connection is freed. For multithreading, we
|
|
|
+ * return a workitem that is delayed, i.e. that is called only after all
|
|
|
+ * workitems created before are finished in all threads. This workitems
|
|
|
+ * contains a callback that goes through the linked list of connections to be
|
|
|
+ * freed. */
|
|
|
|
|
|
#define MAXBACKLOG 100
|
|
|
|
|
@@ -300,7 +317,8 @@ ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
|
|
|
#if UA_LOGLEVEL <= 300
|
|
|
//cppcheck-suppress unreadVariable
|
|
|
ServerNetworkLayerTCP *layer = connection->handle;
|
|
|
- UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "Connection %i | Force closing the connection",
|
|
|
+ UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
|
|
|
+ "Connection %i | Force closing the connection",
|
|
|
connection->sockfd);
|
|
|
#endif
|
|
|
/* only "shutdown" here. this triggers the select, where the socket is
|
|
@@ -319,11 +337,13 @@ ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
|
|
|
socklen_t addrlen = sizeof(struct sockaddr_in);
|
|
|
int res = getpeername(newsockfd, (struct sockaddr*)&addr, &addrlen);
|
|
|
if(res == 0) {
|
|
|
- UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "Connection %i | New connection over TCP from %s:%d",
|
|
|
+ UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
|
|
|
+ "Connection %i | New connection over TCP from %s:%d",
|
|
|
newsockfd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
|
|
} else {
|
|
|
- UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Connection %i | New connection over TCP, getpeername failed with errno %i",
|
|
|
- newsockfd, errno);
|
|
|
+ UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK,
|
|
|
+ "Connection %i | New connection over TCP, "
|
|
|
+ "getpeername failed with errno %i", newsockfd, errno);
|
|
|
}
|
|
|
UA_Connection_init(c);
|
|
|
c->sockfd = newsockfd;
|
|
@@ -359,7 +379,8 @@ ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, UA_Logger logger) {
|
|
|
if(gethostname(hostname, 255) == 0) {
|
|
|
char discoveryUrl[256];
|
|
|
#ifndef _MSC_VER
|
|
|
- du.length = (size_t)snprintf(discoveryUrl, 255, "opc.tcp://%s:%d", hostname, layer->port);
|
|
|
+ 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);
|
|
@@ -376,37 +397,44 @@ ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, UA_Logger logger) {
|
|
|
if(newsock < 0)
|
|
|
#endif
|
|
|
{
|
|
|
- UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening the server socket");
|
|
|
+ UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK,
|
|
|
+ "Error opening the server socket");
|
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
}
|
|
|
|
|
|
/* Set socket options */
|
|
|
int optval = 1;
|
|
|
- if(setsockopt(newsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1 ||
|
|
|
+ if(setsockopt(newsock, SOL_SOCKET, SO_REUSEADDR,
|
|
|
+ (const char *)&optval, sizeof(optval)) == -1 ||
|
|
|
socket_set_nonblocking(newsock) != UA_STATUSCODE_GOOD) {
|
|
|
- UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error during setting of server socket options");
|
|
|
+ UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK,
|
|
|
+ "Error during setting of server socket options");
|
|
|
CLOSESOCKET(newsock);
|
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
}
|
|
|
|
|
|
/* Bind socket to address */
|
|
|
- const struct sockaddr_in serv_addr = {.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
|
|
|
- .sin_port = htons(layer->port), .sin_zero = {0}};
|
|
|
+ const struct sockaddr_in serv_addr = {
|
|
|
+ .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
|
|
|
+ .sin_port = htons(layer->port), .sin_zero = {0}};
|
|
|
if(bind(newsock, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
|
|
|
- UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error during binding of the server socket");
|
|
|
+ UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK,
|
|
|
+ "Error during binding of the server socket");
|
|
|
CLOSESOCKET(newsock);
|
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
}
|
|
|
|
|
|
/* Start listening */
|
|
|
if(listen(newsock, MAXBACKLOG) < 0) {
|
|
|
- UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error listening on server socket");
|
|
|
+ UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK,
|
|
|
+ "Error listening on server socket");
|
|
|
CLOSESOCKET(newsock);
|
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
}
|
|
|
|
|
|
layer->serversockfd = (UA_Int32)newsock; /* cast on win32 */
|
|
|
- UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "TCP network layer listening on %.*s",
|
|
|
+ UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
|
|
|
+ "TCP network layer listening on %.*s",
|
|
|
nl->discoveryUrl.length, nl->discoveryUrl.data);
|
|
|
return UA_STATUSCODE_GOOD;
|
|
|
}
|
|
@@ -435,14 +463,16 @@ ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt1
|
|
|
#endif
|
|
|
{
|
|
|
socket_set_nonblocking(newsockfd);
|
|
|
- /* Send messages directly and do wait to merge packets (disable Nagle's algorithm) */
|
|
|
+ /* Send messages directly and do wait to merge packets (disable
|
|
|
+ Nagle's algorithm) */
|
|
|
int i = 1;
|
|
|
setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&i, sizeof(i));
|
|
|
ServerNetworkLayerTCP_add(layer, (UA_Int32)newsockfd);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /* alloc enough space for a cleanup-connection and free-connection job per resulted socket */
|
|
|
+ /* alloc enough space for a cleanup-connection and free-connection job per
|
|
|
+ resulted socket */
|
|
|
if(resultsize == 0)
|
|
|
return 0;
|
|
|
UA_Job *js = malloc(sizeof(UA_Job) * (size_t)resultsize * 2);
|
|
@@ -493,7 +523,8 @@ static size_t
|
|
|
ServerNetworkLayerTCP_stop(UA_ServerNetworkLayer *nl, UA_Job **jobs) {
|
|
|
ServerNetworkLayerTCP *layer = nl->handle;
|
|
|
UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
|
|
|
- "Shutting down the TCP network layer with %d open connection(s)", layer->mappingsSize);
|
|
|
+ "Shutting down the TCP network layer with %d open connection(s)",
|
|
|
+ layer->mappingsSize);
|
|
|
shutdown((SOCKET)layer->serversockfd,2);
|
|
|
CLOSESOCKET(layer->serversockfd);
|
|
|
UA_Job *items = malloc(sizeof(UA_Job) * layer->mappingsSize * 2);
|
|
@@ -581,7 +612,8 @@ ClientNetworkLayerClose(UA_Connection *connection) {
|
|
|
|
|
|
/* we have no networklayer. instead, attach the reusable buffer to the handle */
|
|
|
UA_Connection
|
|
|
-UA_ClientConnectionTCP(UA_ConnectionConfig localConf, const char *endpointUrl, UA_Logger logger) {
|
|
|
+UA_ClientConnectionTCP(UA_ConnectionConfig localConf, const char *endpointUrl,
|
|
|
+ UA_Logger logger) {
|
|
|
#ifdef _WIN32
|
|
|
WORD wVersionRequested;
|
|
|
WSADATA wsaData;
|